最近在研究怎么用patchkit写一个pwn通防,以便在AWD比赛中多苟一秒。
因为patchkit虽然可以使用C语言,但不能使用任何库函数,什么都得自己实现,所以我的想法是用prctl syscall来用汇编实现,先尝试在64位系统中实现,prctl的系统调用号为157.
prctl 函数原形为 prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog)
其中 prog为如下的结构体
struct sock_fprog { /* Required for SO_ATTACH_FILTER. */
unsigned short len; /* Number of filter blocks */
struct sock_filter *filter;
};
Filter为指向一个BPF结构体数组指针,Len为结构体个数。
struct sock_filter { /* Filter block */
__u16 code; /* Actual filter code */
__u8 jt; /* Jump true */
__u8 jf; /* Jump false */
__u32 k; /* Generic multiuse field */
};
然而这两个结构体并不是那么好写,好在有一个叫seccomp_export_bpf
的函数能够将设置的seccomp以bpf的形式导出,如下.
//要使用seccomp需要安装库
sudo apt install libseccomp-dev libseccomp2 seccomp
//gcc -g simple_syscall_seccomp.c -o simple_syscall_seccomp -lseccomp
#include <unistd.h>
#include <seccomp.h>
#include <linux/seccomp.h>
#include <fcntl.h>
int main(void){
scmp_filter_ctx ctx;
ctx = seccomp_init(SCMP_ACT_ALLOW);
seccomp_rule_add(ctx, SCMP_ACT_KILL, SCMP_SYS(socket), 0);
seccomp_rule_add(ctx, SCMP_ACT_KILL, SCMP_SYS(connect), 0);
seccomp_rule_add(ctx, SCMP_ACT_KILL, SCMP_SYS(bind), 0);
seccomp_rule_add(ctx, SCMP_ACT_KILL, SCMP_SYS(listen), 0);
seccomp_rule_add(ctx, SCMP_ACT_KILL, SCMP_SYS(clone), 0);
seccomp_rule_add(ctx, SCMP_ACT_KILL, SCMP_SYS(execve), 0);
int fd = open("./bpf.out",O_WRONLY|O_CREAT);
seccomp_export_bpf(ctx,fd);
close(fd);
seccomp_load(ctx);
system("/bin/sh");
}
用seccomp_rule_add可以方便的添加一些自定义规则,导出bpf
$hexdump bpf.out -C
00000000 20 00 00 00 04 00 00 00 15 00 00 09 3e 00 00 c0 | ...........>...|
00000010 20 00 00 00 00 00 00 00 35 00 07 00 00 00 00 40 | .......5......@|
00000020 15 00 06 00 29 00 00 00 15 00 05 00 2a 00 00 00 |....).......*...|
00000030 15 00 04 00 31 00 00 00 15 00 03 00 32 00 00 00 |....1.......2...|
00000040 15 00 02 00 38 00 00 00 15 00 01 00 3b 00 00 00 |....8.......;...|
00000050 06 00 00 00 00 00 ff 7f 06 00 00 00 00 00 00 00 |................|
00000060
整理成结构体后,先用c测试一下,如果能成功拦截,就说明这个结构体没有问题。
#include <stdio.h>
#include <unistd.h>
#include <linux/seccomp.h>
#include <seccomp.h>
#include<fcntl.h>
#include <sys/prctl.h>
#include <linux/filter.h>
struct sock_filter sfi[] = {
{0x20,0x00,0x00,0x00000004},
{0x15,0x00,0x09,0xc000003e},
{0x20,0x00,0x00,0x00000000},
{0x35,0x07,0x00,0x40000000},
{0x15,0x06,0x00,0x00000029},
{0x15,0x05,0x00,0x0000002a},
{0x15,0x04,0x00,0x00000031},
{0x15,0x03,0x00,0x00000032},
{0x15,0x02,0x00,0x00000038},
{0x15,0x01,0x00,0x0000003b},
{0x06,0x00,0x00,0x7fff0000},
{0x06,0x00,0x00,0x00000000}
};
struct sock_fprog sfp = {12,sfi};
int main() {
printf("step 1: unrestricted\n");
prctl(PR_SET_NO_NEW_PRIVS,1,0,0,0);
prctl(PR_SET_SECCOMP,SECCOMP_MODE_FILTER,&sfp);
system("/bin/sh");
return 0;
}
最后改成汇编:
push rbp;
mov rbp,rsp;
mov r15,6;
push r15;
mov r15,7FFF000000000006H;
push r15;
mov r15,3B00010015H;
push r15;
mov r15 , 3800020015h;
push r15;
mov r15 , 3200030015h;
push r15;
mov r15 , 3100040015h;
push r15;
mov r15 , 2A00050015h;
push r15;
mov r15 , 2900060015h;
push r15;
mov r15 , 4000000000070035h;
push r15;
mov r15 , 20h;
push r15;
mov r15 , 0C000003E09000015h;
push r15;
mov r15 , 400000020h;
push r15;
mov r15,rsp;
push r15;
mov r15 , 0ch;
push r15;
mov r15,rsp;
push r15;
mov rdi,38;
mov rsi,1;
mov rdx,0;
mov rcx,0;
mov r8,0;
mov rax,157;
syscall;
mov rdi,22;
mov rsi,2;
mov rdx,r15;
mov rax,157;
syscall;
leave;
ret;
更具体的使用方法放在github上了: