seccomp沙盒逃逸基础——沙盒的规则编写

引入:

安全计算模式 seccomp(Secure Computing Mode)是自 Linux 2.6.10 之后引入到 kernel 的特性。一切都在内核中完成,不需要额外的上下文切换,所以不会造成性能问题。目前 在 DockerChrome广泛使用使用 seccomp可以定义系统调用白名单黑名单,可以 定义出现非法系统调用时候的动作,比如结束进程或者使进程调用失败。

seccomp机制用于限制应用程序可以使用的系统调用增加系统的安全性

在/proc/${pid}/status文件中的Seccomp字段可以看到进程的Seccomp。

简介:

seccomp 是 Linux 内核提供的一种应用程序沙箱机制,seccomp 通过只允许应用程序调用 exit(), sigreturn(), read() 和 write() 四种系统调用来达到沙箱的效果。如果应用程序调用了除了这四种之外的系统调用kernel 会向进程发送 SIGKILL 信号。

prctl 函数

prctl就是在c程序中可以使用BPF过滤规则操作进程的一个函数调用。函数原型如下:

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

option有很多,CTF中一般只关注两种option:PR_SET_NO_NEW_PRIVS(38)和PR_SET_SECCOMP(22):

1.若option为PR_SET_NO_NEW_PRIVS(38):

第二个参数arg2设置为1,那么程序线程将不能通过执行execve系统调用来获得提权,该选项只对execve这个系统调用有效。意思就是若你使用syscall(59,'/bin/sh',null,null)或system("/bin/sh")(内部还是系统调用execve)获得的线程shell,用户组依然是之前的用户组,且不能获得更高权限

也就是说:

prctl(38, 1LL, 0LL, 0LL, 0LL)表示禁用系统调用,也就是systemonegadget都没了,还会教子进程也这么干,很坏;

2.若option为PR_SET_SECCOMP(22):

option为22时,表示可以设置沙箱规则,也就是可以自定义函数的系统调用是被允许还是禁止。

如果arg2为SECCOMP_MODE_STRICT(1),则只允许调用read,write,_exit(not exit_group),sigreturn这几个syscall。

在ida中可以看到prctl(22, 1LL);

如果arg2为SECCOMP_MODE_FILTER(2),则为过滤模式,其中对syscall的限制通过参数3的结构体,来自定义过滤规则,此时函数原型如下。

prctl(PR_SET_SECCOMP,SECCOMP_MODE_FILTER,&prog);

&prog形式如下:

struct sock_fprog {
unsigned short len; /* 指令个数 */
struct sock_filter *filter; /*指向包含struct sock_filter的结构体数组指针*/
};

filter是一个结构体数组,里面的元素就是各种规则(可以认为是指令),下面就是一个过滤execve系统调用的过滤规则,与BPF (Berkeley Packets Filter)相关,暂时不深究:

struct sock_filter filter[] = {
BPF_STMT(BPF_LD+BPF_W+BPF_ABS,0), //将帧的偏移0处,取4个字节数据,也就是系统调用号的值载入累加器
BPF_JUMP(BPF_JMP+BPF_JEQ,59,0,1), //当A == 59时,顺序执行下一条规则(返回KILL),否则跳过下一条规则(也就是返回ALLOW),这里的59就是x64的execve系统调用号
BPF_STMT(BPF_RET+BPF_K,SECCOMP_RET_KILL), //返回KILL
BPF_STMT(BPF_RET+BPF_K,SECCOMP_RET_ALLOW), //返回ALLOW
};

使用ptrcl禁用execve系统调用的实例:

#include <stdio.h>
#include <sys/prctl.h>
#include <linux/seccomp.h>
#include <linux/filter.h>
#include <stdlib.h>
int main()
{
struct sock_filter filter[] = {
BPF_STMT(BPF_LD+BPF_W+BPF_ABS,0),
BPF_JUMP(BPF_JMP+BPF_JEQ,59,0,1),
BPF_STMT(BPF_RET+BPF_K,SECCOMP_RET_KILL),
BPF_STMT(BPF_RET+BPF_K,SECCOMP_RET_ALLOW),
};
struct sock_fprog prog = {
len = (unsigned short)(sizeof(filter)/sizeof(filter[0])),//规则条数
filter = filter, //结构体数组指针
};
prctl(PR_SET_NO_NEW_PRIVS,1,0,0,0); //必要的,设置NO_NEW_PRIVS
prctl(PR_SET_SECCOMP,SECCOMP_MODE_FILTER,&prog);
write(0,"test\n",5);
system("/bin/sh");
return 0;
}

