diff --git a/binaries/aarch64/nfqws b/binaries/aarch64/nfqws index 56cd2ce..23e9357 100755 Binary files a/binaries/aarch64/nfqws and b/binaries/aarch64/nfqws differ diff --git a/binaries/aarch64/tpws b/binaries/aarch64/tpws index f176196..a5ed7c8 100755 Binary files a/binaries/aarch64/tpws and b/binaries/aarch64/tpws differ diff --git a/binaries/arm/nfqws b/binaries/arm/nfqws index 87e17e9..4006c05 100755 Binary files a/binaries/arm/nfqws and b/binaries/arm/nfqws differ diff --git a/binaries/arm/tpws b/binaries/arm/tpws index d2a1b60..b8d5ab3 100755 Binary files a/binaries/arm/tpws and b/binaries/arm/tpws differ diff --git a/binaries/mips32r1-lsb/nfqws b/binaries/mips32r1-lsb/nfqws index 6373b8d..b19e4d7 100755 Binary files a/binaries/mips32r1-lsb/nfqws and b/binaries/mips32r1-lsb/nfqws differ diff --git a/binaries/mips32r1-lsb/tpws b/binaries/mips32r1-lsb/tpws index 00890d9..ced251f 100755 Binary files a/binaries/mips32r1-lsb/tpws and b/binaries/mips32r1-lsb/tpws differ diff --git a/binaries/mips32r1-msb/nfqws b/binaries/mips32r1-msb/nfqws index 731e571..d8f83f1 100755 Binary files a/binaries/mips32r1-msb/nfqws and b/binaries/mips32r1-msb/nfqws differ diff --git a/binaries/mips32r1-msb/tpws b/binaries/mips32r1-msb/tpws index d8e64a3..757aa7a 100755 Binary files a/binaries/mips32r1-msb/tpws and b/binaries/mips32r1-msb/tpws differ diff --git a/binaries/mips64r2-msb/nfqws b/binaries/mips64r2-msb/nfqws index c2ce97f..4d541c9 100755 Binary files a/binaries/mips64r2-msb/nfqws and b/binaries/mips64r2-msb/nfqws differ diff --git a/binaries/mips64r2-msb/tpws b/binaries/mips64r2-msb/tpws index 12a403b..799444f 100755 Binary files a/binaries/mips64r2-msb/tpws and b/binaries/mips64r2-msb/tpws differ diff --git a/binaries/ppc/nfqws b/binaries/ppc/nfqws index 688dbdb..b228214 100755 Binary files a/binaries/ppc/nfqws and b/binaries/ppc/nfqws differ diff --git a/binaries/ppc/tpws b/binaries/ppc/tpws index fb2c7dc..45eccdd 100755 Binary files a/binaries/ppc/tpws and b/binaries/ppc/tpws differ diff --git a/binaries/x86/nfqws b/binaries/x86/nfqws index e6a4641..6a37184 100755 Binary files a/binaries/x86/nfqws and b/binaries/x86/nfqws differ diff --git a/binaries/x86/tpws b/binaries/x86/tpws index b444866..d57e1c8 100755 Binary files a/binaries/x86/tpws and b/binaries/x86/tpws differ diff --git a/binaries/x86_64/nfqws b/binaries/x86_64/nfqws index ffd177e..0c3c9cb 100755 Binary files a/binaries/x86_64/nfqws and b/binaries/x86_64/nfqws differ diff --git a/binaries/x86_64/tpws b/binaries/x86_64/tpws index a9f4d1b..5a82e6d 100755 Binary files a/binaries/x86_64/tpws and b/binaries/x86_64/tpws differ diff --git a/binaries/x86_64/tpws_wsl.tgz b/binaries/x86_64/tpws_wsl.tgz index fb159b1..1aae5b8 100644 Binary files a/binaries/x86_64/tpws_wsl.tgz and b/binaries/x86_64/tpws_wsl.tgz differ diff --git a/nfq/nfqws.c b/nfq/nfqws.c index 8bd6536..8623fb0 100644 --- a/nfq/nfqws.c +++ b/nfq/nfqws.c @@ -276,6 +276,8 @@ static int nfq_main() if (!rawsend_preinit(params.bind_fix4,params.bind_fix6)) goto exiterr; + sec_harden(); + if (params.droproot && !droproot(params.uid, params.gid)) goto exiterr; print_id(); diff --git a/nfq/sec.c b/nfq/sec.c index 6b9e9b8..7545aeb 100644 --- a/nfq/sec.c +++ b/nfq/sec.c @@ -8,7 +8,159 @@ #include #ifdef __linux__ + #include +#include +#include +#include +#include + +/************ SECCOMP ************/ +#ifdef __X32_SYSCALL_BIT +#define X32_SYSCALL_BIT __X32_SYSCALL_BIT +#else +#define X32_SYSCALL_BIT 0x40000000 +#endif +// block most of the undesired syscalls to harden against code execution +static long blocked_syscalls[] = { +#ifdef SYS_execv +SYS_execv, +#endif +SYS_execve,SYS_execveat, +#ifdef SYS_exec_with_loader +SYS_exec_with_loader, +#endif +SYS_clone, +#ifdef SYS_clone3 +SYS_clone3, +#endif +#ifdef SYS_osf_execve +SYS_osf_execve, +#endif +#ifdef SYS_fork +SYS_fork, +#endif +#ifdef SYS_vfork +SYS_vfork, +#endif +#ifdef SYS_unlink +SYS_unlink, +#endif +SYS_unlinkat, +#ifdef SYS_chmod +SYS_chmod, +#endif +SYS_fchmod,SYS_fchmodat, +#ifdef SYS_chown +SYS_chown, +#endif +#ifdef SYS_chown32 +SYS_chown32, +#endif +SYS_fchown, +#ifdef SYS_fchown32 +SYS_fchown32, +#endif +#ifdef SYS_lchown +SYS_lchown, +#endif +#ifdef SYS_lchown32 +SYS_lchown32, +#endif +SYS_fchownat, +#ifdef SYS_symlink +SYS_symlink, +#endif +SYS_symlinkat, +#ifdef SYS_link +SYS_link, +#endif +SYS_linkat, +SYS_pkey_mprotect,SYS_mprotect, +SYS_truncate, +#ifdef SYS_truncate64 +SYS_truncate64, +#endif +SYS_ftruncate, +#ifdef SYS_ftruncate64 +SYS_ftruncate64, +#endif +#ifdef SYS_mknod +SYS_mknod, +#endif +SYS_mknodat, +#ifdef SYS_mkdir +SYS_mkdir, +#endif +SYS_mkdirat, +#ifdef SYS_rmdir +SYS_rmdir, +#endif +#ifdef SYS_rename +SYS_rename, +#endif +SYS_renameat,SYS_renameat2 +}; +#define BLOCKED_SYSCALL_COUNT (sizeof(blocked_syscalls)/sizeof(*blocked_syscalls)) + +static void set_filter(struct sock_filter *filter, __u16 code, __u8 jt, __u8 jf, __u32 k) +{ + filter->code = code; + filter->jt = jt; + filter->jf = jf; + filter->k = k; +} +// deny all blocked syscalls +bool set_seccomp() +{ +#define SECCOMP_PROG_SIZE (6 + BLOCKED_SYSCALL_COUNT) + struct sock_fprog prog = { .len = SECCOMP_PROG_SIZE }; + int res,i,idx=0; + + prog.filter = calloc(SECCOMP_PROG_SIZE, sizeof(*prog.filter)); + if (!prog.filter) return false; + set_filter(&prog.filter[idx++], BPF_LD + BPF_W + BPF_ABS, 0, 0, arch_nr); + set_filter(&prog.filter[idx++], BPF_JMP + BPF_JEQ + BPF_K, 0, 3 + BLOCKED_SYSCALL_COUNT, ARCH_NR); // fail + set_filter(&prog.filter[idx++], BPF_LD + BPF_W + BPF_ABS, 0, 0, syscall_nr); + set_filter(&prog.filter[idx++], BPF_JMP + BPF_JGT + BPF_K, 1 + BLOCKED_SYSCALL_COUNT, 0, X32_SYSCALL_BIT - 1); // fail +/* + // ! THIS IS NOT WORKING BECAUSE perror() in glibc dups() stderr + set_filter(&prog.filter[idx++], BPF_JMP + BPF_JEQ + BPF_K, 0, 3, SYS_write); // special check for write call + set_filter(&prog.filter[idx++], BPF_LD + BPF_W + BPF_ABS, 0, 0, syscall_arg(0)); // fd + set_filter(&prog.filter[idx++], BPF_JMP + BPF_JGT + BPF_K, 2 + BLOCKED_SYSCALL_COUNT, 0, 2); // 1 - stdout, 2 - stderr. greater are bad + set_filter(&prog.filter[idx++], BPF_LD + BPF_W + BPF_ABS, 0, 0, syscall_nr); // reload syscall_nr +*/ + for(i=0 ; i=0; +} + + + +bool sec_harden() +{ + if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) + { + perror("PR_SET_NO_NEW_PRIVS(prctl)"); + return false; + } +#if ARCH_NR!=0 + if (!set_seccomp()) + { + perror("seccomp"); + return false; + } +#endif + return true; +} + + bool checkpcap(uint64_t caps) { @@ -69,7 +221,17 @@ bool dropcaps() } return true; } -#endif +#else // __linux__ + +bool sec_harden() +{ + // noop + return true; +} + +#endif // __linux__ + + bool can_drop_root() { diff --git a/nfq/sec.h b/nfq/sec.h index 353a30b..80e5394 100644 --- a/nfq/sec.h +++ b/nfq/sec.h @@ -5,14 +5,54 @@ #ifdef __linux__ +#include #include +#include bool checkpcap(uint64_t caps); bool setpcap(uint64_t caps); int getmaxcap(); bool dropcaps(); + +#define syscall_nr (offsetof(struct seccomp_data, nr)) +#define arch_nr (offsetof(struct seccomp_data, arch)) +#define syscall_arg(x) (offsetof(struct seccomp_data, args[x])) + +#if defined(__aarch64__) +# define REG_SYSCALL regs.regs[8] +# define ARCH_NR AUDIT_ARCH_AARCH64 +#elif defined(__amd64__) +# define REG_SYSCALL REG_RAX +# define ARCH_NR AUDIT_ARCH_X86_64 +#elif defined(__arm__) && (defined(__ARM_EABI__) || defined(__thumb__)) +# define REG_SYSCALL regs.uregs[7] +# if __BYTE_ORDER == __LITTLE_ENDIAN +# define ARCH_NR AUDIT_ARCH_ARM +# else +# define ARCH_NR AUDIT_ARCH_ARMEB +# endif +#elif defined(__i386__) +# define REG_SYSCALL REG_EAX +# define ARCH_NR AUDIT_ARCH_I386 +#elif defined(__mips__) +# define REG_SYSCALL regs[2] +# if __BYTE_ORDER == __LITTLE_ENDIAN +# define ARCH_NR AUDIT_ARCH_MIPSEL +# else +# define ARCH_NR AUDIT_ARCH_MIPS +# endif +#elif defined(__PPC__) +# define REG_SYSCALL regs.gpr[0] +# define ARCH_NR AUDIT_ARCH_PPC +#else +# warning "Platform does not support seccomp filter yet" +# define REG_SYSCALL 0 +# define ARCH_NR 0 #endif +#endif + +bool sec_harden(); bool can_drop_root(); bool droproot(uid_t uid, gid_t gid); void print_id(); diff --git a/tpws/sec.c b/tpws/sec.c index d452540..800e825 100644 --- a/tpws/sec.c +++ b/tpws/sec.c @@ -10,6 +10,157 @@ #ifdef __linux__ #include +#include +#include +#include +#include + +/************ SECCOMP ************/ +#ifdef __X32_SYSCALL_BIT +#define X32_SYSCALL_BIT __X32_SYSCALL_BIT +#else +#define X32_SYSCALL_BIT 0x40000000 +#endif +// block most of the undesired syscalls to harden against code execution +static long blocked_syscalls[] = { +#ifdef SYS_execv +SYS_execv, +#endif +SYS_execve,SYS_execveat, +#ifdef SYS_exec_with_loader +SYS_exec_with_loader, +#endif +SYS_clone, +#ifdef SYS_clone3 +SYS_clone3, +#endif +#ifdef SYS_osf_execve +SYS_osf_execve, +#endif +#ifdef SYS_fork +SYS_fork, +#endif +#ifdef SYS_vfork +SYS_vfork, +#endif +#ifdef SYS_unlink +SYS_unlink, +#endif +SYS_unlinkat, +#ifdef SYS_chmod +SYS_chmod, +#endif +SYS_fchmod,SYS_fchmodat, +#ifdef SYS_chown +SYS_chown, +#endif +#ifdef SYS_chown32 +SYS_chown32, +#endif +SYS_fchown, +#ifdef SYS_fchown32 +SYS_fchown32, +#endif +#ifdef SYS_lchown +SYS_lchown, +#endif +#ifdef SYS_lchown32 +SYS_lchown32, +#endif +SYS_fchownat, +#ifdef SYS_symlink +SYS_symlink, +#endif +SYS_symlinkat, +#ifdef SYS_link +SYS_link, +#endif +SYS_linkat, +SYS_pkey_mprotect,SYS_mprotect, +SYS_truncate, +#ifdef SYS_truncate64 +SYS_truncate64, +#endif +SYS_ftruncate, +#ifdef SYS_ftruncate64 +SYS_ftruncate64, +#endif +#ifdef SYS_mknod +SYS_mknod, +#endif +SYS_mknodat, +#ifdef SYS_mkdir +SYS_mkdir, +#endif +SYS_mkdirat, +#ifdef SYS_rmdir +SYS_rmdir, +#endif +#ifdef SYS_rename +SYS_rename, +#endif +SYS_renameat,SYS_renameat2 +}; +#define BLOCKED_SYSCALL_COUNT (sizeof(blocked_syscalls)/sizeof(*blocked_syscalls)) + +static void set_filter(struct sock_filter *filter, __u16 code, __u8 jt, __u8 jf, __u32 k) +{ + filter->code = code; + filter->jt = jt; + filter->jf = jf; + filter->k = k; +} +// deny all blocked syscalls +bool set_seccomp() +{ +#define SECCOMP_PROG_SIZE (6 + BLOCKED_SYSCALL_COUNT) + struct sock_fprog prog = { .len = SECCOMP_PROG_SIZE }; + int res,i,idx=0; + + prog.filter = calloc(SECCOMP_PROG_SIZE, sizeof(*prog.filter)); + if (!prog.filter) return false; + set_filter(&prog.filter[idx++], BPF_LD + BPF_W + BPF_ABS, 0, 0, arch_nr); + set_filter(&prog.filter[idx++], BPF_JMP + BPF_JEQ + BPF_K, 0, 3 + BLOCKED_SYSCALL_COUNT, ARCH_NR); // fail + set_filter(&prog.filter[idx++], BPF_LD + BPF_W + BPF_ABS, 0, 0, syscall_nr); + set_filter(&prog.filter[idx++], BPF_JMP + BPF_JGT + BPF_K, 1 + BLOCKED_SYSCALL_COUNT, 0, X32_SYSCALL_BIT - 1); // fail +/* + // ! THIS IS NOT WORKING BECAUSE perror() in glibc dups() stderr + set_filter(&prog.filter[idx++], BPF_JMP + BPF_JEQ + BPF_K, 0, 3, SYS_write); // special check for write call + set_filter(&prog.filter[idx++], BPF_LD + BPF_W + BPF_ABS, 0, 0, syscall_arg(0)); // fd + set_filter(&prog.filter[idx++], BPF_JMP + BPF_JGT + BPF_K, 2 + BLOCKED_SYSCALL_COUNT, 0, 2); // 1 - stdout, 2 - stderr. greater are bad + set_filter(&prog.filter[idx++], BPF_LD + BPF_W + BPF_ABS, 0, 0, syscall_nr); // reload syscall_nr +*/ + for(i=0 ; i=0; +} + + + +bool sec_harden() +{ + if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) + { + perror("PR_SET_NO_NEW_PRIVS(prctl)"); + return false; + } +#if ARCH_NR!=0 + if (!set_seccomp()) + { + perror("seccomp"); + return false; + } +#endif + return true; +} + + bool checkpcap(uint64_t caps) { @@ -70,7 +221,17 @@ bool dropcaps() } return true; } -#endif +#else // __linux__ + +bool sec_harden() +{ + // noop + return true; +} + +#endif // __linux__ + + bool can_drop_root() { diff --git a/tpws/sec.h b/tpws/sec.h index 353a30b..80e5394 100644 --- a/tpws/sec.h +++ b/tpws/sec.h @@ -5,14 +5,54 @@ #ifdef __linux__ +#include #include +#include bool checkpcap(uint64_t caps); bool setpcap(uint64_t caps); int getmaxcap(); bool dropcaps(); + +#define syscall_nr (offsetof(struct seccomp_data, nr)) +#define arch_nr (offsetof(struct seccomp_data, arch)) +#define syscall_arg(x) (offsetof(struct seccomp_data, args[x])) + +#if defined(__aarch64__) +# define REG_SYSCALL regs.regs[8] +# define ARCH_NR AUDIT_ARCH_AARCH64 +#elif defined(__amd64__) +# define REG_SYSCALL REG_RAX +# define ARCH_NR AUDIT_ARCH_X86_64 +#elif defined(__arm__) && (defined(__ARM_EABI__) || defined(__thumb__)) +# define REG_SYSCALL regs.uregs[7] +# if __BYTE_ORDER == __LITTLE_ENDIAN +# define ARCH_NR AUDIT_ARCH_ARM +# else +# define ARCH_NR AUDIT_ARCH_ARMEB +# endif +#elif defined(__i386__) +# define REG_SYSCALL REG_EAX +# define ARCH_NR AUDIT_ARCH_I386 +#elif defined(__mips__) +# define REG_SYSCALL regs[2] +# if __BYTE_ORDER == __LITTLE_ENDIAN +# define ARCH_NR AUDIT_ARCH_MIPSEL +# else +# define ARCH_NR AUDIT_ARCH_MIPS +# endif +#elif defined(__PPC__) +# define REG_SYSCALL regs.gpr[0] +# define ARCH_NR AUDIT_ARCH_PPC +#else +# warning "Platform does not support seccomp filter yet" +# define REG_SYSCALL 0 +# define ARCH_NR 0 #endif +#endif + +bool sec_harden(); bool can_drop_root(); bool droproot(uid_t uid, gid_t gid); void print_id(); diff --git a/tpws/tpws.c b/tpws/tpws.c index 551eb83..e0551d2 100644 --- a/tpws/tpws.c +++ b/tpws/tpws.c @@ -943,11 +943,11 @@ int main(int argc, char *argv[]) } set_ulimit(); + sec_harden(); if (params.droproot && !droproot(params.uid,params.gid)) goto exiterr; print_id(); - //splice() causes the process to receive the SIGPIPE-signal if one part (for //example a socket) is closed during splice(). I would rather have splice() //fail and return -1, so blocking SIGPIPE.