由于沙箱规则比较多,规则制定比较自由,所以下文重点探讨绕过的技术。
使用_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/write。这类的系统调用需要平时多关注、收集和整理。
随便找一个seccomp-tools解析的沙箱规则:
$ seccomp-tools dump ./pwn |
这个沙箱规则判断了当前触发系统调用的时候,arch是否为x64,如果不是64就会kill;然后,判断了sys-number是否大于等于0x40000000,如果大于,程序也会被kill;然后设置了黑名单,分别是:execve/execveat/fork/clone/rt_sigreturn。处于黑名单的系统调用会被kill掉,其他系统调用则会放行。
切换指令模式
如果没有0001: 0x15 0x00 0x08 0xc000003e if (A != ARCH_X86_64) goto 0010这一句的检查,那么可以使用retf(return far)指令实现架构切换,或者在x64环境下直接调用int 0x80陷入到内核态。
retf相当于pop ip; pop cs,cs是段寄存器,寄存器为0x23时表示32位运行模式,0x33表示64位运行模式。
从64位切换到32位的模板如下:
xor esp, esp |
使用**0x40000000+X**系统调用
如果没有限制:0003: 0x35 0x06 0x00 0x40000000 if (A >= 0x40000000) goto 0010的话,那么可以使用0x40000000 + X来执行系统调用。
关于x32 ABI可查看x32 ABI - Wikipedia。
比如要执行read:
xor eax, eax |
需要注意的是,从5.16开始,linux内核不支持x32 abi了:Bug #1994516 “Kernels after 5.16 cannot execute x32-ABI binaries…” : Bugs : linux package : Ubuntu (launchpad.net)