基于BPF(伯克利分组过滤器)的seccomp库函数

基于prctl系统调用的机制不够灵活,这个库可以提供一些函数实现prctl类似的效果,库中封装了一些函数,可以不用了解BPF规则而实现过滤。

但是在c程序中使用它,需要装一些库文件

sudo apt install libseccomp-dev libseccomp2 seccomp

scmp_filter_ctx是过滤器的结构体类型

seccomp_init对结构体进行初始化,若参数为SCMP_ACT_ALLOW,则没有匹配到规则的系统调用将被默认允许,过滤为黑名单模式;若为SCMP_ACT_KILL,则为白名单模式,即没有匹配到规则的系统调用都会杀死进程,默认不允许所有的syscall。

seccomp_rule_add是添加一条规则,其函数原型如下:

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

arg_cnt表明是否需要对对应系统调用的参数做出限制以及指示做出限制的个数,如果仅仅需要允许或者禁止所有某个系统调用,arg_cnt直接传入0即可

下面举两个例子:

seccomp_rule_add(ctx, SCMP_ACT_KILL, SCMP_SYS(execve), 0);即禁用execve,不管其参数如何。

seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(dup2), 2, SCMP_A0(SCMP_CMP_EQ, 1), SCMP_A1(SCMP_CMP_EQ, 2));即当调用dup2函数时,只有前两个参数为1和2时,才允许调用。因此,dup2(1, 2);被允许,dup2(2, 42);被阻止。

使用该库的函数实现禁用execve系统调用的实例

//gcc seccomptest.c -o seccomptest -lseccomp
#include <unistd.h>
#include <seccomp.h>
#include <linux/seccomp.h> int main(void){
scmp_filter_ctx ctx;// Init the filter
ctx = seccomp_init(SCMP_ACT_ALLOW);
seccomp_rule_add(ctx, SCMP_ACT_KILL, SCMP_SYS(execve), 0);
seccomp_load(ctx); char * str = "/bin/sh";
write(1,"i will give you a shell\n",24);
syscall(59,str,NULL,NULL);//execve
return 0;
}

另一个实例:

#include <stdio.h>   /* printf */
#include <unistd.h> /* dup2: just for test */
#include <seccomp.h> /* libseccomp */ int main() {
printf("step 1: unrestricted\n"); // Init the filter
scmp_filter_ctx ctx;
ctx = seccomp_init(SCMP_ACT_KILL); // default action: kill 未在白名单的系统调用都被杀死 // setup basic whitelist 设置白名单,以下系统调用被允许
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(rt_sigreturn), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(exit), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(read), 0);
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(write), 0); // setup our rule 设置特定参数的系统调用白名单,dup2(1,2)被允许
seccomp_rule_add(ctx, SCMP_ACT_ALLOW, SCMP_SYS(dup2), 2,
SCMP_A0(SCMP_CMP_EQ, 1),
SCMP_A1(SCMP_CMP_EQ, 2)); // build and load the filter
seccomp_load(ctx);
printf("step 2: only 'rerw' and dup2(1, 2) syscalls\n"); // Redirect stderr to stdout
dup2(1, 2);
printf("step 3: stderr redirected to stdout\n"); // Duplicate stderr to arbitrary fd
dup2(2, 42);
printf("step 4: !! YOU SHOULD NOT SEE ME !!\n"); // Success (well, not so in this case...)
return 0;
}

再来一个例子:

#include<stdio.h>
#include<unistd.h>
#include<sys/syscall.h>
#include<sys/prctl.h>
#include<linux/seccomp.h>
#include<seccomp.h> int main()
{
char *argv[]={"/bin/cat", "flag", NULL};
char *env[]={NULL};
char cmd[20] = "/bin/cat"; scmp_filter_ctx ctx;// Init the filter
ctx = seccomp_init(SCMP_ACT_ALLOW); // default action: Allow
seccomp_rule_add(ctx, SCMP_ACT_KILL, SCMP_SYS(write), 0);//在禁止write时,SCMP_ACT_KILL也默认不允许所有的syscall
seccomp_load(ctx); syscall(0x3b, cmd, argv, env);
return 0;
}

