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:
- Parses the
ipandportmodule parameters. - Creates a TCP socket and attempts to connect to the C2 server.
- On successful connection, sends an encrypted greeting message.
- 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:
- The server sends the password (the raw password, not the hash).
- The rootkit hashes the received password and compares it to the stored
password_hashusing constant-time comparison. - If authentication succeeds, the rootkit elevates to root privileges and unlocks command execution for the session.
- If authentication fails, a rejection message is sent and the session remains locked.
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:
- The current socket is cleaned up.
- The thread sleeps for 5 seconds.
- 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
rmmodwithout 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;
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.