阴间堆风水
逆向
修复switch
0: 0x3985 invalid
1: 0x3797 add
2: 0x37B3 show
3: 0x37cf edit
4: 0x37eb delet
5: 0x3807 change role
struct
通过add函数,猜测出heap_list,heap_size的作用,结合free、edit函数找到两个标志位
结合每个的大小与偏移,推测出数组的数量
1 | struct house |
1 | struct tmp_house |
md5
- 填充1个1和n个0,使信息长度为N*512+448(bit)
- 用64bit存储填充前信息长度,加在后面,长度变为(N+1)*512
- 装入标准的幻数: A=0x67452301, B=0xefcdab89, C=0x98badcfe, D=0x10325476
- 四轮循环运算,循环次数为分组个数(N+1)
1 | import hashlib |
利用
- add大小0x90~0x430,同一角色size只能增加
- peppa 20次,mummy 10次,daddy 5次
- peppa 0x30i, mummy 0x30i + 0x10, daddy 0x31i + 0x20
- view 2次,edit 8次
- delet后无法delet,切换角色可edit、view
- daddy的add不用一直增加!
- daddy add最后一次时会多calloc0xe8
堆风水
role的选择
注意不同role的堆列表是独立的,同时不同role能修改的位置也不同
peppa可以修改fd,bk
mummy可以修改fd_nextsize,bk_nextsize
因而最好peppa打tcache stashing unlink, mummy打largebin attack
当然这不是绝对的,我们可以通过UAF达到对同一个堆块的混淆
tcache stashing unlink
1.tcache
中放5
个,smallbin
中放两个
2.将后进smallbin
的chunk
的bk
(不破坏fd
指针的情况下)修改为[target-0x10]
(即target为将要加入tchache的chunk的user pointer处),同时将目标地址+0x08
处(即target->bk)的值设置为一个指向可写内存的指针。
3.从smallbin中取一个chunk,走完stash流程,目标地址就会被链入tcache中。
布局的问题
1
在tcache中放了5个的情况下,如何使两个chunk进入相同大小的smallbin?
问题转化为:如何使两个chunk进入相同大小的unsortedbin,而不进入tcache
考虑当unsortedbin中只有一个chunk时,分配较小的chunk时会从其中切一块使用,另一块放入lastrmainder(同样是unsortedbin)
所以我们先获取一个较大的unsortedbin,(这一步通过填满tcache获得),随后malloc一块较小的chunk,就可以获得目标大小的unsortedbin
注意这里最后需要获得两块unsortedbin,注意避免在分配第二块时把第一块拿掉。我一开始分配的大小为0x150,刚好可以拿掉一个0xa0剩下一个0xa0,但是在分配第二快时就会出现问题
我的解决方案是,切割0x160的块,从中取出0xb0,刚好剩下0xa0,同时第二次取0xb0时不会出现把获得的unsortedbin取走的情况
网上的解决方案是:再填另一个tcache,两次用不同的unsortedbin切割,但是这种方法比较浪费次数
同时,经过计算、微调,我这里切下来的smallbin的fd和bk刚好位于chunk1->7,1->8的可写区域
2
改到_IO_list_all的指针后,如何修改内容?
本题比较阴间的地方是,不能完整地修改一个堆块
好在出题人给add3加了一个gift,可以申请一个0xe8的完整可写的堆块
所以最后可以把largebin attack指向的largebin留着,完成add3的最后一步,使得daddy从这个largechunk中切一块,从而直接获得完整的修改权限
下策是修改large chunk的chain指针,使其指向可写堆块
布局
1 | #!/usr/bin/env python2 |
伪造IOFILE
改__free_hook做法
1 | int _IO_str_overflow (FILE *fp, int c) |
1 | old_blen = _IO_blen (fp) = (fp)->_IO_buf_end - (fp)->_IO_buf_base |
此时_IO_list_all
指针已经指向了gift chunk,这个chunk的内容完全是可控的
注意前面tcache stashing unlink改的位置,可能需要在__free_hook的地址处加减0x8,因为tcache申请会检查十六字节对齐
因为我没用原题的glibc,这里我对齐之后,0xe8大小的堆块不够写了,按照出题人的思路应该是刚好够写的
1 | fake_IO_addr = heap_base+0x13da0 |
改memset got做法
由于libc是partial RELRO,got表可写
因此可以把memset的got当作一个__free_hook
注意这里做tcache stashing unlink时不能直接覆盖memset的got表,这是因为calloc中会调用memset,如果这时的got已经进入tcache,则会变成加密后的fd,rip运行到这里时会报错
因而正确的做法应该是预留一定的空间,本题限制较大,故不做演示,仅提出思路