结果:

➜  seccomp-escape ./syscall
[1] 2730 invalid system call (core dumped) ./syscall

子进程seccomp

另外,seccomp的沙箱同样适用于子进程,即通过fork也不能逃出sandbox。

#include<stdio.h>
#include<unistd.h>
#include<sys/syscall.h>
#include<sys/prctl.h>
#include<linux/seccomp.h>
#include<seccomp.h>
#include<sys/types.h>
#include<sys/wait.h> int main()
{
char *argv[]={"/bin/cat", "flag", NULL};
char *env[]={NULL};
char cmd[20] = "/bin/cat"; scmp_filter_ctx ctx;
ctx = seccomp_init(SCMP_ACT_ALLOW); // default action: Allow
seccomp_rule_add(ctx, SCMP_ACT_KILL, SCMP_SYS(write), 0);
seccomp_load(ctx); //syscall(0x3b, cmd, argv, env); pid_t pid;
int rv;
pid = fork();
if(pid == 0){ // child process
syscall(59, cmd, argv, env);
}
else
{
waitpid(pid, &rv, 0);
}
return 0; return 0;
}

结果:

➜  seccomp-escape ./syscall
➜ seccomp-escape

查看沙箱规则

seccomp-tools dump ./pwn1

编写沙箱规则的shellcode

使用seccomp-tools生成规则,一条规则是8个字节

#cat 1.asm
A = sys_number
A == 257? e0:next
A == 1? ok:next
return ALLOW
e0:
return ERRNO(0)
ok:
return ALLOW

规则如下:

#seccomp-tools asm 1.asm -f raw |seccomp-tools disasm -
line CODE JT JF K
=================================
0000: 0x20 0x00 0x00 0x00000000 A = sys_number
0001: 0x15 0x02 0x00 0x00000101 if (A == openat) goto 0004
0002: 0x15 0x02 0x00 0x00000001 if (A == write) goto 0005
0003: 0x06 0x00 0x00 0x7fff0000 return ALLOW
0004: 0x06 0x00 0x00 0x00050000 return ERRNO(0)
0005: 0x06 0x00 0x00 0x7fff0000 return ALLOW

生成16进制字符串

#seccomp-tools asm 1.asm
"\x20\x00\x00\x00\x00\x00\x00\x00\x15\x00\x02\x00\x01\x01\x00\x00\x15\x00\x02\x00\x01\x00\x00\x00\x06\x00\x00\x00\x00\x00\xFF\x7F\x06\x00\x00\x00\x00\x00\x05\x00\x06\x00\x00\x00\x00\x00\xFF\x7F"

