1
mirror of https://github.com/rapid7/metasploit-payloads synced 2025-03-30 22:19:17 +02:00
OJ af5d6bd908 First pass of WMI support
Not quite working, but a good deal done.
2014-01-16 13:34:15 +10:00

257 lines
6.9 KiB
C++

/*!
* @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>
#pragma comment(lib, "wbemuuid.lib")
#pragma comment(lib, "comsuppw.lib")
#define PATH_SIZE 512
#define FIELD_SIZE 512
#define ENUM_TIMEOUT 5000
/*! @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 } };
/*!
* @brief Perform a WMI query.
* @param lpwDomain Name of the domain that is to be queried.
* @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 lpwDomain, LPWSTR lpwQuery, Packet* response)
{
HRESULT hResult;
WCHAR cbPath[PATH_SIZE];
swprintf_s(cbPath, PATH_SIZE - 1, L"root\\%s", lpwDomain);
if ((hResult = CoInitializeEx(NULL, COINIT_MULTITHREADED)) == S_OK)
{
IWbemLocator* pLocator = NULL;
IWbemServices* pServices = NULL;
IEnumWbemClassObject* pEnumerator = 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;
}
if (FAILED(hResult = CoCreateInstance(CLSID_WbemLocator, NULL, CLSCTX_ALL, IID_PPV_ARGS(&pLocator))))
{
dprintf("[WMI] Failed to create WbemLocator: %x", hResult);
break;
}
if (FAILED(hResult = pLocator->ConnectServer(cbPath, NULL, NULL, NULL, WBEM_FLAG_CONNECT_USE_MAX_WAIT, NULL, NULL, &pServices)))
{
dprintf("[WMI] Failed to create WbemServices at %S: %x", cbPath, hResult);
break;
}
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;
}
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;
}
// 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;
}
// lock the array
if (FAILED(hResult = SafeArrayLock(pFieldArray)))
{
dprintf("[WMI] Failed to get array dimension: %x", hResult);
break;
}
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 = SafeArrayGetLBound(pFieldArray, 1, &uBound)))
{
dprintf("[WMI] Failed to get array dimensions: %x", hResult);
break;
}
LONG fieldCount = uBound - lBound + 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)
{
char* fieldName = values + (i * FIELD_SIZE);
LONG indices[2] = { 0, i };
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);
}
// add the field names to the packet
packet_add_tlv_group(response, TLV_TYPE_EXT_WMI_FIELDS, valueTlvs, fieldCount);
// with that horrible pain out of the way, let's actually grab the data
do
{
if (FAILED(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);
if (SUCCEEDED(pObj->Get(field, 0, &varValue, NULL, NULL)))
{
_variant_t v(varValue);
switch (v.vt)
{
case VT_BOOL:
strncpy_s(value, FIELD_SIZE, v.boolVal == VARIANT_TRUE ? "true" : "false", FIELD_SIZE - 1);
break;
case VT_INT:
_snprintf_s(value, FIELD_SIZE, FIELD_SIZE - 1, "%"PRId32, (INT)v);
break;
case VT_INT_PTR:
_snprintf_s(value, FIELD_SIZE, FIELD_SIZE - 1, "%"PRId64, (INT_PTR)v);
break;
case VT_UINT:
_snprintf_s(value, FIELD_SIZE, FIELD_SIZE - 1, "%"PRIu32, (UINT)v);
break;
case VT_UINT_PTR:
_snprintf_s(value, FIELD_SIZE, FIELD_SIZE - 1, "%"PRIu64, (UINT_PTR)v);
break;
case VT_BSTR:
case VT_LPSTR:
case VT_LPWSTR:
// not sure if this is correct
strncpy_s(value, FIELD_SIZE, (char*)(_bstr_t)v.bstrVal, FIELD_SIZE - 1);
break;
// TODO more types, such as floats, dates, etc.
default:
// ignore the value for other types
break;
}
}
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);
if (SUCCEEDED(hResult))
{
hResult = S_OK;
}
} 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();
dprintf("[WMI] Things appeard to go well!");
}
else
{
dprintf("[WMI] Failed to initialize COM");
}
return (DWORD)hResult;
}