Skip to main content

C2 Connection

The C2 (Command and Control) connection is the core of epirootkit's remote access capability. It runs as a kernel thread and maintains a persistent TCP connection to an attacker-controlled server.

How It Works

When the module loads, module.c spawns a kernel thread running the connection_thread() function. This thread:

  1. Parses the ip and port module parameters.
  2. Creates a TCP socket and attempts to connect to the C2 server.
  3. On successful connection, sends an encrypted greeting message.
  4. Enters a non-blocking receive loop, waiting for commands.
Target Machine C2 Server
┌──────────────┐ ┌──────────────┐
│ Kernel │ TCP connect │ │
│ Thread ───┼──────────────────►│ Listener │
│ │ │ │
│ │ ROT64 greeting │ │
│ ───┼──────────────────►│ │
│ │ │ │
│ │ ROT64 password │ │
│ ◄──┼───────────────────┤ │
│ │ │ │
│ Auth check │ ROT64 result │ │
│ ───┼──────────────────►│ │
│ │ │ │
│ │ ROT64 command │ │
│ ◄──┼───────────────────┤ │
│ │ │ │
│ Execute │ ROT64 output │ │
│ ───┼──────────────────►│ │
└──────────────┘ └──────────────┘

Authentication Flow

Before any command can be executed, the C2 operator must authenticate:

  1. The server sends the password (the raw password, not the hash).
  2. The rootkit hashes the received password and compares it to the stored password_hash using constant-time comparison.
  3. If authentication succeeds, the rootkit elevates to root privileges and unlocks command execution for the session.
  4. If authentication fails, a rejection message is sent and the session remains locked.
info

Authentication is per-connection. If the TCP connection drops, the attacker must re-authenticate after reconnecting.

Auto-Reconnection

The connection thread implements automatic reconnection with a 5-second delay between attempts. If the C2 server is unreachable or the connection drops:

  1. The current socket is cleaned up.
  2. The thread sleeps for 5 seconds.
  3. A new connection attempt is made.

This loop continues indefinitely until the module is unloaded via rmmod.

Non-Blocking Receive

The receive loop uses MSG_DONTWAIT to avoid blocking the kernel thread. This is critical because:

  • It allows kthread_should_stop() to be checked regularly (every 500ms).
  • It enables the module to be unloaded cleanly with rmmod without hanging.
  • If no data is available, the thread simply sleeps for 500ms and checks again.

ROT64 Encryption

All messages exchanged between the rootkit and the C2 server are obfuscated using a ROT64 cipher. Each byte is shifted by 64 positions (modulo 256) before sending, and shifted back on reception.

// Encryption: shift each byte forward by 64
ptr[i] = (ptr[i] + 64) % 256;

// Decryption: shift each byte back by 64
ptr[i] = (ptr[i] - 64 + 256) % 256;
warning

ROT64 is not a secure encryption scheme. It is a simple obfuscation layer to prevent raw traffic from being immediately readable in plain text. It does not provide confidentiality against any serious analysis.