初探沙箱———转载

z转载自Tiegu’s Blog

沙箱机制初探

前言

之前做题遇到过几次关于沙箱的题目,自己都是靠猜或者是去网上找一些零碎的知识去做的,现在刷buu发现一道关于沙箱机制的题目,加之最近觉得没写博客感觉很多知识点忘得很快,所以打算学习一下沙箱机制,顺便写一篇博客去记录一下。

what’s the 沙箱安全机制

在计算机安全领域,沙箱(Sandbox)是一种程序的隔离运行机制,其目的是限制不可信进程或不可信代码运行时的访问权限。沙箱技术经常被用于执行未经测试的或不可信的客户程序。为了阻止不可信程序可能破坏系统程序或破坏其它用户程序的运行,沙箱技术通过为不可信客户程序提供虚拟化的内存、文件系统、网络等资源,而这种虚拟化手段对客户程序来说是透明的。由于沙箱里的资源被虚拟化(或被间接化),所以沙箱里的不可信程序的恶意行为可以被限制在沙箱中,或者在沙箱里只允许执行在白名单里规定的有限的API操作。

看概念感觉沙箱机制是一种安全隔离技术,但是个人感觉目前做pwn题遇到的沙箱机制用到的是对于一些system call的调用的ban,所以以下介绍的不是对这个沙箱机制的深入了解,而是介绍两种常见的沙箱 seccomp 安全机制和 prctl 。

seccomp的探索

What is seccomp

seccomp (short for secure computing mode) is a computer security facility in the Linux kernel. It was merged into the Linux kernel mainline in kernel version 2.6.12, which was released on March 8, 2005. seccomp allows a process to make a one-way transition into a “secure” state where it cannot make any system calls except exit(), sigreturn(), read() and write() to already-open file descriptors. Should it attempt any other system calls, the kernel will terminate the process with SIGKILL or SIGSYS. In this sense, it does not virtualize the system’s resources but isolates the process from them entirely.

How to use

这里主要介绍几个函数以及利用。

img

ctxFilter context/handle,其中typedef void *scmp_filter_ctx;
seccomp_init是初始化的过滤状态,这里用的是SCMP_ACT_ALLOW,表示默认允许所有的syscacll.如果初始化状态为SCMP_ACT_KILL,则表示默认不允许所有的syscall (详见下图)

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
/*
* seccomp actions
*/

/**
* Kill the process
*/
#define SCMP_ACT_KILL 0x00000000U
/**
* Throw a SIGSYS signal
*/
#define SCMP_ACT_TRAP 0x00030000U
/**
* Return the specified error code
*/
#define SCMP_ACT_ERRNO(x) (0x00050000U | ((x) & 0x0000ffffU))
/**
* Notify a tracing process with the specified value
*/
#define SCMP_ACT_TRACE(x) (0x7ff00000U | ((x) & 0x0000ffffU))
/**
* Allow the syscall to be executed after the action has been logged
*/
#define SCMP_ACT_LOG 0x7ffc0000U
/**
* Allow the syscall to be executed
*/
#define SCMP_ACT_ALLOW 0x7fff0000U

seccomp_rule_add是添加一条规则,函数原形如下

1
int seccomp_rule_add(scmp_filter_ctx ctx, uint32_t action, int syscall, unsigned int arg_cnt, ...);

seccomp_load是应用过滤,如果不调用seccomp_load则上面所有的过滤都不会生效

1
int seccomp_load(const scmp_filter_ctx ctx);

有一点需要再说一下,我们用的是seccomp_rule_add(ctx, SCMP_ACT_KILL, SCMP_SYS(execve), 0);,arg_cnt为0,表示我们直接限制execve,不管他什么参数.

如果arg_cnt不为0,那arg_cnt表示后面限制的参数的个数,也就是只有调用execve,且参数满足要求时,才会拦截syscall.(参数详情参见下图)

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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
/**
* Specify an argument comparison struct for use in declaring rules
* @param arg the argument number, starting at 0
* @param op the comparison operator, e.g. SCMP_CMP_*
* @param datum_a dependent on comparison
* @param datum_b dependent on comparison, optional
*/
#define SCMP_CMP(...) ((struct scmp_arg_cmp){__VA_ARGS__})

/**
* Specify an argument comparison struct for argument 0
*/
#define SCMP_A0(...) SCMP_CMP(0, __VA_ARGS__)

/**
* Specify an argument comparison struct for argument 1
*/
#define SCMP_A1(...) SCMP_CMP(1, __VA_ARGS__)

/**
* Specify an argument comparison struct for argument 2
*/
#define SCMP_A2(...) SCMP_CMP(2, __VA_ARGS__)

/**
* Specify an argument comparison struct for argument 3
*/
#define SCMP_A3(...) SCMP_CMP(3, __VA_ARGS__)

/**
* Specify an argument comparison struct for argument 4
*/
#define SCMP_A4(...) SCMP_CMP(4, __VA_ARGS__)

/**
* Specify an argument comparison struct for argument 5
*/
#define SCMP_A5(...) SCMP_CMP(5, __VA_ARGS__)



