堆溢出之DWORD Shoot

堆溢出之DWORD Shoot

堆块结构

堆块由块首和块身构成,块首占8字节,由块大小和块计算单位和是否占用等信息,块身紧跟在块首,在提到一个块大小的时候,要加上块首大小.如请求分配32字节,实际会分配40字节.堆块的结构如下:

+0x000 Size : Uint2B // 堆块的大小(以堆粒度为单位, 含块首) 
+0x002 PreviousSize : Uint2B // 前一堆块的大小
+0x000 SubSegmentCode : Ptr32 Void +0x004 SmallTagIndex : UChar 
+0x005 Flags : UChar // 表示堆块的状态 
    Flags: 
    0x01 堆块正在被程序或者堆管理器使用 
    0x04 堆块使用了填充模式(File Pattern) 
    0x08 堆块是直接从虚拟内存管理器中分配而来的 
    0x10 堆块是未提交范围之前的最后一个堆块
+0x006 UnusedBytes : UChar // 堆块中未被用户使用的字节数(含块首) +0x007 SegmentIndex : UChar // 代表的堆块状态

Flink这四个字节存储的是相邻的下一个堆块的地址,Blink存储的是上一个相邻的堆块的地址,每个指针占四字节,在空闲态时两个指针存放在块身,占用态时块身将全部用来存放数据。Data就是数据段了。

DWORD Shoot原理

DWORD SHOOT是发生在一种发生在双向链表删除节点的时会发生的情况。他有可能导致任意地址被改写。

正常的unlink:

在ulink执行中正确的流程如下:

就是说在释放堆块的同时会发生如下操作:

 FD = P->fd;                                   
BK = P->bk;    
FD->bk = BK;                                  
BK->fd = FD;

BK是指前一个堆块,FD是指后一个堆块

DWORD Shoot原理如下:

在对堆内存溢出后DWORDSHOOT可以修改任意地址内存,在发生攻击时的程序流程如下所示,通过堆溢出可在对一个节点数据修改(或者其他方式)改变内存分配上下面一个节点的fd和bk数据。简单的来说就是我们通过堆溢出覆盖掉堆块的fd或者bk中的地址,使其跳转到我们想要跳转的地方。

这样就成功的改写了进程中free函数,使得调用free函数时实际上是执行了shellcode。当然也可以修改其他在unlink之后会调用的库函数。

文章目录
  1. 1. 堆溢出之DWORD Shoot
    1. 1.1. 堆块结构
    2. 1.2. DWORD Shoot原理
|