mirror of
https://github.com/rapid7/metasploit-payloads
synced 2025-01-08 14:36:22 +01:00
Update ADSI code to support more types
When non-supported types were returned in queries, ADSI just pooped itself and tore down the Meterpreter session. This a happy tester Meterpreter does not make! This code includes more support for ADSI types with attempts to be semi-sane in stringifying them. Plus, Meterpreter no longer crashes.
This commit is contained in:
parent
5b35852e32
commit
3cde9b69c2
@ -13,12 +13,60 @@ extern "C" {
|
||||
|
||||
#pragma comment(lib, "Activeds.lib")
|
||||
|
||||
#define VALUE_SIZE 512
|
||||
#define VALUE_SIZE 1024
|
||||
#define PATH_SIZE 256
|
||||
|
||||
/*! @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 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 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* buffer, DWORD bufferSize, char* byteFormat = "%02x", char* delim = "-")
|
||||
{
|
||||
DWORD sizeLeft = bufferSize;
|
||||
|
||||
for (DWORD i = 0; i < count && sizeLeft > 0; ++i)
|
||||
{
|
||||
int printed = 0;
|
||||
if (i != 0)
|
||||
{
|
||||
printed = sprintf_s(buffer, sizeLeft, "%s", delim);
|
||||
sizeLeft -= printed;
|
||||
buffer += printed;
|
||||
}
|
||||
|
||||
printed = sprintf_s(buffer, sizeLeft, byteFormat, bytes[i]);
|
||||
sizeLeft -= printed;
|
||||
buffer += printed;
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @brief Perform a domain query via ADSI.
|
||||
* @param lpwDomain Name of the domain that is to be queried.
|
||||
@ -117,29 +165,195 @@ 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:
|
||||
{
|
||||
// We're going to assume that anything that's 16 bytes it's a GUID. This might not be legit, but for the most
|
||||
// part this is going to be true.
|
||||
if (col.pADsValues->OctetString.dwLength == 16)
|
||||
{
|
||||
guid_to_string(col.pADsValues->OctetString.lpValue, valueTarget, VALUE_SIZE);
|
||||
}
|
||||
else
|
||||
{
|
||||
bytes_to_string(col.pADsValues->OctetString.lpValue, col.pADsValues->OctetString.dwLength, valueTarget, VALUE_SIZE);
|
||||
}
|
||||
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:
|
||||
{
|
||||
bytes_to_string(col.pADsValues->ProviderSpecific.lpValue, col.pADsValues->ProviderSpecific.dwLength, valueTarget, VALUE_SIZE);
|
||||
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;
|
||||
bytes_to_string(pna->Address, pna->AddressLength, valueTarget, VALUE_SIZE, "%u", ".");
|
||||
break;
|
||||
}
|
||||
case ADSTYPE_EMAIL:
|
||||
{
|
||||
source = col.pADsValues->Email.Address;
|
||||
break;
|
||||
}
|
||||
case ADSTYPE_NT_SECURITY_DESCRIPTOR:
|
||||
{
|
||||
ADS_NT_SECURITY_DESCRIPTOR* psd = &col.pADsValues->SecurityDescriptor;
|
||||
bytes_to_string(psd->lpValue, psd->dwLength, valueTarget, VALUE_SIZE);
|
||||
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);
|
||||
bytes_to_string(pdb->lpBinaryValue, pdb->dwLength, valueTarget + charsPrinted, VALUE_SIZE - charsPrinted, "%u", ".");
|
||||
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);
|
||||
}
|
||||
|
||||
entries[dwIndex].header.length = lstrlenA(valueTarget) + 1;
|
||||
pDirSearch->FreeColumn(&col);
|
||||
}
|
||||
else
|
||||
|
Loading…
Reference in New Issue
Block a user