seccomp沙盒逃逸基础——沙盒的规则编写的更多相关文章

  1. SharePoint2010沙盒解决方案基础开发——关于TreeView树形控件读取列表数据(树形导航)的webpart开发及问题

    转:http://blog.csdn.net/miragesky2049/article/details/7204882 SharePoint2010沙盒解决方案基础开发--关于TreeView树形控 ...

  2. 再谈CVE-2017-7047 Triple_Fetch和iOS 10.3.2沙盒逃逸

    作者:蒸米 ----------------- 0x00 序 Ian Beer@google发布了CVE-2017-7047Triple_Fetch的exp和writeup[1],chenliang@ ...

  3. python沙盒逃逸

    前言 最近遇到了很多python沙盒逃逸的题目(不知道是不是因为现在python搭的站多了--),实际使用时发现只会复制别人的payload是不够用的,于是自己来总结一波(顺带一提python沙盒逃逸 ...

  4. SSTI注入绕过(沙盒逃逸原理一样)

    在python沙盒逃逸中绕过道理是一样的. 1.python沙盒中删除了很多模块,但是没有删除reload reload(__builtins__),重新加载被删除的模块,直接命令执行,只用于py2 ...

  5. python-Flask模版注入攻击SSTI(python沙盒逃逸)

    一篇以python Flask 模版渲染为例子的SSTI注入教学~ 0x01 Flask使用和渲染 这里简化了flask使用和渲染的教程 只把在安全中我们需要关注的部分写出来 来一段最简单的FLASK ...

  6. CSS基础必备盒模型及清除浮动

    盒模型 盒模型是有两种标准的,一个是标准模型,一个是IE模型. css如何设置两种模型 这里用到了CSS3 的属性 box-sizing /* 标准模型 */ box-sizing:content-b ...

  7. 标准盒模型与IE盒模型之间的转换

    首先上图,这两张很明显可以看出IE盒模型和标准盒模型之间的差别. 当然今天不是去细细追究两种模型具体是怎么去计算布局的,那个很多文章已经已经有过了,不再重复.以前刚开始学习盒模型的时候,就学到的是IE ...

  8. IE盒模型与W3C盒模型区别

    前两天被人问到,叫我解释一下标准盒模型与IE盒模型,额,当时只能说,知道一点,但是没有深入的去探讨过,所以下来之后就自己写了例子,亲自去验证并且查看了网上的一些资料,现将其整理如下: 一.css盒模型 ...

  9. IE盒模型和标准盒模型

    标准盒模型和ie盒模型(怪异盒模型) w3c标准盒模型 width和height不包括padding和border ie盒模型 width和height包含padding和border ie8以上都是 ...

随机推荐

  1. SpringMVC-05 Json交互处理

    SpringMVC-05 Json交互处理 Json 1.什么是JSON? JSON(JavaScript Object Notation, JS 对象标记) 是一种轻量级的数据交换格式,目前使用特别 ...

  2. 锐捷RG-UAC统一上网行为管理审计系统账号密码泄露漏洞 CNVD-2021-14536

    一:产品介绍: 锐捷 RG-UAC 统一上网行为管理审计系统 锐捷统一上网行为管理与审计RG-UAC系列是星网锐捷网络有限公司自主研发的上网行为管理与审计产品,以路由.透明.旁路或混合模式部署在网络的 ...

  3. sqlmap在https下的一种错误 - ssl连接失败

    在昨天与师傅的交流中师傅考了我一个问题,在用sqlmap跑的时候遇到ssl爆红该怎么办,因为在实战中并没有遇到过这种情况,所以今天补一下知识. 首先查询了ssl的概念,通俗来说,如果一个网站没有安装s ...

  4. 2018ICPC南京 A. Adrien and Austin

    题目: 题意:1-N个石子每次只能取连续的1-K个问输赢.(一开始以为只是个简简单单的巴什游戏,激动的提交了一发wr了,再读了一遍题才发现是只能取连续的) 题解:当n==0或者k==1&&am ...

  5. Shell中的(),{}几种语法用法-单独总结

    shell中的(),{}几种语法用法 查看脚本语法是否有错误: bash -n modify_suffix.sh 跟踪执行 sh -x modify_suffix.sh aaa 1. ${var} 2 ...

  6. 热更新应用--热补丁Hotfix学习笔记

    一.热补丁简介 热补丁主要是用于将纯C#工程在不重做的情况下通过打补丁的形式改造成具备lua热更新功能工程,主要是让原来脚本中Start函数和Update函数等函数代码块重定向到lua代码. 二.第一 ...

  7. [深搜]C. 【例题3】虫食算

    C . [ 例 题 3 ] 虫 食 算 题目解析 正解 : Dfs + 剪枝 依题意,把样例以加法的形式展现出来. 根据加法的性质,可以得出有两种情况:有进位和没有进位的. 而从百位到最高位的结果,又 ...

  8. [图论]最短网络:prim

    最短网络 目录 最短网络 Description Input Output Sample Input Sample Output 解析 代码 Description 农民约翰被选为他们镇的镇长!他其中 ...

  9. 面试官:Java中线程是按什么顺序执行的?

    摘要:Java中多线程并发的执行顺序历来是面试中的重点,掌握Java中线程的执行顺序不仅能够在面试中让你脱颖而出,更能够让你在平时的工作中,迅速定位由于多线程并发问题导致的"诡异" ...

  10. Unity2D项目-平台、解谜、战斗! 0.1 序言:团队、项目提出、初步设计、剧情大纲

    各位看官老爷们,这里是RuaiRuai工作室(以下简称RR社),一个做单机游戏的兴趣作坊. 本文跟大家聊一下社团内第一个游戏项目.算是从萌新项目组长的角度,从第一个里程碑的结点处,往前看总结一下项目之 ...