seccomp沙盒逃逸基础——沙盒的规则编写
seccomp沙盒逃逸基础——沙盒的规则编写
引入:
安全计算模式 seccomp(Secure Computing Mode)是自 Linux 2.6.10 之后引入到 kernel 的特性。一切都在内核中完成,不需要额外的上下文切换,所以不会造成性能问题。目前 在 Docker 和 Chrome 中广泛使用。使用 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)表示禁用系统调用,也就是system和onegadget都没了,还会教子进程也这么干,很坏;
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沙盒逃逸基础——沙盒的规则编写的更多相关文章
- SharePoint2010沙盒解决方案基础开发——关于TreeView树形控件读取列表数据(树形导航)的webpart开发及问题
转:http://blog.csdn.net/miragesky2049/article/details/7204882 SharePoint2010沙盒解决方案基础开发--关于TreeView树形控 ...
- 再谈CVE-2017-7047 Triple_Fetch和iOS 10.3.2沙盒逃逸
作者:蒸米 ----------------- 0x00 序 Ian Beer@google发布了CVE-2017-7047Triple_Fetch的exp和writeup[1],chenliang@ ...
- python沙盒逃逸
前言 最近遇到了很多python沙盒逃逸的题目(不知道是不是因为现在python搭的站多了--),实际使用时发现只会复制别人的payload是不够用的,于是自己来总结一波(顺带一提python沙盒逃逸 ...
- SSTI注入绕过(沙盒逃逸原理一样)
在python沙盒逃逸中绕过道理是一样的. 1.python沙盒中删除了很多模块,但是没有删除reload reload(__builtins__),重新加载被删除的模块,直接命令执行,只用于py2 ...
- python-Flask模版注入攻击SSTI(python沙盒逃逸)
一篇以python Flask 模版渲染为例子的SSTI注入教学~ 0x01 Flask使用和渲染 这里简化了flask使用和渲染的教程 只把在安全中我们需要关注的部分写出来 来一段最简单的FLASK ...
- CSS基础必备盒模型及清除浮动
盒模型 盒模型是有两种标准的,一个是标准模型,一个是IE模型. css如何设置两种模型 这里用到了CSS3 的属性 box-sizing /* 标准模型 */ box-sizing:content-b ...
- 标准盒模型与IE盒模型之间的转换
首先上图,这两张很明显可以看出IE盒模型和标准盒模型之间的差别. 当然今天不是去细细追究两种模型具体是怎么去计算布局的,那个很多文章已经已经有过了,不再重复.以前刚开始学习盒模型的时候,就学到的是IE ...
- IE盒模型与W3C盒模型区别
前两天被人问到,叫我解释一下标准盒模型与IE盒模型,额,当时只能说,知道一点,但是没有深入的去探讨过,所以下来之后就自己写了例子,亲自去验证并且查看了网上的一些资料,现将其整理如下: 一.css盒模型 ...
- IE盒模型和标准盒模型
标准盒模型和ie盒模型(怪异盒模型) w3c标准盒模型 width和height不包括padding和border ie盒模型 width和height包含padding和border ie8以上都是 ...
随机推荐
- WorkSkill整理之 java用Scanner 类输入数组并打印
输入不确定长度的数组 import java.util.*; public static void main(String[] args){ System.out.println("请输入一 ...
- Anchor-Free总结
目录 Anchor-Free综述 一. CornerNet 1.1 概述 1.2 模块介绍 1.2.1 Heatmap 1.2.2 Offset 1.2.3 Grouping Corners 1.2. ...
- IPFS是什么?IPFS与Filecoin有什么关系?
Filecoin 基于 IPFS 的去中心化存储网络,是 IPFS 上唯一的激励层,是一个基于区块链技术发行的通证.Filecoin 翻译过来就是文件币,简称为 FIL. 在 FIlecoin 网络中 ...
- 周期串(JAVA语言)
package 第三章习题; /* * 如果一个字符可以由某个长度为k的字符串重复多次得到,则称该串以k为周期. * 例如:abcabcabcabc 以3为周期(注意:它也以6和12为周期) * ...
- 开源的 Switch 模拟器——GitHub 热点速览 v.21.12
作者:HelloGitHub-小鱼干 脸滚键盘操作选手小鱼干这里要推荐一个超酷 Switch 模拟器,不能埋没你的游戏天赋.Ryujinx 是一个 C# 写的 Switch 模拟器,1700+ 游戏可 ...
- 学习笔记-json数据格式化
标准的json : let result=[{"a": 'aa', "b": 'aa', "c": 'aa'}, {"a" ...
- Database | 浅谈Query Optimization (2)
为什么选择左深连接树 对于n个表的连接,数量为卡特兰数,近似\(4^n\),因此为了减少枚举空间,早期的优化器仅考虑左深连接树,将数量减少为\(n!\) 但为什么是左深连接树,而不是其他样式呢? 如果 ...
- (6)MySQL进阶篇SQL优化(MyISAM表锁)
1.MySQL锁概述 锁是计算机协调多个进程或线程并发访问某一资源的机制.在数据库中,除传统的计算资源 (如 CPU.RAM.I/O 等)的抢占以外,数据也是一种供许多用户共享的资源.如何保证数 据并 ...
- Dynamic CRM登陆界面的客制化(持续更新)
Dynamic CRM的登陆页面比较西化,不是很适合中国人使用.目前先把注销跳转的问题解决了. 服务端使用下面命令,将文件导出来 Export-AdfsWebTheme –Name default – ...
- OO第四单元作业总结以及课程总结
第四单元总结--UML 第四单元作业架构分析 第一次作业其实是本单元三次作业中最难的一次.由于第一次是第一次作业,要考虑到搭建框架和设计架构,这次作业的思维性很强.在了解了各个类型元素(Element ...