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. 如何优雅的移植JavaScript组件到Blazor

    Blazor作为一个新兴的交互式 Web UI 的框架,有其自身的优缺点,如果现有的 JavaScript 组件能移植到 Blazor,无疑让 Blazor 如虎添翼,本文就介绍一下自己在开发 Bul ...

  2. CentOS 8.3安装MySQL 8.0.21后无法登录管理数据库

    安装mysql后登录不了,提示: ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES) ...

  3. EF Core 原理从源码出发(二)

    紧接着我的上一篇博客,上回分析到ef 一个重要的对象,changetracker这个对象,当我们向DbContext添加对象的时候我们会调用如下代码. 1 private EntityEntry< ...

  4. css字体的属性

    1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="U ...

  5. CSS网页的布局

    1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="U ...

  6. ethtool - 命令

    ethtool 导览:     1. 如何查看 Linux 中可用的网卡接口     2. 如何查看 Linux 中网卡信息     3. 如何查看网卡驱动版本以及硬件版本     4. 如何查看网络 ...

  7. 【python小示例】简易彩票中奖模拟

    咱自己写个彩票程序,成功亏掉3个亿 今天突发奇想,自己设计一个小程序,模拟彩票中奖,看看如果自己有个彩票公司,能挣钱吗?代码如下: # -*- utf-8 -*- """ ...

  8. 使用Azure API Management, Functions, Power Apps和Logic App构建应用

    ASP.NET OpenAPI 可以非常方便的将我们的Web API项目自动文档化,除了自动文档化以外,我们还可以利用Azure API Management将Open API自动文档化了的Web A ...

  9. [状压DP]炮兵阵地

    炮 兵 阵 地 炮兵阵地 炮兵阵地 题目描述 司令部的将军们打算在 N ∗ M N*M N∗M的网格地图上部署他们的炮兵部队.一个 N ∗ M N*M N∗M的地图由 N N N行 M M M列组成, ...

  10. 《进击吧!Blazor!》系列入门教程 第一章 8.部署

    <进击吧!Blazor!>是本人与张善友老师合作的Blazor零基础入门教程视频,此教程能让一个从未接触过Blazor的程序员掌握开发Blazor应用的能力. 视频地址:https://s ...