0


5.4 堆溢出利用(上)——DWORD SHOOT

一、预备知识

    堆管理系统的三类操作:堆块分配、堆块释放和堆快合并归根结底都是对链表的修改。堆溢出利用的精髓就是用精心构造的数据溢出下一个堆块的块首,改写块首中的前向指针(flink)和后向指针(blink),然后在分配、释放、合并等操作发生时伺机获得一次向内存任意地址写入任意数据的机会。这种能够向内存任意地址写入任意数据的机会称之为“DWORD SHOOT”。

    通过DWORD SHOOT,攻击者可以劫持进程,运行shellcode,主要有如下情形:

点射目标(target)子弹(payload)改写后的结果栈帧中的函数返回地址shellcode的起始地址函数返回时,跳去执行shellcode栈帧中S.E.H句柄shellcode的起始地址异常发生时,跳去执行shellcode重要函数调用地址shellcode的起始地址函数调用时,跳去执行shellcode
举一个例子说明DWORD SHOOT究竟时如何发生的。将一个结点从双向链表中“卸下”的函数很可能是这样的:(参考数据结构)

int remove (ListNode * node) 
{ 
    node -> blink -> flink = node -> flink; 
    node -> flink -> blink = node -> blink; 
    return 0; 
}
    当堆溢出发生时,非法数据可以淹没下一个堆块的块首。这时,块首是可以被攻击者控制的,即块首中存放的前向指针(flink)和后向指针(blink)是可以被攻击者伪造的。当这个堆块被从双向链表中“卸下”时,node -> blink -> flink = node -> flink 将把伪造的 flink 指针值写入伪造的 blink 所指的地址中去,从而发生 DWORD SHOOT。过程如下:

     注:图5.3.1为正常“拆卸”,图5.3.2为异常拆卸!!!

    ** !!!另外,请特别注意实际内存中的前向指针和后向指针示意图:(与数据结构中有一点点不一样,图中释放顺序为h1、h3、h4)**

二、实验环境

    操作系统:Windows 2000 professional

    软件版本:原版OD(实时调试状态)、VC++6.0(release)

三、实验代码

#include <windows.h>

main()
{
    HLOCAL h1, h2,h3,h4,h5,h6; 
    HANDLE hp; 
    hp = HeapCreate(0,0x1000,0x10000); 
    h1 = HeapAlloc(hp,HEAP_ZERO_MEMORY,8); 
    h2 = HeapAlloc(hp,HEAP_ZERO_MEMORY,8); 
    h3 = HeapAlloc(hp,HEAP_ZERO_MEMORY,8); 
    h4 = HeapAlloc(hp,HEAP_ZERO_MEMORY,8); 
    h5 = HeapAlloc(hp,HEAP_ZERO_MEMORY,8); 
    h6 = HeapAlloc(hp,HEAP_ZERO_MEMORY,8);
    

    _asm int 3//used to break the process 
    //free the odd blocks to prevent coalesing 
    
    HeapFree(hp,0,h1); 
    HeapFree(hp,0,h3); 
    HeapFree(hp,0,h5); //now freelist[2] got 3 entries 
    //will allocate from freelist[2] which means unlink the last entry h5
    
    h1 = HeapAlloc(hp,HEAP_ZERO_MEMORY,8); 

    return 0;
}
     注意:

    (1)程序首先创建了一个大小为 0x1000 的堆区,并从其中连续申请了 6 个大小为 8 字节 

的堆块(加上块首实际上是 16 字节),是从初始的尾块中“切”下来的。

    (2)释放奇数次申请的堆块是为了防止堆块合并的发生。 

    (3)三次释放结束后,freelist[2]所标识的空表中应该链入了 3 个空闲堆块,它们依次是 h1、 h3、h5。 (链入尾部)

    (4)再次申请 8 字节的堆块,应该从 freelist[2]所标识的空表中分配,这意味着最后一个堆 

块 h5 被从空表中“拆下”。

    (5)如果我们手动修改 h5 块首中的指针,应该能够观察到 DWORD SHOOT 的发生。

四、实验步骤

     1、编译程序,直接进入OD界面,停在断点处:

     2、F8释放三次内存,手动更改H5的前向指针为0x44444444,后向指针为0x00000000.

     3、执行内存申请的指令,会发现编译器运行错误。

     根据:
node->blink->flink=node->flink
     无法将0x44444444写入0x00000000。
标签: 安全

本文转载自: https://blog.csdn.net/qq_55202378/article/details/127156557
版权归原作者 sliver呀 所有, 如有侵权,请联系我们删除。

“5.4 堆溢出利用(上)——DWORD SHOOT”的评论:

还没有评论