mirror of
https://github.com/rapid7/metasploit-payloads
synced 2024-12-21 05:35:54 +01:00
Land #80, lots of @OJ PRs
This lands: rapid7/meterpreter#69 rapid7/meterpreter#70 rapid7/meterpreter#75 rapid7/meterpreter#77 rapid7/meterpreter#78 All have been tested sufficiently, and once this lands, the binaries as well as the library and module updates represented by rapid7/metasploit-framework#3122 will also land.
This commit is contained in:
commit
369e83318e
@ -8,8 +8,8 @@ framework_dir = ../metasploit-framework/
|
||||
# Change me if you want to build openssl and libpcap somewhere else
|
||||
build_tmp = posix-meterp-build-tmp
|
||||
|
||||
|
||||
BIONIC=$(PWD)/source/bionic
|
||||
ROOT=$(basename $(CURDIR:%/=%))
|
||||
BIONIC=$(ROOT)/source/bionic
|
||||
LIBC=$(BIONIC)/libc
|
||||
LIBM=$(BIONIC)/libm
|
||||
COMPILED=$(BIONIC)/compiled
|
||||
@ -94,7 +94,7 @@ $(COMPILED):
|
||||
mkdir $(COMPILED)/
|
||||
|
||||
$(COMPILED)/libc.so: $(COMPILED)
|
||||
(cd source/bionic/libc && ARCH=x86 TOP=${PWD} jam)
|
||||
(cd source/bionic/libc && ARCH=x86 TOP=${ROOT} jam)
|
||||
(cd source/bionic/libc/out/x86/ && $(MAKE) -f Makefile.msf && [ -f libbionic.so ])
|
||||
cp source/bionic/libc/out/x86/libbionic.so $(COMPILED)/libc.so
|
||||
|
||||
|
@ -84,6 +84,7 @@ You will need:
|
||||
- gcc-multilib, if you're building on a 64-bit machine
|
||||
- jam
|
||||
- wget
|
||||
- flex
|
||||
|
||||
Meterpreter requires libpcap-1.1.1 and OpenSSL 0.9.8o sources, which it
|
||||
will download automatically during the build process. If for some
|
||||
|
@ -213,6 +213,61 @@ Packet *packet_create( PacketTlvType type, LPCSTR method )
|
||||
return packet;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Create a packet that is used to contain a subgroup.
|
||||
* @returns An instance of a packet to use as a group container.
|
||||
* @remarks Group packets can be used to arbitrarily nest groupings prior to
|
||||
* sending the packet to the client.
|
||||
*/
|
||||
Packet* packet_create_group()
|
||||
{
|
||||
Packet* packet = NULL;
|
||||
do
|
||||
{
|
||||
if (!(packet = (Packet*)malloc(sizeof(Packet))))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
memset(packet, 0, sizeof(Packet));
|
||||
|
||||
// we don't need to worry about the TLV header at this point
|
||||
// so we'll ignore it
|
||||
|
||||
// Initialize the payload to be blank
|
||||
packet->payload = NULL;
|
||||
packet->payloadLength = 0;
|
||||
|
||||
return packet;
|
||||
} while (0);
|
||||
|
||||
if (packet)
|
||||
{
|
||||
free(packet);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Add a group packet to the parent packet.
|
||||
* @param packet Pointer to the container packet that the group is to be added to.
|
||||
* @param type The type of group packet being added.
|
||||
* @param groupPacket the packet containing the group data (created by `packet_create_group`).
|
||||
* @returns Indication of success or failure.
|
||||
* @remarks The function calls `packet_destroy` on the `groupPacket` if adding the packet succeeds.
|
||||
*/
|
||||
DWORD packet_add_group(Packet* packet, TlvType type, Packet* groupPacket)
|
||||
{
|
||||
DWORD result = packet_add_tlv_raw(packet, type, groupPacket->payload, groupPacket->payloadLength);
|
||||
if (result == ERROR_SUCCESS)
|
||||
{
|
||||
packet_destroy(groupPacket);
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Create a response packet from a request.
|
||||
* @details Create a response packet from a request, referencing the requestors
|
||||
|
@ -206,9 +206,11 @@ typedef struct
|
||||
*/
|
||||
LINKAGE Packet *packet_create(PacketTlvType type, LPCSTR method);
|
||||
LINKAGE Packet *packet_create_response(Packet *packet);
|
||||
LINKAGE Packet* packet_create_group();
|
||||
LINKAGE Packet *packet_duplicate(Packet *packet);
|
||||
LINKAGE VOID packet_destroy(Packet *packet);
|
||||
|
||||
LINKAGE DWORD packet_add_group(Packet* packet, TlvType type, Packet* groupPacket);
|
||||
LINKAGE DWORD packet_add_tlv_string(Packet *packet, TlvType type, LPCSTR str);
|
||||
LINKAGE DWORD packet_add_tlv_wstring(Packet *packet, TlvType type, LPCWSTR str);
|
||||
LINKAGE DWORD packet_add_tlv_uint(Packet *packet, TlvType type, UINT val);
|
||||
|
@ -3,6 +3,7 @@
|
||||
* @brief Definitions for ADSI functionality.
|
||||
*/
|
||||
#include "extapi.h"
|
||||
#include "wshelpers.h"
|
||||
#include "adsi.h"
|
||||
#include "adsi_interface.h"
|
||||
|
||||
@ -10,41 +11,7 @@
|
||||
#define DEFAULT_PAGE_SIZE 1000
|
||||
|
||||
/*!
|
||||
* @brief Helper function that converts an ASCII string to a wide char string.
|
||||
* @param lpValue ASCII string to convert.
|
||||
* @param lpwValue Target memory for the converted string.
|
||||
* @remark \c lpwValue must be freed by the caller using `free`.
|
||||
* @returns Indication of success or failure.
|
||||
*/
|
||||
DWORD to_wide_string(LPSTR lpValue, LPWSTR* lpwValue)
|
||||
{
|
||||
size_t charsCopied = 0;
|
||||
DWORD valueLength;
|
||||
DWORD dwResult;
|
||||
|
||||
do
|
||||
{
|
||||
if (lpValue == NULL)
|
||||
{
|
||||
BREAK_WITH_ERROR("[EXTAPI ADSI] Value parameter missing", ERROR_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
valueLength = lstrlenA(lpValue);
|
||||
*lpwValue = (LPWSTR)malloc(sizeof(WCHAR)* (lstrlenA(lpValue) + 1));
|
||||
if (*lpwValue == NULL)
|
||||
{
|
||||
BREAK_WITH_ERROR("[EXTAPI ADSI] Unable to allocate memory", ERROR_OUTOFMEMORY);
|
||||
}
|
||||
|
||||
mbstowcs_s(&charsCopied, *lpwValue, valueLength + 1, lpValue, valueLength);
|
||||
dwResult = ERROR_SUCCESS;
|
||||
} while (0);
|
||||
|
||||
return dwResult;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Enumerate all the users in AD.
|
||||
* @brief Perform an ASDI query against a domain.
|
||||
* @param remote Pointer to the \c Remote instance.
|
||||
* @param packet Pointer to the incoming \c Packet instance.
|
||||
* @returns Indication of success or failure.
|
||||
|
@ -5,8 +5,6 @@
|
||||
#ifndef _METERPRETER_SOURCE_EXTENSION_EXTAPI_ADSI_H
|
||||
#define _METERPRETER_SOURCE_EXTENSION_EXTAPI_ADSI_H
|
||||
|
||||
//DWORD request_adsi_user_enum(Remote *remote, Packet *packet);
|
||||
//DWORD request_adsi_computer_enum(Remote *remote, Packet *packet);
|
||||
DWORD request_adsi_domain_query(Remote *remote, Packet *packet);
|
||||
|
||||
#endif
|
||||
|
@ -13,12 +13,97 @@ extern "C" {
|
||||
|
||||
#pragma comment(lib, "Activeds.lib")
|
||||
|
||||
#define VALUE_SIZE 512
|
||||
#define VALUE_SIZE 1024
|
||||
#define PATH_SIZE 256
|
||||
|
||||
typedef BOOL (WINAPI *PCONVERTSIDTOSTRINGSID)(PSID pSid, LPSTR* pStr);
|
||||
|
||||
/*! @brief The GUID of the Directory Search COM object. */
|
||||
static const IID IID_IDirectorySearch = { 0x109BA8EC, 0x92F0, 0x11D0, { 0xA7, 0x90, 0x00, 0xC0, 0x4F, 0xD8, 0xD5, 0xA8 } };
|
||||
|
||||
static PCONVERTSIDTOSTRINGSID pConvertSidToStringSid = NULL;
|
||||
static HMODULE hAdvapi32 = NULL;
|
||||
|
||||
/*!
|
||||
* @brief Render a SID to a string.
|
||||
* @param pSid Pointer to the SID to render.
|
||||
* @param pStr Pointer to the variable that will receive the string. Free with `LocalFree`.
|
||||
* @returns Indication of success or failure.
|
||||
*/
|
||||
BOOL ConvertSidToStringSid(PSID pSid, LPSTR* pStr)
|
||||
{
|
||||
if (pConvertSidToStringSid == NULL)
|
||||
{
|
||||
if (hAdvapi32 == NULL)
|
||||
{
|
||||
hAdvapi32 = LoadLibraryA("Advapi32.dll");
|
||||
}
|
||||
|
||||
pConvertSidToStringSid = hAdvapi32 == NULL ? NULL : (PCONVERTSIDTOSTRINGSID)GetProcAddress(hAdvapi32, "ConvertSidToStringSidA");
|
||||
}
|
||||
|
||||
return pConvertSidToStringSid == NULL ? FALSE : pConvertSidToStringSid(pSid, pStr);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Render a byte array as a GUID string.
|
||||
* @param bytes Pointer to the GUID bytes.
|
||||
* @param buffer Pointer to the target buffer.
|
||||
* @param bufferSize size of the memory available in \c buffer.
|
||||
* @remark Assumes the caller knows what they're doing, and assumes that there are 16 bytes in the array.
|
||||
*/
|
||||
void guid_to_string(LPBYTE bytes, char* buffer, DWORD bufferSize)
|
||||
{
|
||||
sprintf_s(buffer, bufferSize, "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
|
||||
bytes[0], bytes[1], bytes[2], bytes[3],
|
||||
bytes[4], bytes[5], bytes[6], bytes[7],
|
||||
bytes[8], bytes[9], bytes[10], bytes[11],
|
||||
bytes[12], bytes[13], bytes[14], bytes[15]);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Render a byte array as a string.
|
||||
* @param bytes Pointer to the bytes.
|
||||
* @param count Number of bytes to write.
|
||||
* @param buffer Pointer to the target buffer.
|
||||
* @param bufferSize size of the memory available in \c buffer.
|
||||
* @param byteFormat optional per-byte format (defaults to \c %02x).
|
||||
* @param byteFormatMaxLen optional per-byte format max length (to make sure we allocated enough memory).
|
||||
* @param delim optional delimiter to render between bytes (defaults to \c -).
|
||||
* @remark Assumes the caller knows what they're doing, and assumes that there are 16 bytes in the array.
|
||||
*/
|
||||
char* bytes_to_string(LPBYTE bytes, DWORD count, char* byteFormat = "%02x", DWORD byteFormatMaxLen = 2, char* delim = "-")
|
||||
{
|
||||
dprintf("[EXTAPI ADSI] Stringifying a binary of %u bytes", count);
|
||||
|
||||
if (bytes == NULL || count == 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t delimLen = delim == NULL ? 0 : strlen(delim);
|
||||
size_t requiredSize = count * byteFormatMaxLen + (count - 1) * delimLen + 1;
|
||||
char* string = (char*)malloc(requiredSize);
|
||||
char* csr = string;
|
||||
|
||||
if (string)
|
||||
{
|
||||
for (DWORD i = 0; i < count; ++i)
|
||||
{
|
||||
if (i != 0 && delimLen > 0)
|
||||
{
|
||||
csr += sprintf_s(csr, delimLen + 1, "%s", delim);
|
||||
}
|
||||
|
||||
csr += sprintf_s(csr, byteFormatMaxLen + 1, byteFormat, bytes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI ADSI] Stringified a binary of %u bytes to: %s", count, string);
|
||||
|
||||
return string;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Perform a domain query via ADSI.
|
||||
* @param lpwDomain Name of the domain that is to be queried.
|
||||
@ -117,29 +202,224 @@ DWORD domain_query(LPCWSTR lpwDomain, LPWSTR lpwFilter, LPWSTR* lpwQueryCols,
|
||||
HRESULT hr = pDirSearch->GetColumn(hSearch, lpwQueryCols[dwIndex], &col);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
WCHAR* source = NULL;
|
||||
switch (col.dwADsType)
|
||||
{
|
||||
case ADSTYPE_LARGE_INTEGER:
|
||||
_i64toa_s(col.pADsValues->LargeInteger.QuadPart, valueTarget, VALUE_SIZE, 10);
|
||||
entries[dwIndex].header.length = lstrlenA(valueTarget) + 1;
|
||||
dprintf("[ADSI] Adding large int value %ul", (UINT)col.pADsValues->Integer);
|
||||
break;
|
||||
case ADSTYPE_INTEGER:
|
||||
_itoa_s((UINT)col.pADsValues->Integer, valueTarget, VALUE_SIZE, 10);
|
||||
entries[dwIndex].header.length = lstrlenA(valueTarget) + 1;
|
||||
dprintf("[ADSI] Adding int value %u", (UINT)col.pADsValues->Integer);
|
||||
break;
|
||||
default:
|
||||
WCHAR* source = col.dwADsType == ADSTYPE_CASE_IGNORE_STRING
|
||||
? col.pADsValues->CaseIgnoreString
|
||||
: col.pADsValues->CaseExactString;
|
||||
case ADSTYPE_LARGE_INTEGER:
|
||||
{
|
||||
_i64toa_s(col.pADsValues->LargeInteger.QuadPart, valueTarget, VALUE_SIZE, 10);
|
||||
dprintf("[ADSI] Adding large int value %ul", (UINT)col.pADsValues->Integer);
|
||||
break;
|
||||
}
|
||||
case ADSTYPE_INTEGER:
|
||||
{
|
||||
_itoa_s((UINT)col.pADsValues->Integer, valueTarget, VALUE_SIZE, 10);
|
||||
dprintf("[ADSI] Adding int value %u", (UINT)col.pADsValues->Integer);
|
||||
break;
|
||||
}
|
||||
case ADSTYPE_DN_STRING:
|
||||
{
|
||||
source = col.pADsValues->DNString;
|
||||
break;
|
||||
}
|
||||
case ADSTYPE_PRINTABLE_STRING:
|
||||
{
|
||||
source = col.pADsValues->PrintableString;
|
||||
break;
|
||||
}
|
||||
case ADSTYPE_NUMERIC_STRING:
|
||||
{
|
||||
source = col.pADsValues->NumericString;
|
||||
break;
|
||||
}
|
||||
case ADSTYPE_CASE_EXACT_STRING:
|
||||
{
|
||||
source = col.pADsValues->CaseExactString;
|
||||
break;
|
||||
}
|
||||
case ADSTYPE_CASE_IGNORE_STRING:
|
||||
{
|
||||
source = col.pADsValues->CaseIgnoreString;
|
||||
break;
|
||||
}
|
||||
case ADSTYPE_BOOLEAN:
|
||||
{
|
||||
source = col.pADsValues->Boolean == 0 ? L"False" : L"True";
|
||||
break;
|
||||
}
|
||||
case ADSTYPE_OCTET_STRING:
|
||||
{
|
||||
char* s = bytes_to_string(col.pADsValues->OctetString.lpValue, col.pADsValues->OctetString.dwLength);
|
||||
if (s)
|
||||
{
|
||||
strncpy_s(valueTarget, VALUE_SIZE, s, VALUE_SIZE - 1);
|
||||
free(s);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ADSTYPE_UTC_TIME:
|
||||
{
|
||||
SYSTEMTIME* pt = &col.pADsValues->UTCTime;
|
||||
sprintf_s(valueTarget, VALUE_SIZE, "%4u-%02u-%02u %02u:%02u:%02u.%03u",
|
||||
pt->wYear, pt->wMonth, pt->wDay, pt->wHour, pt->wMinute, pt->wSecond, pt->wMilliseconds);
|
||||
break;
|
||||
}
|
||||
case ADSTYPE_PROV_SPECIFIC:
|
||||
{
|
||||
char* s = bytes_to_string(col.pADsValues->ProviderSpecific.lpValue, col.pADsValues->ProviderSpecific.dwLength);
|
||||
if (s)
|
||||
{
|
||||
strncpy_s(valueTarget, VALUE_SIZE, s, VALUE_SIZE - 1);
|
||||
free(s);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ADSTYPE_OBJECT_CLASS:
|
||||
{
|
||||
source = col.pADsValues->ClassName;
|
||||
break;
|
||||
}
|
||||
case ADSTYPE_CASEIGNORE_LIST:
|
||||
{
|
||||
// list of strings, yay!
|
||||
char* prefix = "";
|
||||
PADS_CASEIGNORE_LIST list = col.pADsValues->pCaseIgnoreList;
|
||||
char* csr = valueTarget;
|
||||
size_t sizeLeft = VALUE_SIZE;
|
||||
|
||||
wcstombs_s(&charsConverted, valueTarget, VALUE_SIZE, source, VALUE_SIZE - 1);
|
||||
dprintf("[ADSI] Adding string %s", valueTarget);
|
||||
entries[dwIndex].header.length = lstrlenA(valueTarget) + 1;
|
||||
break;
|
||||
while (list != NULL && sizeLeft > 0)
|
||||
{
|
||||
int printed = sprintf_s(csr, sizeLeft, "%s%S", prefix, list->String);
|
||||
sizeLeft -= printed;
|
||||
csr += printed;
|
||||
prefix = ", ";
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ADSTYPE_PATH:
|
||||
{
|
||||
PADS_PATH path = col.pADsValues->pPath;
|
||||
sprintf_s(valueTarget, VALUE_SIZE, "Vol: %S, Path: %S, Type: %u", path->VolumeName, path->Path, path->Type);
|
||||
break;
|
||||
}
|
||||
case ADSTYPE_POSTALADDRESS:
|
||||
{
|
||||
PADS_POSTALADDRESS addr = col.pADsValues->pPostalAddress;
|
||||
char* prefix = "";
|
||||
PADS_CASEIGNORE_LIST list = col.pADsValues->pCaseIgnoreList;
|
||||
char* csr = valueTarget;
|
||||
size_t sizeLeft = VALUE_SIZE;
|
||||
|
||||
for (DWORD i = 0; i < sizeof(addr->PostalAddress) / sizeof(addr->PostalAddress[0]) && sizeLeft > 0; ++i)
|
||||
{
|
||||
if (!addr->PostalAddress[i] || lstrlenW(addr->PostalAddress[i]) == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
int printed = sprintf_s(csr, sizeLeft, "%s%S", prefix, addr->PostalAddress[i]);
|
||||
sizeLeft -= printed;
|
||||
csr += printed;
|
||||
prefix = ", ";
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ADSTYPE_TIMESTAMP:
|
||||
{
|
||||
ADS_TIMESTAMP* pts = &col.pADsValues->Timestamp;
|
||||
sprintf_s(valueTarget, VALUE_SIZE, "Event: %S, Sec: %u", pts->EventID, pts->WholeSeconds);
|
||||
break;
|
||||
}
|
||||
case ADSTYPE_BACKLINK:
|
||||
{
|
||||
ADS_BACKLINK* pbl = &col.pADsValues->BackLink;
|
||||
sprintf_s(valueTarget, VALUE_SIZE, "Name: %S, ID: %u", pbl->ObjectName, pbl->RemoteID);
|
||||
break;
|
||||
}
|
||||
case ADSTYPE_TYPEDNAME:
|
||||
{
|
||||
PADS_TYPEDNAME ptn = col.pADsValues->pTypedName;
|
||||
sprintf_s(valueTarget, VALUE_SIZE, "Interval: %u, Level: %u, Name: %S", ptn->Interval, ptn->Level, ptn->ObjectName);
|
||||
break;
|
||||
}
|
||||
case ADSTYPE_NETADDRESS:
|
||||
{
|
||||
PADS_NETADDRESS pna = col.pADsValues->pNetAddress;
|
||||
// IP address octects won't be bigger than 3 chars (given that we can only have 255 as a max value
|
||||
char* s = bytes_to_string(pna->Address, pna->AddressLength, "%u", 3, ".");
|
||||
if (s)
|
||||
{
|
||||
strncpy_s(valueTarget, VALUE_SIZE, s, VALUE_SIZE - 1);
|
||||
free(s);
|
||||
}
|
||||
dprintf("[ADSI] %u network address of %u bytes added", pna->AddressType, pna->AddressLength);
|
||||
break;
|
||||
}
|
||||
case ADSTYPE_EMAIL:
|
||||
{
|
||||
source = col.pADsValues->Email.Address;
|
||||
break;
|
||||
}
|
||||
case ADSTYPE_NT_SECURITY_DESCRIPTOR:
|
||||
{
|
||||
ADS_NT_SECURITY_DESCRIPTOR* psd = &col.pADsValues->SecurityDescriptor;
|
||||
char* s = NULL;
|
||||
if(ConvertSidToStringSid((PSID)psd->lpValue, &s))
|
||||
{
|
||||
dprintf("[EXTAPI ADSI] converted SID: %s", s);
|
||||
strncpy_s(valueTarget, VALUE_SIZE, s, VALUE_SIZE - 1);
|
||||
LocalFree(s);
|
||||
}
|
||||
else
|
||||
{
|
||||
s = bytes_to_string(psd->lpValue, psd->dwLength);
|
||||
if (s)
|
||||
{
|
||||
strncpy_s(valueTarget, VALUE_SIZE, s, VALUE_SIZE - 1);
|
||||
free(s);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ADSTYPE_DN_WITH_BINARY:
|
||||
{
|
||||
PADS_DN_WITH_BINARY pdb = col.pADsValues->pDNWithBinary;
|
||||
sprintf_s(valueTarget, VALUE_SIZE, "DN: %S, Value: %S", pdb->pszDNString);
|
||||
size_t charsPrinted = lstrlenA(valueTarget);
|
||||
char* s = bytes_to_string(pdb->lpBinaryValue, pdb->dwLength, "%u", 3, ".");
|
||||
if (s)
|
||||
{
|
||||
strncpy_s(valueTarget + charsPrinted, VALUE_SIZE, s, VALUE_SIZE - 1);
|
||||
free(s);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ADSTYPE_DN_WITH_STRING:
|
||||
{
|
||||
PADS_DN_WITH_STRING pds = col.pADsValues->pDNWithString;
|
||||
sprintf_s(valueTarget, VALUE_SIZE, "DN: %S, Value: %S", pds->pszDNString, pds->pszStringValue);
|
||||
break;
|
||||
}
|
||||
case ADSTYPE_FAXNUMBER:
|
||||
case ADSTYPE_REPLICAPOINTER:
|
||||
default:
|
||||
{
|
||||
// this is a string of some kind
|
||||
dprintf("[ADSI] Unhandled ADSI type %u (%x), adding unknown", col.dwADsType, col.dwADsType);
|
||||
sprintf_s(valueTarget, VALUE_SIZE, "(unhandled ADSI type %u)", col.dwADsType);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if source is now non-null it means a value was added to it,
|
||||
// so we can just do a conversion directly into the value target
|
||||
if (source != NULL)
|
||||
{
|
||||
wcstombs_s(&charsConverted, valueTarget, VALUE_SIZE, source, VALUE_SIZE - 1);
|
||||
dprintf("[ADSI] Adding string value %s", valueTarget);
|
||||
}
|
||||
|
||||
entries[dwIndex].header.length = lstrlenA(valueTarget) + 1;
|
||||
pDirSearch->FreeColumn(&col);
|
||||
}
|
||||
else
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*!
|
||||
* @file adsi_interface.h
|
||||
* @brief Declarations for functions that deal directly with ADSI
|
||||
* via the COM interfaces (hence the .cpp extension).
|
||||
* via the COM interface.
|
||||
*/
|
||||
#ifndef _METERPRETER_SOURCE_EXTENSION_EXTAPI_ADSI_INTERFACE_H
|
||||
#define _METERPRETER_SOURCE_EXTENSION_EXTAPI_ADSI_INTERFACE_H
|
||||
|
@ -339,47 +339,32 @@ VOID timestamp_to_string(SYSTEMTIME* pTime, char buffer[40])
|
||||
VOID dump_clipboard_capture(Packet* pResponse, ClipboardCapture* pCapture, BOOL bCaptureImageData)
|
||||
{
|
||||
ClipboardFile* pFile;
|
||||
Tlv entries[4];
|
||||
Packet* group = packet_create_group();
|
||||
TlvType groupType;
|
||||
Packet* file = NULL;
|
||||
char timestamp[40];
|
||||
|
||||
dprintf("[EXTAPI CLIPBOARD] Dumping clipboard capture");
|
||||
|
||||
memset(entries, 0, sizeof(entries));
|
||||
memset(timestamp, 0, sizeof(timestamp));
|
||||
|
||||
timestamp_to_string(&pCapture->stCaptureTime, timestamp);
|
||||
entries[0].header.type = TLV_TYPE_EXT_CLIPBOARD_TYPE_TIMESTAMP;
|
||||
entries[0].header.length = lstrlenA(timestamp) + 1;
|
||||
entries[0].buffer = (PUCHAR)timestamp;
|
||||
packet_add_tlv_string(group, TLV_TYPE_EXT_CLIPBOARD_TYPE_TIMESTAMP, timestamp);
|
||||
dprintf("[EXTAPI CLIPBOARD] Timestamp added: %s", timestamp);
|
||||
|
||||
switch (pCapture->captureType)
|
||||
{
|
||||
case CapText:
|
||||
dprintf("[EXTAPI CLIPBOARD] Dumping text %s", pCapture->lpText);
|
||||
entries[1].header.type = TLV_TYPE_EXT_CLIPBOARD_TYPE_TEXT_CONTENT;
|
||||
entries[1].buffer = (PUCHAR)(pCapture->lpText ? pCapture->lpText : "(null - clipboard was cleared)");
|
||||
entries[1].header.length = lstrlenA((char*)entries[1].buffer) + 1;
|
||||
|
||||
packet_add_tlv_group(pResponse, TLV_TYPE_EXT_CLIPBOARD_TYPE_TEXT, entries, 2);
|
||||
dprintf("[EXTAPI CLIPBOARD] Text added to packet");
|
||||
packet_add_tlv_string(group, TLV_TYPE_EXT_CLIPBOARD_TYPE_TEXT_CONTENT, (PUCHAR)(pCapture->lpText ? pCapture->lpText : "(null - clipboard was cleared)"));
|
||||
groupType = TLV_TYPE_EXT_CLIPBOARD_TYPE_TEXT;
|
||||
break;
|
||||
case CapImage:
|
||||
dprintf("[EXTAPI CLIPBOARD] Dumping image %ux%x", pCapture->lpImage->dwWidth, pCapture->lpImage->dwHeight);
|
||||
entries[1].header.type = TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG_DIMX;
|
||||
entries[1].header.length = sizeof(DWORD);
|
||||
entries[1].buffer = (PUCHAR)&pCapture->lpImage->dwWidth;
|
||||
|
||||
entries[2].header.type = TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG_DIMY;
|
||||
entries[2].header.length = sizeof(DWORD);
|
||||
entries[2].buffer = (PUCHAR)&pCapture->lpImage->dwHeight;
|
||||
|
||||
entries[3].header.type = TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG_DATA;
|
||||
entries[3].header.length = pCapture->lpImage->dwImageSize;
|
||||
entries[3].buffer = (PUCHAR)pCapture->lpImage->lpImageContent;
|
||||
|
||||
packet_add_tlv_group(pResponse, TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG, entries, bCaptureImageData && pCapture->lpImage->lpImageContent ? 4 : 3);
|
||||
dprintf("[EXTAPI CLIPBOARD] Image added to packet");
|
||||
packet_add_tlv_uint(group, TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG_DIMX, pCapture->lpImage->dwWidth);
|
||||
packet_add_tlv_uint(group, TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG_DIMY, pCapture->lpImage->dwHeight);
|
||||
packet_add_tlv_raw(group, TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG_DATA, pCapture->lpImage->lpImageContent, pCapture->lpImage->dwImageSize);
|
||||
groupType = TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG;
|
||||
break;
|
||||
case CapFiles:
|
||||
pFile = pCapture->lpFiles;
|
||||
@ -387,25 +372,25 @@ VOID dump_clipboard_capture(Packet* pResponse, ClipboardCapture* pCapture, BOOL
|
||||
while (pFile)
|
||||
{
|
||||
dprintf("[EXTAPI CLIPBOARD] Dumping file %p", pFile);
|
||||
file = packet_create_group();
|
||||
|
||||
dprintf("[EXTAPI CLIPBOARD] Adding path %s", pFile->lpPath);
|
||||
entries[1].header.type = TLV_TYPE_EXT_CLIPBOARD_TYPE_FILE_NAME;
|
||||
entries[1].header.length = lstrlenA(pFile->lpPath) + 1;
|
||||
entries[1].buffer = (PUCHAR)pFile->lpPath;
|
||||
packet_add_tlv_string(file, TLV_TYPE_EXT_CLIPBOARD_TYPE_FILE_NAME, pFile->lpPath);
|
||||
|
||||
dprintf("[EXTAPI CLIPBOARD] Adding size %llu", htonq(pFile->qwSize));
|
||||
entries[2].header.type = TLV_TYPE_EXT_CLIPBOARD_TYPE_FILE_SIZE;
|
||||
entries[2].header.length = sizeof(QWORD);
|
||||
entries[2].buffer = (PUCHAR)&pFile->qwSize;
|
||||
packet_add_tlv_qword(file, TLV_TYPE_EXT_CLIPBOARD_TYPE_FILE_SIZE, pFile->qwSize);
|
||||
|
||||
dprintf("[EXTAPI CLIPBOARD] Adding group");
|
||||
packet_add_tlv_group(pResponse, TLV_TYPE_EXT_CLIPBOARD_TYPE_FILE, entries, 3);
|
||||
packet_add_group(group, TLV_TYPE_EXT_CLIPBOARD_TYPE_FILE, file);
|
||||
|
||||
pFile = pFile->pNext;
|
||||
dprintf("[EXTAPI CLIPBOARD] Moving to next");
|
||||
}
|
||||
groupType = TLV_TYPE_EXT_CLIPBOARD_TYPE_FILES;
|
||||
break;
|
||||
}
|
||||
|
||||
packet_add_group(pResponse, groupType, group);
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -635,8 +620,8 @@ DWORD capture_clipboard(BOOL bCaptureImageData, ClipboardCapture** ppCapture)
|
||||
pCapture->captureType = CapImage;
|
||||
pCapture->lpImage = (ClipboardImage*)malloc(sizeof(ClipboardImage));
|
||||
memset(pCapture->lpImage, 0, sizeof(ClipboardImage));
|
||||
pCapture->lpImage->dwWidth = htonl(lpBI->bmiHeader.biWidth);
|
||||
pCapture->lpImage->dwHeight = htonl(lpBI->bmiHeader.biHeight);
|
||||
pCapture->lpImage->dwWidth = lpBI->bmiHeader.biWidth;
|
||||
pCapture->lpImage->dwHeight = lpBI->bmiHeader.biHeight;
|
||||
|
||||
// throw together a basic guess for this, it doesn't have to be exact.
|
||||
pCapture->dwSize = lpBI->bmiHeader.biWidth * lpBI->bmiHeader.biHeight * 4;
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include "service.h"
|
||||
#include "clipboard.h"
|
||||
#include "adsi.h"
|
||||
#include "wmi.h"
|
||||
|
||||
// this sets the delay load hook function, see DelayLoadMetSrv.h
|
||||
EnableDelayLoadMetSrv();
|
||||
@ -24,6 +25,7 @@ Command customCommands[] =
|
||||
COMMAND_REQ("extapi_window_enum", request_window_enum),
|
||||
COMMAND_REQ("extapi_service_enum", request_service_enum),
|
||||
COMMAND_REQ("extapi_service_query", request_service_query),
|
||||
COMMAND_REQ("extapi_service_control", request_service_control),
|
||||
COMMAND_REQ("extapi_clipboard_get_data", request_clipboard_get_data),
|
||||
COMMAND_REQ("extapi_clipboard_set_data", request_clipboard_set_data),
|
||||
COMMAND_REQ("extapi_clipboard_monitor_start", request_clipboard_monitor_start),
|
||||
@ -33,6 +35,7 @@ Command customCommands[] =
|
||||
COMMAND_REQ("extapi_clipboard_monitor_stop", request_clipboard_monitor_stop),
|
||||
COMMAND_REQ("extapi_clipboard_monitor_dump", request_clipboard_monitor_dump),
|
||||
COMMAND_REQ("extapi_adsi_domain_query", request_adsi_domain_query),
|
||||
COMMAND_REQ("extapi_wmi_query", request_wmi_query),
|
||||
COMMAND_TERMINATOR
|
||||
};
|
||||
|
||||
@ -48,7 +51,10 @@ DWORD __declspec(dllexport) InitServerExtension(Remote *remote)
|
||||
|
||||
command_register_all(customCommands);
|
||||
|
||||
return initialise_clipboard();
|
||||
initialise_clipboard();
|
||||
initialise_service();
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -29,6 +29,10 @@
|
||||
#define TLV_TYPE_EXT_SERVICE_QUERY_LOADORDERGROUP MAKE_CUSTOM_TLV(TLV_META_TYPE_STRING, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 24)
|
||||
#define TLV_TYPE_EXT_SERVICE_QUERY_INTERACTIVE MAKE_CUSTOM_TLV(TLV_META_TYPE_BOOL, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 25)
|
||||
#define TLV_TYPE_EXT_SERVICE_QUERY_DACL MAKE_CUSTOM_TLV(TLV_META_TYPE_STRING, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 26)
|
||||
#define TLV_TYPE_EXT_SERVICE_QUERY_STATUS MAKE_CUSTOM_TLV(TLV_META_TYPE_UINT, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 27)
|
||||
|
||||
#define TLV_TYPE_EXT_SERVICE_CTRL_NAME MAKE_CUSTOM_TLV(TLV_META_TYPE_STRING, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 28)
|
||||
#define TLV_TYPE_EXT_SERVICE_CTRL_OP MAKE_CUSTOM_TLV(TLV_META_TYPE_UINT, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 29)
|
||||
|
||||
#define TLV_TYPE_EXT_CLIPBOARD_DOWNLOAD MAKE_CUSTOM_TLV(TLV_META_TYPE_BOOL, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 35)
|
||||
|
||||
@ -40,6 +44,7 @@
|
||||
#define TLV_TYPE_EXT_CLIPBOARD_TYPE_FILE MAKE_CUSTOM_TLV(TLV_META_TYPE_GROUP, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 41)
|
||||
#define TLV_TYPE_EXT_CLIPBOARD_TYPE_FILE_NAME MAKE_CUSTOM_TLV(TLV_META_TYPE_STRING, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 42)
|
||||
#define TLV_TYPE_EXT_CLIPBOARD_TYPE_FILE_SIZE MAKE_CUSTOM_TLV(TLV_META_TYPE_QWORD, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 43)
|
||||
#define TLV_TYPE_EXT_CLIPBOARD_TYPE_FILES MAKE_CUSTOM_TLV(TLV_META_TYPE_GROUP, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 44)
|
||||
|
||||
#define TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG MAKE_CUSTOM_TLV(TLV_META_TYPE_GROUP, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 45)
|
||||
#define TLV_TYPE_EXT_CLIPBOARD_TYPE_IMAGE_JPG_DIMX MAKE_CUSTOM_TLV(TLV_META_TYPE_UINT, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 46)
|
||||
@ -59,4 +64,12 @@
|
||||
#define TLV_TYPE_EXT_ASDI_MAXRESULTS MAKE_CUSTOM_TLV(TLV_META_TYPE_UINT, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 60)
|
||||
#define TLV_TYPE_EXT_ASDI_PAGESIZE MAKE_CUSTOM_TLV(TLV_META_TYPE_UINT, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 61)
|
||||
|
||||
#define TLV_TYPE_EXT_WMI_DOMAIN MAKE_CUSTOM_TLV(TLV_META_TYPE_STRING, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 65)
|
||||
#define TLV_TYPE_EXT_WMI_QUERY MAKE_CUSTOM_TLV(TLV_META_TYPE_STRING, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 66)
|
||||
#define TLV_TYPE_EXT_WMI_FIELD MAKE_CUSTOM_TLV(TLV_META_TYPE_STRING, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 67)
|
||||
#define TLV_TYPE_EXT_WMI_VALUE MAKE_CUSTOM_TLV(TLV_META_TYPE_STRING, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 68)
|
||||
#define TLV_TYPE_EXT_WMI_FIELDS MAKE_CUSTOM_TLV(TLV_META_TYPE_GROUP, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 69)
|
||||
#define TLV_TYPE_EXT_WMI_VALUES MAKE_CUSTOM_TLV(TLV_META_TYPE_GROUP, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 70)
|
||||
#define TLV_TYPE_EXT_WMI_ERROR MAKE_CUSTOM_TLV(TLV_META_TYPE_STRING, TLV_TYPE_EXTENSION_EXTAPI, TLV_EXTENSIONS + 71)
|
||||
|
||||
#endif
|
||||
|
@ -8,10 +8,38 @@
|
||||
#ifdef _WIN32
|
||||
#include <Sddl.h>
|
||||
|
||||
/*! @brief The possible list of operations to perform on a service */
|
||||
typedef enum _ServiceOperation
|
||||
{
|
||||
ServOpStart = 1,
|
||||
ServOpPause = 2,
|
||||
ServOpResume = 3,
|
||||
ServOpStop = 4,
|
||||
ServOpRestart = 5
|
||||
} ServiceOperation;
|
||||
|
||||
HMODULE hAdvapi32 = NULL;
|
||||
|
||||
/*! @brief Typedef for the OpenSCManagerA function. */
|
||||
typedef SC_HANDLE(WINAPI * POPENSCMANAGERA)(LPCSTR lpMachineName, LPCSTR lpDatabaseName, DWORD dwDesiredAccess);
|
||||
static POPENSCMANAGERA pOpenSCManagerA = NULL;
|
||||
|
||||
/*! @brief Typedef for the CloseServiceHandle function. */
|
||||
typedef BOOL(WINAPI * PCLOSESERVICEHANDLE)(SC_HANDLE hSCObject);
|
||||
static PCLOSESERVICEHANDLE pCloseServiceHandle = NULL;
|
||||
|
||||
/*! @brief Typedef for the StartServiceA function. */
|
||||
typedef BOOL (WINAPI * PSTARTSERVICEA)(SC_HANDLE hService, DWORD dwNumServiceArgs, LPCTSTR *lpServiceArgVectors);
|
||||
static PSTARTSERVICEA pStartServiceA = NULL;
|
||||
|
||||
/*! @brief Typedef for the ControlService function. */
|
||||
typedef BOOL (WINAPI * PCONTROLSERVICE)(SC_HANDLE hService, DWORD dwControl, LPSERVICE_STATUS lpServiceStatus);
|
||||
static PCONTROLSERVICE pControlService = NULL;
|
||||
|
||||
/*! @brief Typedef for the QueryServiceStatus function. */
|
||||
typedef BOOL (WINAPI * PQUERYSERVICESTATUS)(SC_HANDLE hService, LPSERVICE_STATUS lpServiceStatus);
|
||||
static PQUERYSERVICESTATUS pQueryServiceStatus = NULL;
|
||||
|
||||
/*! @brief Typedef for the EnumServicesStatusExA function. */
|
||||
typedef BOOL(WINAPI * PENUMSERVICESSTATUSEXA)(
|
||||
SC_HANDLE hSCManager,
|
||||
@ -25,8 +53,12 @@ typedef BOOL(WINAPI * PENUMSERVICESSTATUSEXA)(
|
||||
LPDWORD lpResumeHandle,
|
||||
LPCSTR pszGroupName
|
||||
);
|
||||
static PENUMSERVICESSTATUSEXA pEnumServicesStatusExA = NULL;
|
||||
|
||||
/*! @brief Typedef for the OpenServiceA function. */
|
||||
typedef SC_HANDLE(WINAPI * POPENSERVICEA)(SC_HANDLE hSCManager, LPCSTR lpServiceName, DWORD dwDesiredAcces);
|
||||
static POPENSERVICEA pOpenServiceA = NULL;
|
||||
|
||||
/*! @brief Typedef for the QueryServiceObjectSecurity function. */
|
||||
typedef BOOL(WINAPI * PQUERYSERVICEOBJECTSECURITY)(
|
||||
SC_HANDLE hService,
|
||||
@ -35,6 +67,8 @@ typedef BOOL(WINAPI * PQUERYSERVICEOBJECTSECURITY)(
|
||||
DWORD cbBufSize,
|
||||
LPDWORD pcbBytesNeeded
|
||||
);
|
||||
static PQUERYSERVICEOBJECTSECURITY pQueryServiceObjectSecurity = NULL;
|
||||
|
||||
/*! @brief Typedef for the QueryServiceConfigA function. */
|
||||
typedef BOOL(WINAPI * PQUERYSERVICECONFIGA)(
|
||||
SC_HANDLE hService,
|
||||
@ -42,6 +76,8 @@ typedef BOOL(WINAPI * PQUERYSERVICECONFIGA)(
|
||||
DWORD dbBufSize,
|
||||
LPDWORD pcbBytesNeeded
|
||||
);
|
||||
static PQUERYSERVICECONFIGA pQueryServiceConfigA = NULL;
|
||||
|
||||
/*! @brief Typedef for the ConvertSecurityDescriptorToStringSecurityDescriptorA function. */
|
||||
typedef BOOL(WINAPI * PCSDTSSDA)(
|
||||
PSECURITY_DESCRIPTOR SecurityDescriptor,
|
||||
@ -50,15 +86,148 @@ typedef BOOL(WINAPI * PCSDTSSDA)(
|
||||
LPCSTR *StringSecurityDescriptor,
|
||||
PULONG StringSecurityDescriptorLen
|
||||
);
|
||||
static PCSDTSSDA pCSDTSSDA = NULL;
|
||||
|
||||
VOID add_enumerated_service(Packet *pResponse, LPCSTR cpName, LPCSTR cpDisplayName, DWORD dwProcessId, DWORD dwStatus, BOOL bInteractive);
|
||||
DWORD query_service(LPCSTR cpServiceName, Packet *pResponse);
|
||||
DWORD get_service_config(HMODULE hAdvapi32, SC_HANDLE scService, Packet *pResponse);
|
||||
DWORD get_service_dacl(HMODULE hAdvapi32, SC_HANDLE scService, Packet *pResponse);
|
||||
DWORD get_service_config(SC_HANDLE scService, Packet *pResponse);
|
||||
DWORD get_service_status(SC_HANDLE scService, Packet *pResponse);
|
||||
DWORD get_service_dacl(SC_HANDLE scService, Packet *pResponse);
|
||||
#endif
|
||||
|
||||
DWORD execute_service_task(LPCSTR lpServiceName, ServiceOperation eServiceOp, Packet *response);
|
||||
DWORD enumerate_services(Packet *response);
|
||||
|
||||
/*!
|
||||
* @brief Initialise the service part of the extended api.
|
||||
*/
|
||||
VOID initialise_service()
|
||||
{
|
||||
do
|
||||
{
|
||||
dprintf("[EXTAPI SERVICE] Loading advapi32.dll");
|
||||
if ((hAdvapi32 = LoadLibraryA("advapi32.dll")) == NULL)
|
||||
{
|
||||
dprintf("[EXTAPI SERVICE] Unable to load advapi32.dll");
|
||||
break;
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI SERVICE] Searching for OpenSCManagerA");
|
||||
if ((pOpenSCManagerA = (POPENSCMANAGERA)GetProcAddress(hAdvapi32, "OpenSCManagerA")) == NULL)
|
||||
{
|
||||
dprintf("[EXTAPI SERVICE] Unable to locate OpenSCManagerA in advapi32.dll");
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI SERVICE] Searching for CloseServiceHandle");
|
||||
if ((pCloseServiceHandle = (PCLOSESERVICEHANDLE)GetProcAddress(hAdvapi32, "CloseServiceHandle")) == NULL)
|
||||
{
|
||||
dprintf("[EXTAPI SERVICE] Unable to locate CloseServiceHandle in advapi32.dll. Continuing anyway.");
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI SERVICE] Searching for EnumServicesStatusExA");
|
||||
if ((pEnumServicesStatusExA = (PENUMSERVICESSTATUSEXA)GetProcAddress(hAdvapi32, "EnumServicesStatusExA")) == NULL)
|
||||
{
|
||||
dprintf("[EXTAPI SERVICE] Unable to locate EnumServicesStatusExA in advapi32.dll.");
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI SERVICE] Searching for CloseServiceHandle");
|
||||
if ((pCloseServiceHandle = (PCLOSESERVICEHANDLE)GetProcAddress(hAdvapi32, "CloseServiceHandle")) == NULL)
|
||||
{
|
||||
dprintf("[EXTAPI SERVICE] Unable to locate CloseServiceHandle in advapi32.dll. Continuing anyway.");
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI SERVICE] Searching for OpenServiceA");
|
||||
if ((pOpenServiceA = (POPENSERVICEA)GetProcAddress(hAdvapi32, "OpenServiceA")) == NULL)
|
||||
{
|
||||
dprintf("[EXTAPI SERVICE] Unable to locate OpenServiceA in advapi32.dll.");
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI SERVICE] Searching for QueryServiceConfigA");
|
||||
if ((pQueryServiceConfigA = (PQUERYSERVICECONFIGA)GetProcAddress(hAdvapi32, "QueryServiceConfigA")) == NULL)
|
||||
{
|
||||
dprintf("[EXTAPI SERVICE] Unable to locate QueryServiceConfigA in advapi32.dll.");
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI SERVICE] Searching for QueryServiceObjectSecurity");
|
||||
if ((pQueryServiceObjectSecurity = (PQUERYSERVICEOBJECTSECURITY)GetProcAddress(hAdvapi32, "QueryServiceObjectSecurity")) == NULL)
|
||||
{
|
||||
dprintf("[EXTAPI SERVICE] Unable to locate QueryServiceObjectSecurity in advapi32.dll.");
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI SERVICE] Searching for ConvertSecurityDescriptorToStringSecurityDescriptorA");
|
||||
if ((pCSDTSSDA = (PCSDTSSDA)GetProcAddress(hAdvapi32, "ConvertSecurityDescriptorToStringSecurityDescriptorA")) == NULL)
|
||||
{
|
||||
dprintf("[EXTAPI SERVICE] Unable to locate ConvertSecurityDescriptorToStringSecurityDescriptorA in advapi32.dll.");
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI SERVICE] Searching for StartServiceA");
|
||||
if ((pStartServiceA = (PSTARTSERVICEA)GetProcAddress(hAdvapi32, "StartServiceA")) == NULL)
|
||||
{
|
||||
dprintf("[EXTAPI SERVICE] Unable to locate StartServiceA in advapi32.dll.");
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI SERVICE] Searching for ControlService");
|
||||
if ((pControlService = (PCONTROLSERVICE)GetProcAddress(hAdvapi32, "ControlService")) == NULL)
|
||||
{
|
||||
dprintf("[EXTAPI SERVICE] Unable to locate ControlService in advapi32.dll.");
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI SERVICE] Searching for QueryServiceStatus");
|
||||
if ((pQueryServiceStatus = (PQUERYSERVICESTATUS)GetProcAddress(hAdvapi32, "QueryServiceStatus")) == NULL)
|
||||
{
|
||||
dprintf("[EXTAPI SERVICE] Unable to locate QueryServiceStatus in advapi32.dll.");
|
||||
}
|
||||
} while (0);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Handle the request for service control.
|
||||
* @param remote Pointer to the \c Remote making the request.
|
||||
* @param packet Pointer to the request \c Packet.
|
||||
* @returns Indication of sucess or failure.
|
||||
*/
|
||||
DWORD request_service_control(Remote *remote, Packet *packet)
|
||||
{
|
||||
LPSTR lpServiceName = NULL;
|
||||
ServiceOperation eServiceOp = 0;
|
||||
DWORD dwResult = ERROR_SUCCESS;
|
||||
Packet * response = packet_create_response(packet);
|
||||
|
||||
do
|
||||
{
|
||||
if (!response)
|
||||
{
|
||||
dprintf("[EXTAPI SERVICE] Unable to create response packet");
|
||||
dwResult = ERROR_OUTOFMEMORY;
|
||||
break;
|
||||
}
|
||||
|
||||
lpServiceName = packet_get_tlv_value_string(packet, TLV_TYPE_EXT_SERVICE_CTRL_NAME);
|
||||
if (!lpServiceName)
|
||||
{
|
||||
BREAK_WITH_ERROR("[EXTAPI SERVICE] Missing service name parameter", ERROR_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
eServiceOp = (ServiceOperation)packet_get_tlv_value_uint(packet, TLV_TYPE_EXT_SERVICE_CTRL_OP);
|
||||
if (eServiceOp == 0)
|
||||
{
|
||||
BREAK_WITH_ERROR("[EXTAPI SERVICE] Missing service operation parameter", ERROR_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI SERVICE] Executing service control task");
|
||||
dwResult = execute_service_task(lpServiceName, eServiceOp, response);
|
||||
|
||||
} while (0);
|
||||
|
||||
dprintf("[EXTAPI SERVICE] Transmitting response back to caller.");
|
||||
if (response)
|
||||
{
|
||||
packet_transmit_response(dwResult, remote, response);
|
||||
}
|
||||
|
||||
return dwResult;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Handle the request for service enumeration.
|
||||
* @param remote Pointer to the \c Remote making the request.
|
||||
@ -121,7 +290,7 @@ DWORD request_service_query(Remote *remote, Packet *packet)
|
||||
lpServiceName = packet_get_tlv_value_string(packet, TLV_TYPE_EXT_SERVICE_ENUM_NAME);
|
||||
if (!lpServiceName)
|
||||
{
|
||||
BREAK_WITH_ERROR("[EXTAPI SERVICE] Missing service name parameter", ERROR_BAD_ARGUMENTS);
|
||||
BREAK_WITH_ERROR("[EXTAPI SERVICE] Missing service name parameter", ERROR_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI SERVICE] Beginning service enumeration");
|
||||
@ -149,39 +318,18 @@ DWORD query_service(LPCSTR cpServiceName, Packet *pResponse)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
// currently we only support Windoze
|
||||
|
||||
DWORD dwResult = ERROR_SUCCESS;
|
||||
HMODULE hAdvapi32 = NULL;
|
||||
POPENSCMANAGERA pOpenSCManagerA = NULL;
|
||||
PCLOSESERVICEHANDLE pCloseServiceHandle = NULL;
|
||||
POPENSERVICEA pOpenServiceA = NULL;
|
||||
SC_HANDLE scManager = NULL;
|
||||
SC_HANDLE scService = NULL;
|
||||
|
||||
do
|
||||
{
|
||||
dprintf("[EXTAPI SERVICE] Loading advapi32.dll");
|
||||
if ((hAdvapi32 = LoadLibraryA("advapi32.dll")) == NULL)
|
||||
if (hAdvapi32 == NULL
|
||||
|| pOpenSCManagerA == NULL
|
||||
|| pCloseServiceHandle == NULL
|
||||
|| pOpenServiceA == NULL)
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI SERVICE] Unable to load advapi32.dll");
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI SERVICE] Searching for OpenSCManagerA");
|
||||
if ((pOpenSCManagerA = (POPENSCMANAGERA)GetProcAddress(hAdvapi32, "OpenSCManagerA")) == NULL)
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI SERVICE] Unable to locate OpenSCManagerA in advapi32.dll");
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI SERVICE] Searching for CloseServiceHandle");
|
||||
if ((pCloseServiceHandle = (PCLOSESERVICEHANDLE)GetProcAddress(hAdvapi32, "CloseServiceHandle")) == NULL)
|
||||
{
|
||||
dprintf("[EXTAPI SERVICE] Unable to locate CloseServiceHandle in advapi32.dll. Continuing anyway.");
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI SERVICE] Searching for OpenServiceA");
|
||||
if ((pOpenServiceA = (POPENSERVICEA)GetProcAddress(hAdvapi32, "OpenServiceA")) == NULL)
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI SERVICE] Unable to locate OpenServiceA in advapi32.dll.");
|
||||
BREAK_WITH_ERROR("[EXTAPI SERVICE] Unable to query services, required functions not found", ERROR_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI SERVICE] Opening the Service Control manager");
|
||||
@ -198,8 +346,9 @@ DWORD query_service(LPCSTR cpServiceName, Packet *pResponse)
|
||||
break;
|
||||
}
|
||||
|
||||
get_service_config(hAdvapi32, scService, pResponse);
|
||||
get_service_dacl(hAdvapi32, scService, pResponse);
|
||||
get_service_config(scService, pResponse);
|
||||
get_service_status(scService, pResponse);
|
||||
get_service_dacl(scService, pResponse);
|
||||
|
||||
} while (0);
|
||||
|
||||
@ -213,11 +362,6 @@ DWORD query_service(LPCSTR cpServiceName, Packet *pResponse)
|
||||
pCloseServiceHandle(scManager);
|
||||
}
|
||||
|
||||
if (hAdvapi32)
|
||||
{
|
||||
FreeLibrary(hAdvapi32);
|
||||
}
|
||||
|
||||
return dwResult;
|
||||
#else
|
||||
return ERROR_NOT_SUPPORTED;
|
||||
@ -236,10 +380,6 @@ DWORD enumerate_services(Packet *pResponse)
|
||||
// currently we only support Windoze
|
||||
|
||||
DWORD dwResult = ERROR_SUCCESS;
|
||||
HMODULE hAdvapi32 = NULL;
|
||||
POPENSCMANAGERA pOpenSCManagerA = NULL;
|
||||
PCLOSESERVICEHANDLE pCloseServiceHandle = NULL;
|
||||
PENUMSERVICESSTATUSEXA pEnumServicesStatusExA = NULL;
|
||||
SC_HANDLE scManager = NULL;
|
||||
ENUM_SERVICE_STATUS_PROCESSA* pSsInfo = NULL;
|
||||
DWORD dwBytesNeeded = 0;
|
||||
@ -250,28 +390,12 @@ DWORD enumerate_services(Packet *pResponse)
|
||||
|
||||
do
|
||||
{
|
||||
dprintf("[EXTAPI SERVICE] Loading advapi32.dll");
|
||||
if ((hAdvapi32 = LoadLibraryA("advapi32.dll")) == NULL)
|
||||
if (hAdvapi32 == NULL
|
||||
|| pOpenSCManagerA == NULL
|
||||
|| pCloseServiceHandle == NULL
|
||||
|| pEnumServicesStatusExA == NULL)
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI SERVICE] Unable to load advapi32.dll");
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI SERVICE] Searching for OpenSCManagerA");
|
||||
if ((pOpenSCManagerA = (POPENSCMANAGERA)GetProcAddress(hAdvapi32, "OpenSCManagerA")) == NULL)
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI SERVICE] Unable to locate OpenSCManagerA in advapi32.dll");
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI SERVICE] Searching for CloseServiceHandle");
|
||||
if ((pCloseServiceHandle = (PCLOSESERVICEHANDLE)GetProcAddress(hAdvapi32, "CloseServiceHandle")) == NULL)
|
||||
{
|
||||
dprintf("[EXTAPI SERVICE] Unable to locate CloseServiceHandle in advapi32.dll. Continuing anyway.");
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI SERVICE] Searching for EnumServicesStatusExA");
|
||||
if ((pEnumServicesStatusExA = (PENUMSERVICESSTATUSEXA)GetProcAddress(hAdvapi32, "EnumServicesStatusExA")) == NULL)
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI SERVICE] Unable to locate EnumServicesStatusExA in advapi32.dll.");
|
||||
BREAK_WITH_ERROR("[EXTAPI SERVICE] Unable to enumerate services, required functions not found", ERROR_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
// TODO: add support for other machine names so that this instance can query other machines on the network.
|
||||
@ -323,9 +447,163 @@ DWORD enumerate_services(Packet *pResponse)
|
||||
pCloseServiceHandle(scManager);
|
||||
}
|
||||
|
||||
if (hAdvapi32)
|
||||
return dwResult;
|
||||
#else
|
||||
return ERROR_NOT_SUPPORTED;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Perform the task/operation on a service.
|
||||
* @param cpServiceName Name of the serivce to perform the query on.
|
||||
* @param eServiceOp The operationg to perform on the service.
|
||||
* @param pRacket Pointer to the response \c Packet.
|
||||
* @returns Indication of sucess or failure.
|
||||
* @retval ERROR_SUCCESS Operation succeeded.
|
||||
*/
|
||||
DWORD execute_service_task(LPCSTR cpServiceName, ServiceOperation eServiceOp, Packet *pResponse)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
// currently we only support Windoze
|
||||
DWORD dwResult = ERROR_SUCCESS;
|
||||
DWORD dwOpenFlags = SC_MANAGER_CONNECT | GENERIC_READ | SERVICE_QUERY_STATUS;
|
||||
DWORD dwControlFlag = 0;
|
||||
DWORD dwTargetStatus = 0;
|
||||
SC_HANDLE scManager = NULL;
|
||||
SC_HANDLE scService = NULL;
|
||||
SERVICE_STATUS serviceStatus;
|
||||
|
||||
do
|
||||
{
|
||||
FreeLibrary(hAdvapi32);
|
||||
if (hAdvapi32 == NULL
|
||||
|| pOpenSCManagerA == NULL
|
||||
|| pStartServiceA == NULL
|
||||
|| pCloseServiceHandle == NULL
|
||||
|| pQueryServiceStatus == NULL
|
||||
|| pOpenServiceA == NULL)
|
||||
{
|
||||
BREAK_WITH_ERROR("[EXTAPI SERVICE] Unable to query services, required functions not found", ERROR_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI SERVICE] Opening the Service Control manager");
|
||||
if ((scManager = pOpenSCManagerA(NULL, SERVICES_ACTIVE_DATABASEA, SC_MANAGER_CONNECT | GENERIC_READ)) == NULL)
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI SERVICE] Unable to open the service control manager");
|
||||
}
|
||||
|
||||
switch (eServiceOp)
|
||||
{
|
||||
case ServOpStart:
|
||||
dwOpenFlags |= SERVICE_START;
|
||||
break;
|
||||
case ServOpStop:
|
||||
dwOpenFlags |= SERVICE_STOP;
|
||||
break;
|
||||
case ServOpPause:
|
||||
case ServOpResume:
|
||||
dwOpenFlags |= SERVICE_PAUSE_CONTINUE;
|
||||
break;
|
||||
case ServOpRestart:
|
||||
dwOpenFlags |= SERVICE_START | SERVICE_STOP;
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI SERVICE] Opening the Service: %s", cpServiceName);
|
||||
if ((scService = pOpenServiceA(scManager, cpServiceName, dwOpenFlags)) == NULL)
|
||||
{
|
||||
dwResult = GetLastError();
|
||||
dprintf("[EXTAPI SERVICE] Unable to open the service: %s (%u)", cpServiceName, dwResult);
|
||||
break;
|
||||
}
|
||||
|
||||
// let's get a clue as to what the service status is before we move on
|
||||
if (!pQueryServiceStatus(scService, &serviceStatus))
|
||||
{
|
||||
dwResult = GetLastError();
|
||||
dprintf("[EXTAPI SERVICE] Unable to query the service status: %s (%u)", cpServiceName, dwResult);
|
||||
break;
|
||||
}
|
||||
|
||||
dwResult = ERROR_SUCCESS;
|
||||
if (eServiceOp == ServOpStart)
|
||||
{
|
||||
// we can't try to start the service if it isn't stopped
|
||||
if (serviceStatus.dwCurrentState == SERVICE_STOPPED)
|
||||
{
|
||||
if (!pStartServiceA(scService, 0, NULL))
|
||||
{
|
||||
dwResult = GetLastError();
|
||||
dprintf("[EXTAPI SERVICE] Unable to start the service: %s (%u)", cpServiceName, dwResult);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if(serviceStatus.dwCurrentState != SERVICE_RUNNING)
|
||||
{
|
||||
dprintf("[EXTAPI SERVICE] Unable to start the service in its current state: %s %x", cpServiceName, serviceStatus.dwCurrentState);
|
||||
dwResult = ERROR_INVALID_OPERATION;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (eServiceOp)
|
||||
{
|
||||
case ServOpRestart:
|
||||
case ServOpStop:
|
||||
dwControlFlag = SERVICE_CONTROL_STOP;
|
||||
dwTargetStatus = SERVICE_STOPPED;
|
||||
break;
|
||||
case ServOpPause:
|
||||
dwControlFlag = SERVICE_CONTROL_PAUSE;
|
||||
dwTargetStatus = SERVICE_PAUSED;
|
||||
break;
|
||||
case ServOpResume:
|
||||
dwControlFlag = SERVICE_CONTROL_CONTINUE;
|
||||
dwTargetStatus = SERVICE_RUNNING;
|
||||
break;
|
||||
}
|
||||
|
||||
dwResult = ERROR_SUCCESS;
|
||||
|
||||
if (serviceStatus.dwCurrentState == dwTargetStatus)
|
||||
{
|
||||
dprintf("[EXTAPI SERVICE] Service already in target state: %u on %s (%u)", eServiceOp, cpServiceName, dwResult);
|
||||
}
|
||||
else if (!pControlService(scService, dwControlFlag, &serviceStatus))
|
||||
{
|
||||
dwResult = GetLastError();
|
||||
dprintf("[EXTAPI SERVICE] Unable to control the service: %u on %s (%u)", eServiceOp, cpServiceName, dwResult);
|
||||
break;
|
||||
}
|
||||
|
||||
if (eServiceOp == ServOpRestart)
|
||||
{
|
||||
// At this point the service should either be stopped already or it will be stopping.
|
||||
// We have to wait until the service has stopped before we attempt to restart.
|
||||
do
|
||||
{
|
||||
Sleep(500);
|
||||
pQueryServiceStatus(scService, &serviceStatus);
|
||||
} while (serviceStatus.dwCurrentState != SERVICE_STOPPED);
|
||||
|
||||
// next we try to kick it off again
|
||||
if (!pStartServiceA(scService, 0, NULL))
|
||||
{
|
||||
dwResult = GetLastError();
|
||||
dprintf("[EXTAPI SERVICE] Unable to start the service: %s (%u)", cpServiceName, dwResult);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} while (0);
|
||||
|
||||
if (scService && pCloseServiceHandle)
|
||||
{
|
||||
pCloseServiceHandle(scService);
|
||||
}
|
||||
|
||||
if (scManager && pCloseServiceHandle)
|
||||
{
|
||||
pCloseServiceHandle(scManager);
|
||||
}
|
||||
|
||||
return dwResult;
|
||||
@ -381,25 +659,22 @@ VOID add_enumerated_service(Packet *pResponse, LPCSTR cpName, LPCSTR cpDisplayNa
|
||||
/*!
|
||||
* @brief Query the configuration of the given service.
|
||||
* @details On successful query the results of the query are added to the response.
|
||||
* @param hAdvapi32 Handle to the advapi32.dll.
|
||||
* @param scService Service handle referencing the service to query.
|
||||
* @param pResponse Pointer to the response \c Packet to add the result to.
|
||||
* @returns Indication of success or failure.
|
||||
* @retval ERROR_SUCCESS The service configuration query succeeded.
|
||||
*/
|
||||
DWORD get_service_config(HMODULE hAdvapi32, SC_HANDLE scService, Packet *pResponse)
|
||||
DWORD get_service_config(SC_HANDLE scService, Packet *pResponse)
|
||||
{
|
||||
DWORD dwResult = ERROR_SUCCESS;
|
||||
PQUERYSERVICECONFIGA pQueryServiceConfigA = NULL;
|
||||
LPQUERY_SERVICE_CONFIGA lpServiceConfig = NULL;
|
||||
DWORD cbBytesNeeded = 0;
|
||||
|
||||
do
|
||||
{
|
||||
dprintf("[EXTAPI SERVICE] Searching for QueryServiceConfigA");
|
||||
if ((pQueryServiceConfigA = (PQUERYSERVICECONFIGA)GetProcAddress(hAdvapi32, "QueryServiceConfigA")) == NULL)
|
||||
if (pQueryServiceConfigA == NULL)
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI SERVICE] Unable to locate QueryServiceConfigA in advapi32.dll.");
|
||||
BREAK_WITH_ERROR("[EXTAPI SERVICE] Unable to enumerate services, required functions not found", ERROR_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
if (pQueryServiceConfigA(scService, NULL, 0, &cbBytesNeeded))
|
||||
@ -440,36 +715,61 @@ DWORD get_service_config(HMODULE hAdvapi32, SC_HANDLE scService, Packet *pRespon
|
||||
return dwResult;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Query the status of a given service handle.
|
||||
* @details On successful querying the status is added to the response.
|
||||
* @param scService Service handle referencing the service to query.
|
||||
* @param pResponse Pointer to the response \c Packet to add the result to.
|
||||
* @returns Indication of success or failure.
|
||||
* @retval ERROR_SUCCESS The service status query succeeded.
|
||||
*/
|
||||
DWORD get_service_status(SC_HANDLE scService, Packet *pResponse)
|
||||
{
|
||||
DWORD dwResult = ERROR_SUCCESS;
|
||||
SERVICE_STATUS serviceStatus;
|
||||
|
||||
do
|
||||
{
|
||||
if (pQueryServiceStatus == NULL)
|
||||
{
|
||||
BREAK_WITH_ERROR("[EXTAPI SERVICE] Unable to query service status, required functions not found", ERROR_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
// let's get a clue as to what the service status is before we move on
|
||||
if (!pQueryServiceStatus(scService, &serviceStatus))
|
||||
{
|
||||
dwResult = GetLastError();
|
||||
dprintf("[EXTAPI SERVICE] Unable to query the service status: %u", dwResult);
|
||||
break;
|
||||
}
|
||||
|
||||
packet_add_tlv_uint(pResponse, TLV_TYPE_EXT_SERVICE_QUERY_STATUS, serviceStatus.dwCurrentState);
|
||||
|
||||
} while (0);
|
||||
|
||||
return dwResult;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Get the DACL of the specified service.
|
||||
* @details On successful query the DACL string is added to the response.
|
||||
* @param hAdvapi32 Handle to the advapi32.dll.
|
||||
* @param scService Service handle referencing the service to query.
|
||||
* @param pResponse Pointer to the response \c Packet to add the result to.
|
||||
* @returns Indication of success or failure.
|
||||
* @retval ERROR_SUCCESS The service configuration query succeeded.
|
||||
*/
|
||||
DWORD get_service_dacl(HMODULE hAdvapi32, SC_HANDLE scService, Packet *pResponse)
|
||||
DWORD get_service_dacl(SC_HANDLE scService, Packet *pResponse)
|
||||
{
|
||||
DWORD dwResult = ERROR_SUCCESS;
|
||||
DWORD dwBytesNeeded = 0;
|
||||
PQUERYSERVICEOBJECTSECURITY pQueryServiceObjectSecurity = NULL;
|
||||
PCSDTSSDA pCSDTSSDA = NULL;
|
||||
PSECURITY_DESCRIPTOR pSecurityDescriptor = NULL;
|
||||
LPSTR lpDaclString;
|
||||
|
||||
do
|
||||
{
|
||||
dprintf("[EXTAPI SERVICE] Searching for QueryServiceObjectSecurity");
|
||||
if ((pQueryServiceObjectSecurity = (PQUERYSERVICEOBJECTSECURITY)GetProcAddress(hAdvapi32, "QueryServiceObjectSecurity")) == NULL)
|
||||
if (pQueryServiceObjectSecurity == NULL || pCSDTSSDA == NULL)
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI SERVICE] Unable to locate QueryServiceObjectSecurity in advapi32.dll.");
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI SERVICE] Searching for ConvertSecurityDescriptorToStringSecurityDescriptorA");
|
||||
if ((pCSDTSSDA = (PCSDTSSDA)GetProcAddress(hAdvapi32, "ConvertSecurityDescriptorToStringSecurityDescriptorA")) == NULL)
|
||||
{
|
||||
BREAK_ON_ERROR("[EXTAPI SERVICE] Unable to locate ConvertSecurityDescriptorToStringSecurityDescriptorA in advapi32.dll.");
|
||||
BREAK_WITH_ERROR("[EXTAPI SERVICE] Unable to get service dacl, required functions not found", ERROR_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
if (pQueryServiceObjectSecurity(scService, DACL_SECURITY_INFORMATION, (PSECURITY_DESCRIPTOR)&pSecurityDescriptor, 0, &dwBytesNeeded))
|
||||
|
@ -5,7 +5,9 @@
|
||||
#ifndef _METERPRETER_SOURCE_EXTENSION_EXTAPI_SERVICE_H
|
||||
#define _METERPRETER_SOURCE_EXTENSION_EXTAPI_SERVICE_H
|
||||
|
||||
VOID initialise_service();
|
||||
DWORD request_service_enum(Remote *remote, Packet *packet);
|
||||
DWORD request_service_query(Remote *remote, Packet *packet);
|
||||
DWORD request_service_control(Remote *remote, Packet *packet);
|
||||
|
||||
#endif
|
||||
|
78
c/meterpreter/source/extensions/extapi/wmi.c
Normal file
78
c/meterpreter/source/extensions/extapi/wmi.c
Normal file
@ -0,0 +1,78 @@
|
||||
/*!
|
||||
* @file wmi.c
|
||||
* @brief Definitions for WMI request handling functionality.
|
||||
*/
|
||||
#include "extapi.h"
|
||||
#include "wshelpers.h"
|
||||
#include "wmi.h"
|
||||
#include "wmi_interface.h"
|
||||
|
||||
/*!
|
||||
* @brief Execute a WMI query.
|
||||
* @param remote Pointer to the \c Remote instance.
|
||||
* @param packet Pointer to the incoming \c Packet instance.
|
||||
* @returns Indication of success or failure.
|
||||
* @remark Real error codes are returned to the caller via a response packet.
|
||||
*/
|
||||
DWORD request_wmi_query(Remote *remote, Packet *packet)
|
||||
{
|
||||
DWORD dwResult = ERROR_SUCCESS;
|
||||
LPSTR lpValue = NULL;
|
||||
LPWSTR lpwRoot = NULL;
|
||||
LPWSTR lpwQuery = NULL;
|
||||
Packet * response = packet_create_response(packet);
|
||||
|
||||
do
|
||||
{
|
||||
if (!response)
|
||||
{
|
||||
BREAK_WITH_ERROR("[EXTAPI WMI] Unable to create response packet", ERROR_OUTOFMEMORY);
|
||||
}
|
||||
|
||||
lpValue = packet_get_tlv_value_string(packet, TLV_TYPE_EXT_WMI_DOMAIN);
|
||||
|
||||
if (!lpValue)
|
||||
{
|
||||
lpValue = "root\\CIMV2";
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI WMI] Domain: %s", lpValue);
|
||||
dwResult = to_wide_string(lpValue, &lpwRoot);
|
||||
if (dwResult != ERROR_SUCCESS)
|
||||
{
|
||||
dprintf("[EXTAPI WMI] Failed to get Domain");
|
||||
break;
|
||||
}
|
||||
|
||||
lpValue = packet_get_tlv_value_string(packet, TLV_TYPE_EXT_WMI_QUERY);
|
||||
dprintf("[EXTAPI WMI] Query: %s", lpValue);
|
||||
dwResult = to_wide_string(lpValue, &lpwQuery);
|
||||
if (dwResult != ERROR_SUCCESS)
|
||||
{
|
||||
dprintf("[EXTAPI WMI] Failed to get Query");
|
||||
break;
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI WMI] Beginning WMI query enumeration");
|
||||
dwResult = wmi_query(lpwRoot, lpwQuery, response);
|
||||
dprintf("[EXTAPI WMI] Result of processing: %u (0x%x)", dwResult, dwResult);
|
||||
} while (0);
|
||||
|
||||
if (lpwQuery)
|
||||
{
|
||||
free(lpwQuery);
|
||||
}
|
||||
|
||||
if (lpwRoot)
|
||||
{
|
||||
free(lpwRoot);
|
||||
}
|
||||
|
||||
dprintf("[EXTAPI WMI] Transmitting response back to caller.");
|
||||
if (response)
|
||||
{
|
||||
packet_transmit_response(dwResult, remote, response);
|
||||
}
|
||||
|
||||
return dwResult;
|
||||
}
|
10
c/meterpreter/source/extensions/extapi/wmi.h
Normal file
10
c/meterpreter/source/extensions/extapi/wmi.h
Normal file
@ -0,0 +1,10 @@
|
||||
/*!
|
||||
* @file wmi.h
|
||||
* @brief Declarations for WMI request handlers.
|
||||
*/
|
||||
#ifndef _METERPRETER_SOURCE_EXTENSION_EXTAPI_WMI_H
|
||||
#define _METERPRETER_SOURCE_EXTENSION_EXTAPI_WMI_H
|
||||
|
||||
DWORD request_wmi_query(Remote *remote, Packet *packet);
|
||||
|
||||
#endif
|
454
c/meterpreter/source/extensions/extapi/wmi_interface.cpp
Normal file
454
c/meterpreter/source/extensions/extapi/wmi_interface.cpp
Normal file
@ -0,0 +1,454 @@
|
||||
/*!
|
||||
* @file wmi_interface.h
|
||||
* @brief Declarations for functions that deal directly with WMI
|
||||
* via the COM interfaces (hence the .cpp extension).
|
||||
*/
|
||||
extern "C" {
|
||||
#include "extapi.h"
|
||||
#include <inttypes.h>
|
||||
#include "wmi_interface.h"
|
||||
}
|
||||
#include <WbemCli.h>
|
||||
#include <comutil.h>
|
||||
#include <comdef.h>
|
||||
|
||||
#pragma comment(lib, "wbemuuid.lib")
|
||||
#pragma comment(lib, "comsuppw.lib")
|
||||
|
||||
#define FIELD_SIZE 1024
|
||||
#define ENUM_TIMEOUT 5000
|
||||
|
||||
/*! The number of fields to ignore at the start of the query, which we aren't interested in.
|
||||
* For some reason there's one more system field in x64 than there is in x86. */
|
||||
#ifdef _WIN64
|
||||
#define SYSTEM_FIELD_COUNT 9
|
||||
#else
|
||||
#define SYSTEM_FIELD_COUNT 8
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* @brief Convert a variant type to a string and write it to the given buffer.
|
||||
* @param v The variant to convert.
|
||||
* @param buffer Pointer to the buffer to write the value to.
|
||||
* @param bufferSize size of the buffer.
|
||||
* @returns Pointer to the next location in the buffer.
|
||||
* @remarks This attempts to "flatten" a variant, including array types. The implementation is
|
||||
* not 100% complete, but is good enough for the sake of this requirement. Only arrays
|
||||
* of BSTR are currenty supported, more types can be added later if needed. Arbitrary
|
||||
* array depth has been attempted, but no tests have yet found a nested array in the
|
||||
* result set. There's probably bugs in that bit.
|
||||
*/
|
||||
char* variant_to_string(_variant_t& v, char* buffer, DWORD bufferSize)
|
||||
{
|
||||
dprintf("[WMI] preparing to parse variant of type %u (%x), buffer size %u", v.vt, v.vt, bufferSize);
|
||||
|
||||
switch (v.vt)
|
||||
{
|
||||
case VT_EMPTY:
|
||||
strncpy_s(buffer, bufferSize, "(EMPTY)", bufferSize - 1);
|
||||
break;
|
||||
case VT_NULL:
|
||||
strncpy_s(buffer, bufferSize, "(NULL)", bufferSize - 1);
|
||||
break;
|
||||
case VT_BOOL:
|
||||
strncpy_s(buffer, bufferSize, v.boolVal == VARIANT_TRUE ? "true" : "false", bufferSize - 1);
|
||||
break;
|
||||
case VT_I1:
|
||||
_snprintf_s(buffer, bufferSize, bufferSize - 1, "%"PRId8, (CHAR)v);
|
||||
break;
|
||||
case VT_I2:
|
||||
_snprintf_s(buffer, bufferSize, bufferSize - 1, "%"PRId16, (SHORT)v);
|
||||
break;
|
||||
case VT_INT:
|
||||
case VT_I4:
|
||||
_snprintf_s(buffer, bufferSize, bufferSize - 1, "%"PRId32, (INT)v);
|
||||
break;
|
||||
case VT_INT_PTR:
|
||||
case VT_I8:
|
||||
_snprintf_s(buffer, bufferSize, bufferSize - 1, "%"PRId64, (INT_PTR)v);
|
||||
break;
|
||||
case VT_UI1:
|
||||
_snprintf_s(buffer, bufferSize, bufferSize - 1, "%"PRIu8, (BYTE)v);
|
||||
break;
|
||||
case VT_UI2:
|
||||
_snprintf_s(buffer, bufferSize, bufferSize - 1, "%"PRIu16, (SHORT)v);
|
||||
break;
|
||||
case VT_UINT:
|
||||
case VT_UI4:
|
||||
_snprintf_s(buffer, bufferSize, bufferSize - 1, "%"PRIu32, (UINT)v);
|
||||
break;
|
||||
case VT_UINT_PTR:
|
||||
case VT_UI8:
|
||||
_snprintf_s(buffer, bufferSize, bufferSize - 1, "%"PRIu64, (UINT_PTR)v);
|
||||
break;
|
||||
case VT_BSTR:
|
||||
case VT_LPSTR:
|
||||
case VT_LPWSTR:
|
||||
// not sure if this is correct
|
||||
strncpy_s(buffer, bufferSize, (char*)(_bstr_t)v.bstrVal, bufferSize - 1);
|
||||
break;
|
||||
// TODO more types, such as floats, dates, etc.
|
||||
default:
|
||||
if ((v.vt & VT_ARRAY) == VT_ARRAY)
|
||||
{
|
||||
// nested array type, great.
|
||||
dprintf("[WMI] array type found!");
|
||||
LPSAFEARRAY array = v.parray;
|
||||
HRESULT hResult;
|
||||
|
||||
if (FAILED(hResult = SafeArrayLock(array)))
|
||||
{
|
||||
dprintf("[WMI] Failed to get array dimension: %x", hResult);
|
||||
break;
|
||||
}
|
||||
dprintf("[WMI] Field name array locked.");
|
||||
|
||||
LONG* indices = NULL;
|
||||
LONG* bounds = NULL;
|
||||
do
|
||||
{
|
||||
VARTYPE varType;
|
||||
SafeArrayGetVartype(array, &varType);
|
||||
dprintf("[WMI] Array type %u (%x)", (ULONG)varType, (ULONG)varType);
|
||||
dprintf("[WMI] Array dimensions: %u", SafeArrayGetDim(array));
|
||||
|
||||
LONG iterations = 1;
|
||||
LONG dim = SafeArrayGetDim(array);
|
||||
indices = (LONG*)malloc(dim * sizeof(LONG));
|
||||
bounds = (LONG*)malloc(dim * sizeof(LONG) * 2);
|
||||
memset(indices, 0, dim * sizeof(LONG));
|
||||
memset(bounds, 0, dim * sizeof(LONG) * 2);
|
||||
|
||||
for (LONG i = 0; i < dim; ++i)
|
||||
{
|
||||
LONG* lBound = bounds + i * 2;
|
||||
LONG* uBound = lBound + 1;
|
||||
if (FAILED(hResult = SafeArrayGetLBound(array, i + 1, lBound))
|
||||
|| FAILED(hResult = SafeArrayGetUBound(array, i + 1, uBound)))
|
||||
{
|
||||
dprintf("[WMI] Failed to get array dimensions: %x", hResult);
|
||||
break;
|
||||
}
|
||||
dprintf("[WMI] Array bounds: %u to %u", *lBound, *uBound);
|
||||
|
||||
iterations *= *uBound - *lBound;
|
||||
indices[i] = *lBound;
|
||||
}
|
||||
dprintf("[WMI] Array requires %u iterations", iterations);
|
||||
|
||||
// we're going to wrap our array elements in brackets, and separate with pipes
|
||||
// because we need some kind of array visualisation and this is the best I could
|
||||
// come up with at this time of night. Each dimension nests in a new set of brackets
|
||||
while (iterations-- > 0)
|
||||
{
|
||||
for (LONG i = 0; i < dim; ++i)
|
||||
{
|
||||
if (indices[i] == 0)
|
||||
{
|
||||
// save space for the closing bracket as well
|
||||
bufferSize -= 2;
|
||||
*buffer++ = '{';
|
||||
dprintf("[WMI] opening bracket for dimension %u", i);
|
||||
}
|
||||
else if(*(buffer - 1) != '|')
|
||||
{
|
||||
--bufferSize;
|
||||
*buffer++ = '|';
|
||||
}
|
||||
}
|
||||
|
||||
dprintf("[WMI] extracting value for iteration %u", iterations);
|
||||
switch (varType)
|
||||
{
|
||||
case VT_BSTR:
|
||||
BSTR val;
|
||||
if (SUCCEEDED(SafeArrayGetElement(array, indices, (void*)&val)))
|
||||
{
|
||||
dprintf("[WMI] Value extracted for iteration %u", iterations);
|
||||
char* newBuf = variant_to_string(_variant_t(val), buffer, bufferSize);
|
||||
bufferSize -= (LONG)(newBuf - buffer + 1);
|
||||
buffer = newBuf;
|
||||
dprintf("[WMI] Value added", iterations);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
dprintf("[WMI] Unsupported nested array type %u", (LONG)varType);
|
||||
break;
|
||||
}
|
||||
|
||||
++indices[dim - 1];
|
||||
for (LONG i = dim - 1; i >= 0; --i)
|
||||
{
|
||||
if (indices[i] == bounds[i * 2 + 1])
|
||||
{
|
||||
dprintf("[WMI] closing bracket for dimension %u", i);
|
||||
*buffer++ = '}';
|
||||
indices[i] = bounds[i * 2];
|
||||
if (i > 0)
|
||||
{
|
||||
++indices[i - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (0);
|
||||
|
||||
if (indices)
|
||||
{
|
||||
free(indices);
|
||||
}
|
||||
if (bounds)
|
||||
{
|
||||
free(bounds);
|
||||
}
|
||||
|
||||
SafeArrayUnlock(array);
|
||||
}
|
||||
else
|
||||
{
|
||||
dprintf("[WMI] Unhandled type: %u (%x)", v.vt, v.vt);
|
||||
}
|
||||
// ignore the buffer for other types
|
||||
break;
|
||||
}
|
||||
|
||||
// return wherever we go to.
|
||||
return buffer + strlen(buffer);
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Perform a WMI query.
|
||||
* @param lpwRoot Name of the root object that is to be queried against.
|
||||
* @param lpwQuery The filter to use when reading objects (LDAP style).
|
||||
* @param response The response \c Packet to add the results to.
|
||||
*/
|
||||
DWORD wmi_query(LPCWSTR lpwRoot, LPWSTR lpwQuery, Packet* response)
|
||||
{
|
||||
HRESULT hResult;
|
||||
|
||||
dprintf("[WMI] Initialising COM");
|
||||
if ((hResult = CoInitializeEx(NULL, COINIT_MULTITHREADED)) == S_OK)
|
||||
{
|
||||
dprintf("[WMI] COM initialised");
|
||||
IWbemLocator* pLocator = NULL;
|
||||
IWbemServices* pServices = NULL;
|
||||
IEnumWbemClassObject* pEnumerator = NULL;
|
||||
IWbemClassObject* pSuperClass = NULL;
|
||||
IWbemClassObject* pObj = NULL;
|
||||
Tlv* valueTlvs = NULL;
|
||||
char* values = NULL;
|
||||
VARIANT** fields = NULL;
|
||||
|
||||
do
|
||||
{
|
||||
if (FAILED(hResult = CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, 0)))
|
||||
{
|
||||
dprintf("[WMI] Failed to initialize security: %x", hResult);
|
||||
break;
|
||||
}
|
||||
dprintf("[WMI] Security initialised");
|
||||
|
||||
if (FAILED(hResult = CoCreateInstance(CLSID_WbemLocator, NULL, CLSCTX_ALL, IID_PPV_ARGS(&pLocator))))
|
||||
{
|
||||
dprintf("[WMI] Failed to create WbemLocator: %x", hResult);
|
||||
break;
|
||||
}
|
||||
dprintf("[WMI] WbemLocator created.");
|
||||
|
||||
if (FAILED(hResult = pLocator->ConnectServer(_bstr_t(lpwRoot), NULL, NULL, NULL, WBEM_FLAG_CONNECT_USE_MAX_WAIT, NULL, NULL, &pServices)))
|
||||
{
|
||||
dprintf("[WMI] Failed to create WbemServices at %S: %x", lpwRoot, hResult);
|
||||
break;
|
||||
}
|
||||
dprintf("[WMI] WbemServices created.");
|
||||
|
||||
if (FAILED(hResult = pServices->ExecQuery(L"WQL", lpwQuery, WBEM_FLAG_FORWARD_ONLY, NULL, &pEnumerator)))
|
||||
{
|
||||
dprintf("[WMI] Failed to create Enumerator for query %S: %x", lpwQuery, hResult);
|
||||
break;
|
||||
}
|
||||
dprintf("[WMI] Enumerated created.");
|
||||
|
||||
ULONG numFound;
|
||||
if (FAILED(hResult = pEnumerator->Next(ENUM_TIMEOUT, 1, &pObj, &numFound)))
|
||||
{
|
||||
dprintf("[WMI] Failed to get the first query element: %x", lpwQuery, hResult);
|
||||
break;
|
||||
}
|
||||
dprintf("[WMI] First result read. hr=%x p=%p", hResult, pObj);
|
||||
|
||||
if (hResult == WBEM_S_FALSE)
|
||||
{
|
||||
// this is not an error
|
||||
dprintf("[WMI] No results found!");
|
||||
break;
|
||||
}
|
||||
|
||||
// get the names of the fields out of the first object before doing anything else.
|
||||
LPSAFEARRAY pFieldArray = NULL;
|
||||
if (FAILED(hResult = pObj->GetNames(NULL, WBEM_FLAG_ALWAYS, NULL, &pFieldArray)))
|
||||
{
|
||||
dprintf("[WMI] Failed to get field names: %x", hResult);
|
||||
break;
|
||||
}
|
||||
dprintf("[WMI] Field Names extracted. hr=%x p=%p", hResult, pFieldArray);
|
||||
|
||||
// lock the array
|
||||
if (FAILED(hResult = SafeArrayLock(pFieldArray)))
|
||||
{
|
||||
dprintf("[WMI] Failed to get array dimension: %x", hResult);
|
||||
break;
|
||||
}
|
||||
dprintf("[WMI] Field name array locked.");
|
||||
|
||||
do
|
||||
{
|
||||
dprintf("[WMI] Array dimensions: %u", SafeArrayGetDim(pFieldArray));
|
||||
|
||||
// this array is just one dimension, let's get the bounds of the first dimension
|
||||
LONG lBound, uBound;
|
||||
if (FAILED(hResult = SafeArrayGetLBound(pFieldArray, 1, &lBound))
|
||||
|| FAILED(hResult = SafeArrayGetUBound(pFieldArray, 1, &uBound)))
|
||||
{
|
||||
dprintf("[WMI] Failed to get array dimensions: %x", hResult);
|
||||
break;
|
||||
}
|
||||
dprintf("[WMI] Bounds: %u to %u", lBound, uBound);
|
||||
|
||||
LONG fieldCount = uBound - lBound - SYSTEM_FIELD_COUNT - 1;
|
||||
dprintf("[WMI] Query results in %u fields", fieldCount);
|
||||
|
||||
fields = (VARIANT**)malloc(fieldCount * sizeof(VARIANT**));
|
||||
valueTlvs = (Tlv*)malloc(fieldCount * sizeof(Tlv));
|
||||
values = (char*)malloc(fieldCount * FIELD_SIZE);
|
||||
memset(fields, 0, fieldCount * sizeof(VARIANT**));
|
||||
memset(valueTlvs, 0, fieldCount * sizeof(Tlv));
|
||||
memset(values, 0, fieldCount * FIELD_SIZE);
|
||||
|
||||
for (LONG i = 0; i < fieldCount; ++i)
|
||||
{
|
||||
LONG indices[1] = { i + SYSTEM_FIELD_COUNT };
|
||||
char* fieldName = values + (i * FIELD_SIZE);
|
||||
SafeArrayPtrOfIndex(pFieldArray, indices, (void**)&fields[i]);
|
||||
_bstr_t bstr(fields[i]->bstrVal);
|
||||
|
||||
strncpy_s(fieldName, FIELD_SIZE, (const char*)bstr, FIELD_SIZE - 1);
|
||||
|
||||
valueTlvs[i].header.type = TLV_TYPE_EXT_WMI_FIELD;
|
||||
valueTlvs[i].header.length = (UINT)strlen(fieldName) + 1;
|
||||
valueTlvs[i].buffer = (PUCHAR)fieldName;
|
||||
|
||||
dprintf("[WMI] Added header field: %s", fieldName);
|
||||
}
|
||||
|
||||
dprintf("[WMI] added all field headers");
|
||||
// add the field names to the packet
|
||||
packet_add_tlv_group(response, TLV_TYPE_EXT_WMI_FIELDS, valueTlvs, fieldCount);
|
||||
|
||||
dprintf("[WMI] processing values...");
|
||||
// with that horrible pain out of the way, let's actually grab the data
|
||||
do
|
||||
{
|
||||
if (FAILED(hResult))
|
||||
{
|
||||
dprintf("[WMI] Loop exited via %x", hResult);
|
||||
break;
|
||||
}
|
||||
|
||||
memset(valueTlvs, 0, fieldCount * sizeof(Tlv));
|
||||
memset(values, 0, fieldCount * FIELD_SIZE);
|
||||
|
||||
for (LONG i = 0; i < fieldCount; ++i)
|
||||
{
|
||||
char* value = values + (i * FIELD_SIZE);
|
||||
valueTlvs[i].header.type = TLV_TYPE_EXT_WMI_VALUE;
|
||||
valueTlvs[i].buffer = (PUCHAR)value;
|
||||
|
||||
VARIANT varValue;
|
||||
VariantInit(&varValue);
|
||||
|
||||
_bstr_t field(fields[i]->bstrVal);
|
||||
dprintf("[WMI] Extracting value for %s", (char*)field);
|
||||
if (SUCCEEDED(pObj->Get(field, 0, &varValue, NULL, NULL)))
|
||||
{
|
||||
variant_to_string(_variant_t(varValue), value, FIELD_SIZE);
|
||||
}
|
||||
|
||||
valueTlvs[i].header.length = (UINT)strlen(value) + 1;
|
||||
dprintf("[WMI] Added value for %s: %s", (char*)_bstr_t(fields[i]->bstrVal), value);
|
||||
}
|
||||
|
||||
// add the field values to the packet
|
||||
packet_add_tlv_group(response, TLV_TYPE_EXT_WMI_VALUES, valueTlvs, fieldCount);
|
||||
|
||||
pObj->Release();
|
||||
pObj = NULL;
|
||||
} while ((hResult = pEnumerator->Next(ENUM_TIMEOUT, 1, &pObj, &numFound)) != WBEM_S_FALSE);
|
||||
|
||||
} while (0);
|
||||
|
||||
SafeArrayUnlock(pFieldArray);
|
||||
} while (0);
|
||||
|
||||
if (fields)
|
||||
{
|
||||
free(fields);
|
||||
}
|
||||
|
||||
if (values)
|
||||
{
|
||||
free(values);
|
||||
}
|
||||
|
||||
if (valueTlvs)
|
||||
{
|
||||
free(valueTlvs);
|
||||
}
|
||||
|
||||
if (pObj)
|
||||
{
|
||||
pObj->Release();
|
||||
}
|
||||
|
||||
if (pEnumerator)
|
||||
{
|
||||
pEnumerator->Release();
|
||||
}
|
||||
|
||||
if (pServices)
|
||||
{
|
||||
pServices->Release();
|
||||
}
|
||||
|
||||
if (pLocator)
|
||||
{
|
||||
pLocator->Release();
|
||||
}
|
||||
CoUninitialize();
|
||||
|
||||
if (SUCCEEDED(hResult))
|
||||
{
|
||||
hResult = S_OK;
|
||||
dprintf("[WMI] Things appeard to go well!");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
dprintf("[WMI] Failed to initialize COM");
|
||||
}
|
||||
|
||||
if (FAILED(hResult))
|
||||
{
|
||||
// if we failed, we're going to convert the error to a string, add it and still return success, but we'll
|
||||
// also include the hresult.
|
||||
char errorMessage[1024];
|
||||
memset(errorMessage, 0, 1024);
|
||||
_com_error comError(hResult);
|
||||
_snprintf_s(errorMessage, 1024, 1023, "%s (0x%x)", comError.ErrorMessage(), hResult);
|
||||
dprintf("[WMI] returning error -> %s", errorMessage);
|
||||
packet_add_tlv_string(response, TLV_TYPE_EXT_WMI_ERROR, errorMessage);
|
||||
hResult = S_OK;
|
||||
}
|
||||
|
||||
return (DWORD)hResult;
|
||||
}
|
11
c/meterpreter/source/extensions/extapi/wmi_interface.h
Normal file
11
c/meterpreter/source/extensions/extapi/wmi_interface.h
Normal file
@ -0,0 +1,11 @@
|
||||
/*!
|
||||
* @file wmi_interface.h
|
||||
* @brief Declarations for functions that deal directly with WMI
|
||||
* via the COM interfaces.
|
||||
*/
|
||||
#ifndef _METERPRETER_SOURCE_EXTENSION_EXTAPI_WMI_INTERFACE_H
|
||||
#define _METERPRETER_SOURCE_EXTENSION_EXTAPI_WMI_INTERFACE_H
|
||||
|
||||
DWORD wmi_query(LPCWSTR lpwDomain, LPWSTR lpwQuery, Packet* response);
|
||||
|
||||
#endif
|
40
c/meterpreter/source/extensions/extapi/wshelpers.c
Normal file
40
c/meterpreter/source/extensions/extapi/wshelpers.c
Normal file
@ -0,0 +1,40 @@
|
||||
/*!
|
||||
* @file wshelpers.h
|
||||
* @brief Declarations for wide-string helper functions.
|
||||
*/
|
||||
#include "extapi.h"
|
||||
#include "wshelpers.h"
|
||||
|
||||
/*!
|
||||
* @brief Helper function that converts an ASCII string to a wide char string.
|
||||
* @param lpValue ASCII string to convert.
|
||||
* @param lpwValue Target memory for the converted string.
|
||||
* @remark \c lpwValue must be freed by the caller using `free`.
|
||||
* @returns Indication of success or failure.
|
||||
*/
|
||||
DWORD to_wide_string(LPSTR lpValue, LPWSTR* lpwValue)
|
||||
{
|
||||
size_t charsCopied = 0;
|
||||
DWORD valueLength;
|
||||
DWORD dwResult;
|
||||
|
||||
do
|
||||
{
|
||||
if (lpValue == NULL)
|
||||
{
|
||||
BREAK_WITH_ERROR("[EXTAPI ADSI] Value parameter missing", ERROR_INVALID_PARAMETER);
|
||||
}
|
||||
|
||||
valueLength = lstrlenA(lpValue);
|
||||
*lpwValue = (LPWSTR)malloc(sizeof(WCHAR)* (lstrlenA(lpValue) + 1));
|
||||
if (*lpwValue == NULL)
|
||||
{
|
||||
BREAK_WITH_ERROR("[EXTAPI ADSI] Unable to allocate memory", ERROR_OUTOFMEMORY);
|
||||
}
|
||||
|
||||
mbstowcs_s(&charsCopied, *lpwValue, valueLength + 1, lpValue, valueLength);
|
||||
dwResult = ERROR_SUCCESS;
|
||||
} while (0);
|
||||
|
||||
return dwResult;
|
||||
}
|
10
c/meterpreter/source/extensions/extapi/wshelpers.h
Normal file
10
c/meterpreter/source/extensions/extapi/wshelpers.h
Normal file
@ -0,0 +1,10 @@
|
||||
/*!
|
||||
* @file wshelpers.h
|
||||
* @brief Declarations for wide-string helper functions.
|
||||
*/
|
||||
#ifndef _METERPRETER_SOURCE_EXTENSION_EXTAPI_WSHELPERS_H
|
||||
#define _METERPRETER_SOURCE_EXTENSION_EXTAPI_WSHELPERS_H
|
||||
|
||||
DWORD to_wide_string(LPSTR lpValue, LPWSTR* lpwValue);
|
||||
|
||||
#endif
|
@ -114,6 +114,7 @@
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<TreatLinkerWarningAsErrors>true</TreatLinkerWarningAsErrors>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
@ -143,6 +144,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\$(PlatformSho
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<TreatLinkerWarningAsErrors>true</TreatLinkerWarningAsErrors>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
@ -176,6 +178,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\$(PlatformSho
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<AdditionalIncludeDirectories>..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\extapi;..\..\source\openssl\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<TreatLinkerWarningAsErrors>true</TreatLinkerWarningAsErrors>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
@ -210,6 +213,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\$(PlatformSho
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<AdditionalIncludeDirectories>..\..\source\ReflectiveDLLInjection\common;..\..\source\extensions\extapi;..\..\source\openssl\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<TreatLinkerWarningAsErrors>true</TreatLinkerWarningAsErrors>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
@ -249,6 +253,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\$(PlatformSho
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<TreatLinkerWarningAsErrors>true</TreatLinkerWarningAsErrors>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
@ -299,6 +304,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\$(PlatformSho
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<TreatLinkerWarningAsErrors>true</TreatLinkerWarningAsErrors>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
@ -351,6 +357,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\$(PlatformSho
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<TreatLinkerWarningAsErrors>true</TreatLinkerWarningAsErrors>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
@ -401,6 +408,7 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\$(PlatformSho
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<TreatWarningAsError>true</TreatWarningAsError>
|
||||
<TreatLinkerWarningAsErrors>true</TreatLinkerWarningAsErrors>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
@ -438,6 +446,9 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\$(PlatformSho
|
||||
<ClCompile Include="..\..\source\extensions\extapi\extapi.c" />
|
||||
<ClCompile Include="..\..\source\extensions\extapi\service.c" />
|
||||
<ClCompile Include="..\..\source\extensions\extapi\window.c" />
|
||||
<ClCompile Include="..\..\source\extensions\extapi\wmi.c" />
|
||||
<ClCompile Include="..\..\source\extensions\extapi\wmi_interface.cpp" />
|
||||
<ClCompile Include="..\..\source\extensions\extapi\wshelpers.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\source\extensions\extapi\adsi.h" />
|
||||
@ -447,6 +458,9 @@ copy /y "$(TargetDir)$(TargetFileName)" "$(ProjectDir)..\..\output\$(PlatformSho
|
||||
<ClInclude Include="..\..\source\extensions\extapi\extapi.h" />
|
||||
<ClInclude Include="..\..\source\extensions\extapi\service.h" />
|
||||
<ClInclude Include="..\..\source\extensions\extapi\window.h" />
|
||||
<ClInclude Include="..\..\source\extensions\extapi\wmi.h" />
|
||||
<ClInclude Include="..\..\source\extensions\extapi\wmi_interface.h" />
|
||||
<ClInclude Include="..\..\source\extensions\extapi\wshelpers.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\backcompat\backcompat.vcxproj">
|
||||
|
Loading…
Reference in New Issue
Block a user