/**
* Comparison operators
*/
enum scmp_compare {
_SCMP_CMP_MIN = 0,
SCMP_CMP_NE = 1, /**< not equal */
SCMP_CMP_LT = 2, /**< less than */
SCMP_CMP_LE = 3, /**< less than or equal */
SCMP_CMP_EQ = 4, /**< equal */
SCMP_CMP_GE = 5, /**< greater than or equal */
SCMP_CMP_GT = 6, /**< greater than */
SCMP_CMP_MASKED_EQ = 7, /**< masked equality */
_SCMP_CMP_MAX,
};

/**
* Argument datum
*/
typedef uint64_t scmp_datum_t;

/**
* Argument / Value comparison definition
*/
struct scmp_arg_cmp {
unsigned int arg; /**< argument number, starting at 0 */
enum scmp_compare op; /**< the comparison op, e.g. SCMP_CMP_* */
scmp_datum_t datum_a;
scmp_datum_t datum_b;
};

举个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <unistd.h>
#include <seccomp.h>
#include <linux/seccomp.h>

int main(void){
scmp_filter_ctx ctx;
ctx = seccomp_init(SCMP_ACT_ALLOW);
seccomp_rule_add(ctx, SCMP_ACT_KILL, SCMP_SYS(write),1,SCMP_A2(SCMP_CMP_EQ,0x10));//第2(从0)个参数等于0x10
seccomp_load(ctx);
write(1,"i will give you a shell\n",24);//不被拦截
write(1,"1234567812345678",0x10);//被拦截
return 0;
}

prctl 函数

查看函数原型:

1
2
#include <sys/prctl.h>
int prctl(int option, unsigned long arg2, unsigned long arg3,unsigned long arg4,unsigned long arg5);

第一个参数是指定相应的操作,在手册上有特别多的选项,这里打算介绍两个。

PR_SET_NO_NEW_PRIVS(用38表示)

简单的说就是如果 option 设置为 PR_SET_NO_NEW_PRIVS 的话,第二个参数如果设置为 1 的话,不能够进行 execve 的系统调用,同时这个选项还会继承给子进程

这样的话常规的调用 system 函数、one_gadget 的用不了了,这里的设置点其实和 pwnable.tw 上 orw 那道题一样,只能进行几个系统调用:open、write、read

img

从上图可以看出,当prctl的第一个参数设置为38时,第二个参数设置为1时,变会触发上述效果。

PR_SET_SECCOMP(用22表示)

第二个参数,可以参见man手册里面的介绍

img

设置 seccomp ,其实也就是设置沙箱规则,这个 option 有两个子参数:

  • 这里如果设置了 SECCOMP_MODE_STRICT (用1表示)模式的话,系统调用只能使用 read, write,_exit 这三个。

  • 如果设置了 SECCOMP_MODE_FILTER (用2表示)的话,系统调用规则就可以被 Berkeley Packet Filter(BPF) 的规则所定义,这玩意就是这里最最重点的东西了。

    首先介绍一下这个BPF是啥吧,度娘上面的解释是:

    img

看解释感觉是网络数据包传输过滤的一种规则,但事实上,后面已经被引用为沙箱规则

BPF 定义了一个伪机器。这个伪机器可以执行代码,有一个累加器,寄存器,和赋值、算术、跳转指令。一条指令由一个定义好的结构 struct bpf_insn 表示,与真正的机器代码很相似,若干个这样的结构组成的数组,就成为 BPF 的指令序列。

总结一些点:

  1. 结构赋值操作指令为:BPF_STMT、BPF_JUMP ,两个宏展开都是已经赋值的了struct bpf_insn结构。

  2. BPF 的主要指令有 BPF_LD,BPF_ALU,BPF_JMP,BPF_RET 等。BPF_LD 将数据装入累加器,BPF_ALU 对累加器执行算术命令,BPF_JMP 是跳转指令,BPF_RET 是程序返回指令

  3. BPF 条件判断跳转指令:BPF_JMP、BPF_JEQ,BPF_JA,BPF_JGT等,语法跟汇编语言几乎相等,根据后面的几个参数进行判断,然后跳转到相应的地方。

  4. 返回指令:BPF_RET、BPF_K,返回后面参数的值

  5. 一些杂用指令:BPF_H表示按字传输,BPF_W表示按双字传输,BPF_B表示按单个字节传输;BPF_ABS表示绝对偏移,BPF_IND表示相对偏移, SECCOMP_RET_ALLOW 表示允许, SECCOMP_RET_ERRNO 表示禁止。

    这个其实背后也牵涉到很多内容,参见以下两篇文章的介绍。

    http://www.360doc.com/content/06/1026/17/13362_241408.shtml

http://www.secwk.com/2019/09/20/6564/

seccomp-tools 工具

以上设置在pwn题中遇到时一般都是禁止了一些系统调用。故可以seccomp-tools这个工具去查看禁用的系统调用。

  • 安装:

    1
    2
    $ sudo apt install gcc ruby-dev
    $ gem install seccomp-tools
  • 使用:一般用到dump这个用法,其他详细用法可见上面github。

    1
    seccomp-tools dump ./pwn

参考文章

http://www.secwk.com/2019/09/20/6564/

https://veritas501.space/2018/05/05/seccomp%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/

查看评论