how2heap之House_of_Roman
House of Roman
总结一句话就是fastbin attack+unsorted bin attack+brute force
该方法不需要泄露libc地址,partial overwrite写onegadget或者system撞大运(1/4096)
step 1
Fastbin Chunk points to __malloc_hook
这里的fastbin attack利用了堆块的布局,结合off_by_one构造fastbin链,值得关注
1
fastbin_victim 0x71
chunk 0x91
main_arena_use 0x91
relative_offset_heap 0x71
Top chunk
2
free(main_arena_use)
unsortedbin main_arena_use 0x91
3
malloc(0x60)
fastbin_victim 0x71
chunk 0x91
fake_libc_chunk 0x71
unsorted bin 0x21
relative_offset_heap 0x71
Top chunk
4
free(relative_offset_heap)
free(fastbin_victim)
fastbin: fastbin_victim->relative_offset_heap
5
Previous1
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
27Free chunk (fastbins) | PREV_INUSE
Addr: 0x603000
Size: 0x71
fd: 0x603190
Allocated chunk | PREV_INUSE
Addr: 0x603070
Size: 0x91
Allocated chunk | PREV_INUSE
Addr: 0x603100
Size: 0x71
Free chunk (unsortedbin) | PREV_INUSE
Addr: 0x603170
Size: 0x21
fd: 0x7ffff7bcdb78
bk: 0x7ffff7bcdb78
Free chunk (fastbins)
Addr: 0x603190
Size: 0x70
fd: 0x00
Top chunk | PREV_INUSE
Addr: 0x603200
Size: 0x20e01
fastbin_victim的fd指针最后一字节改为\x00
After1
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
27Free chunk (fastbins) | PREV_INUSE
Addr: 0x603000
Size: 0x71
fd: 0x603100
Allocated chunk | PREV_INUSE
Addr: 0x603070
Size: 0x91
Free chunk (fastbins) | PREV_INUSE
Addr: 0x603100
Size: 0x71
fd: 0x7ffff7bcdbf8
Free chunk (unsortedbin) | PREV_INUSE
Addr: 0x603170
Size: 0x21
fd: 0x7ffff7bcdb78
bk: 0x7ffff7bcdb78
Allocated chunk
Addr: 0x603190
Size: 0x70
Top chunk | PREV_INUSE
Addr: 0x603200
Size: 0x20e01
虽然fake_libc_chunk此时处于used状态,但是其是从unsorted bin切割得到的,原fd指针处仍残留有指向main_arena附近的地址(为爆破出__malloc_hook-0x23地址做准备)
fastbin: fastbin_victim->fake_libc_chunk->main_arena+2161
2fastbins
0x70: 0x603000 —▸ 0x603100 —▸ 0x7ffff7bcdbf8 (main_arena+216) ◂— 0x7ffff7bcdbf8
6
此时位于0x603100处的fake_libc_chunk是used状态且被放入fastbin的
修改fake_libc_chunk的fd指针后两字节为&__malloc_hook-0x23后两字节
fastbin: fastbin_victim -> fake_libc_chunk -> (__malloc_hook - 0x23) size:0x70
(开了地址随机化时该步骤成功率为1/16)
7
malloc(0x60)
malloc(0x60)
malloc_hook_chunk = malloc(0x60)
step 2
Unsorted_bin attack
1
unsorted bin ptr = malloc(0x80)
malloc(0x30) [barrier]
2
free(unsorted bin ptr) ->unsorted bin
3
Previous1
2
3
4
5
6
7
8
9Free chunk (unsortedbin) | PREV_INUSE
Addr: 0x603200
Size: 0x91
fd: 0x7ffff7bcdb78
bk: 0x7ffff7bcdb78
Allocated chunk
Addr: 0x603290
Size: 0x40
修改unsorted bin的bk指针最后两字节为__malloc_hook最后两字节
After1
2
3
4
5
6
7
8
9Free chunk (unsortedbin) | PREV_INUSE
Addr: 0x603200
Size: 0x91
fd: 0x7ffff7bcdb78
bk: 0x7ffff7bcdb00
Allocated chunk
Addr: 0x603290
Size: 0x40
这一步存在爆破,正确与否与之前fastbin attack中相同,成功率不变
4
trigger the unsortedbin attack
malloc(0x80)
则会向地址0x7ffff7bcdb00+0x10处写入0x7ffff7bcdb78,即向__malloc_hook写入main_arena+88
step 3
set __malloc_hook to system/one_gadget
此时__malloc_hook已经写入了main_arena+88
接下来利用step 1中fastbin attack申请到的chunk对__malloc_hook进行partial overwrite,共写入三个字节,其中低12bits是确定的,而高12bits需要爆破,成功率为1/4096=0.02%
同时如果这里能爆破成功,则上一步必然也成功,所以这一步的成功率为整个攻击的成功率
举例来说
当前__malloc_hook写入的是0x00007ffff7bcdb78(但我们实际上不知道)
自行假设libc基址后三字节为0x809000
计算得one_gadget后三字节为0x84e226
并且好像__malloc_hook的倒数第三个数字与libc基址倒数第三个数字固定相差0x4,所以也就可以算出fastbin attack中需要爆破的数字应该为0xd
总结
- fastbin attack(堆排布+off by one+brute force)申请到
__malloc_hook-0x23处的堆块 - unsorted bin attack将main_arena+88写入__malloc_hook
- 编辑堆块,partial overwrite写入onegadget或system地址
(7.13更新)
例题
护网杯2018 2018_task_calendar
题目分析
无输出
开了PIE
add
1 | _QWORD *add() |
只能存放4个chunk指针
申请的chunk大小限制在0~104 (0x68)
指针和size存在bss段上
edit
1 | int sub_E0E() |
1 | __int64 __fastcall sub_B5F(__int64 a1, signed int a2) |
注意到edit中for语句for ( i = 0; i <= a2; ++i ),存在off by one。同时最少读入两字节。
另外可以对处于free状态的chunk编辑
delete
1 | void sub_ED5() |
只free了指针
没有置0
存在uaf
思路
利用house of roman
先申请几个堆,然后利用off by one修改下一个chunk的size位(该chunk大小和下一个chunk大小相加再加0x10),再free掉被修改size的chunk,从而构造出unsorted bin
申请相应大小的chunk,让unsorted bin中的另一个指针刚好指向切割后剩下的unsorted bin的fd
然后free掉两个fastbin,根据堆之间的偏移修改其中一个fastbin的fd(改一个字节),使其指向刚才剩下的unsorted bin。然后再利用之前说的有一个指向剩下的unsorted bin的指针修改其fd指向
__malloc_hook-0x23,再申请三次即可完成fastbin attack(注意该fastbin链对应的chunk size为0x70)接下来进行unsorted bin attack。注意之前剩下的unsorted bin属于能申请的范围,且有指针指向。直接覆盖其fd,并将bk指向
__malloc_hook-0x10,然后申请相应大小的chunk,即完成unsorted bin attack最后利用fastbin attack申请到的chunk修改
__malloc_hook处地址三个字节为one_gadget,再malloc即可。
调试方法
先把本地ASLR关了
root下执行echo 0 > /proc/sys/kernel/randomize_va_space
exp
1 | from pwn import* |
后记
本来想调原作者给的demo,结果可能是版本原因,调完发现onegadget都打不通
不过还是从作者的思路学到了这种fastbin attack+unsorted bin attack的组合技,可以先利用unsorted bin attack写一个地址,再利用这个地址第一个字节是0x7f来作为fake fastbin的size位,这样一来计算好偏移即可完成fastbin attack,且理论上可以完成任意地址的fastbin attack
另外实际成功率确实很低
调了很久终于运气好出了(不过还是本地的)
留图纪念




