unknown il y a 2 ans
Parent
commit
1d69204a81

+ 17 - 0
KIT/SystemInfo/README.md

@@ -0,0 +1,17 @@
+# SystemInfo
+Enumerate system information via WMI. 
+
+>This tool has some serious limitations due the fact that COM security settings only can be set once. So if the current process already used COM -and most likely called CoInitializeSecurity API- the security setting can't be set for a second time. This results in the situation that most of the time security permissions don't allow for this tool to run if the beacon is started in an existing process. 
+
+If you know a solution for the double CoInitializeSecurity call problem (RPC_E_TOO_LATE) or how to fetch the data without getting the WBEM_E_ACCESS_DENIED error, please let me know!
+
+
+## Usage
+* `systeminfo`
+
+
+## Compile
+- 1\. Make sure Visual Studio is installed and supports C/C++.
+- 2\. Open the `x64 Native Tools Command Prompt for VS <2019/2022>` terminal.
+- 3\. Run the `bofcompile.bat` script to compile the object file. 
+- 4\. In Cobalt strike, use the script manager to load the .cna script to import the tool. 

+ 69 - 0
KIT/SystemInfo/beacon.h

@@ -0,0 +1,69 @@
+/*
+ * Beacon Object Files (BOF)
+ * -------------------------
+ * A Beacon Object File is a light-weight post exploitation tool that runs
+ * with Beacon's inline-execute command.
+ *
+ * Additional BOF resources are available here:
+ *   - https://github.com/Cobalt-Strike/bof_template
+ *
+ * Cobalt Strike 4.x
+ * ChangeLog:
+ *    1/25/2022: updated for 4.5
+ */
+
+/* data API */
+typedef struct {
+	char * original; /* the original buffer [so we can free it] */
+	char * buffer;   /* current pointer into our buffer */
+	int    length;   /* remaining length of data */
+	int    size;     /* total size of this buffer */
+} datap;
+
+DECLSPEC_IMPORT void    BeaconDataParse(datap * parser, char * buffer, int size);
+DECLSPEC_IMPORT char *  BeaconDataPtr(datap * parser, int size);
+DECLSPEC_IMPORT int     BeaconDataInt(datap * parser);
+DECLSPEC_IMPORT short   BeaconDataShort(datap * parser);
+DECLSPEC_IMPORT int     BeaconDataLength(datap * parser);
+DECLSPEC_IMPORT char *  BeaconDataExtract(datap * parser, int * size);
+
+/* format API */
+typedef struct {
+	char * original; /* the original buffer [so we can free it] */
+	char * buffer;   /* current pointer into our buffer */
+	int    length;   /* remaining length of data */
+	int    size;     /* total size of this buffer */
+} formatp;
+
+DECLSPEC_IMPORT void    BeaconFormatAlloc(formatp * format, int maxsz);
+DECLSPEC_IMPORT void    BeaconFormatReset(formatp * format);
+DECLSPEC_IMPORT void    BeaconFormatAppend(formatp * format, char * text, int len);
+DECLSPEC_IMPORT void    BeaconFormatPrintf(formatp * format, char * fmt, ...);
+DECLSPEC_IMPORT char *  BeaconFormatToString(formatp * format, int * size);
+DECLSPEC_IMPORT void    BeaconFormatFree(formatp * format);
+DECLSPEC_IMPORT void    BeaconFormatInt(formatp * format, int value);
+
+/* Output Functions */
+#define CALLBACK_OUTPUT      0x0
+#define CALLBACK_OUTPUT_OEM  0x1e
+#define CALLBACK_OUTPUT_UTF8 0x20
+#define CALLBACK_ERROR       0x0d
+
+DECLSPEC_IMPORT void   BeaconOutput(int type, char * data, int len);
+DECLSPEC_IMPORT void   BeaconPrintf(int type, char * fmt, ...);
+
+
+/* Token Functions */
+DECLSPEC_IMPORT BOOL   BeaconUseToken(HANDLE token);
+DECLSPEC_IMPORT void   BeaconRevertToken();
+DECLSPEC_IMPORT BOOL   BeaconIsAdmin();
+
+/* Spawn+Inject Functions */
+DECLSPEC_IMPORT void   BeaconGetSpawnTo(BOOL x86, char * buffer, int length);
+DECLSPEC_IMPORT void   BeaconInjectProcess(HANDLE hProc, int pid, char * payload, int p_len, int p_offset, char * arg, int a_len);
+DECLSPEC_IMPORT void   BeaconInjectTemporaryProcess(PROCESS_INFORMATION * pInfo, char * payload, int p_len, int p_offset, char * arg, int a_len);
+DECLSPEC_IMPORT BOOL   BeaconSpawnTemporaryProcess(BOOL x86, BOOL ignoreToken, STARTUPINFO * si, PROCESS_INFORMATION * pInfo);
+DECLSPEC_IMPORT void   BeaconCleanupProcess(PROCESS_INFORMATION * pInfo);
+
+/* Utility Functions */
+DECLSPEC_IMPORT BOOL   toWideChar(char * src, wchar_t * dst, int max);

+ 5 - 0
KIT/SystemInfo/bofcompile.bat

@@ -0,0 +1,5 @@
+@ECHO OFF
+
+cl.exe /nologo /c /Od /MT /W0 /GS- /Tc systeminfo.c
+move /y systeminfo.obj systeminfo.o
+

+ 261 - 0
KIT/SystemInfo/systeminfo.c

@@ -0,0 +1,261 @@
+#include <stdio.h>
+#include <wbemidl.h>
+#include "systeminfo.h"
+#include "beacon.h"
+
+
+//https://github.com/outflanknl/C2-Tool-Collection/blob/main/BOF/Psx/SOURCE/Psx.c
+HRESULT BeaconPrintToStreamW(_In_z_ LPCWSTR lpwFormat, ...) {
+	HRESULT hr = S_FALSE;
+	va_list argList;
+	DWORD dwWritten = 0;
+
+	if (g_lpStream <= (LPSTREAM)1) {
+		hr = OLE32$CreateStreamOnHGlobal(NULL, TRUE, &g_lpStream);
+		if (FAILED(hr)) {
+			return hr;
+		}
+	}
+
+	if (g_lpwPrintBuffer <= (LPWSTR)1) { 
+		g_lpwPrintBuffer = (LPWSTR)MSVCRT$calloc(MAX_STRING, sizeof(WCHAR));
+		if (g_lpwPrintBuffer == NULL) {
+			hr = E_FAIL;
+			goto CleanUp;
+		}
+	}
+
+	va_start(argList, lpwFormat);
+	if (!MSVCRT$_vsnwprintf_s(g_lpwPrintBuffer, MAX_STRING, MAX_STRING -1, lpwFormat, argList)) {
+		hr = E_FAIL;
+		goto CleanUp;
+	}
+
+	if (g_lpStream != NULL) {
+		if (FAILED(hr = g_lpStream->lpVtbl->Write(g_lpStream, g_lpwPrintBuffer, (ULONG)MSVCRT$wcslen(g_lpwPrintBuffer) * sizeof(WCHAR), &dwWritten))) {
+			goto CleanUp;
+		}
+	}
+
+	hr = S_OK;
+
+CleanUp:
+
+	if (g_lpwPrintBuffer != NULL) {
+		MSVCRT$memset(g_lpwPrintBuffer, 0, MAX_STRING * sizeof(WCHAR)); // Clear print buffer.
+	}
+
+	va_end(argList);
+	return hr;
+}
+
+//https://github.com/outflanknl/C2-Tool-Collection/blob/main/BOF/Psx/SOURCE/Psx.c
+VOID BeaconOutputStreamW() {
+	STATSTG ssStreamData = { 0 };
+	SIZE_T cbSize = 0;
+	ULONG cbRead = 0;
+	LARGE_INTEGER pos;
+	LPWSTR lpwOutput = NULL;
+
+	if (FAILED(g_lpStream->lpVtbl->Stat(g_lpStream, &ssStreamData, STATFLAG_NONAME))) {
+		return;
+	}
+
+	cbSize = ssStreamData.cbSize.LowPart;
+	lpwOutput = KERNEL32$HeapAlloc(KERNEL32$GetProcessHeap(), HEAP_ZERO_MEMORY, cbSize + 1);
+	if (lpwOutput != NULL) {
+		pos.QuadPart = 0;
+		if (FAILED(g_lpStream->lpVtbl->Seek(g_lpStream, pos, STREAM_SEEK_SET, NULL))) {
+			goto CleanUp;
+		}
+
+		if (FAILED(g_lpStream->lpVtbl->Read(g_lpStream, lpwOutput, (ULONG)cbSize, &cbRead))) {		
+			goto CleanUp;
+		}
+
+		BeaconPrintf(CALLBACK_OUTPUT, "%ls", lpwOutput);
+	}
+
+CleanUp:
+
+	if (g_lpStream != NULL) {
+		g_lpStream->lpVtbl->Release(g_lpStream);
+		g_lpStream = NULL;
+	}
+
+	if (g_lpwPrintBuffer != NULL) {
+		MSVCRT$free(g_lpwPrintBuffer);
+		g_lpwPrintBuffer = NULL;
+	}
+
+	if (lpwOutput != NULL) {
+		KERNEL32$HeapFree(KERNEL32$GetProcessHeap(), 0, lpwOutput);
+	}
+
+	return;
+}
+
+
+
+int go() {
+	BOOL SomethingToPrint = 0;
+    HRESULT hr = S_OK;
+    IWbemLocator *pLoc = NULL;
+    IWbemServices *pSvc = NULL;
+    IEnumWbemClassObject* pEnumerator = NULL;
+    IWbemClassObject *pclsObj = NULL;
+    ULONG uReturn = 0;
+	VARIANT vtProp;
+	BSTR strNetworkResource = NULL;
+	BSTR strQueryLanguage = NULL;
+	BSTR strQuery = NULL;
+
+    hr = OLE32$CoInitializeEx(NULL, COINIT_MULTITHREADED);
+    if (FAILED(hr)) goto cleanup;
+
+    hr = OLE32$CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, EOAC_NONE, NULL);
+    if (FAILED(hr)) {
+		if(hr == RPC_E_TOO_LATE) {
+			BeaconPrintf(CALLBACK_ERROR, "COM error RPC_E_TOO_LATE (COM security settings already set for this process). Will attempt to do it with the current security settings..", hr);
+		} else {
+			BeaconPrintf(CALLBACK_ERROR, "CoInitializeSecurity failed with error: 0x%lx\n", hr);
+			goto cleanup;
+		}
+	}
+
+    IID CLSIDWbemLocator = {0x4590f811, 0x1d3a, 0x11d0, {0x89, 0x1f, 0x00, 0xaa, 0x00, 0x4b, 0x2e, 0x24}};
+	IID IIDIWbemLocator = {0xdc12a687, 0x737f, 0x11cf, {0x88, 0x4d, 0x00, 0xaa, 0x00, 0x4b, 0x2e, 0x24}};
+    hr = OLE32$CoCreateInstance(&CLSIDWbemLocator, NULL, CLSCTX_INPROC_SERVER, &IIDIWbemLocator, (void**)&pLoc);
+    if (FAILED(hr)) goto cleanup;
+
+    strNetworkResource = OLEAUT32$SysAllocString(L"ROOT\\CIMV2");
+    hr = pLoc->lpVtbl->ConnectServer(pLoc, strNetworkResource, NULL, NULL, NULL, 0, NULL, NULL, &pSvc);
+    if (FAILED(hr)) goto cleanup;
+
+	//Win32_OperatingSystem
+    strQueryLanguage = OLEAUT32$SysAllocString(L"WQL");
+    strQuery = OLEAUT32$SysAllocString(L"SELECT * FROM Win32_OperatingSystem");
+    hr = pSvc->lpVtbl->ExecQuery(pSvc, strQueryLanguage, strQuery, WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator);
+    if (FAILED(hr)) goto cleanup;
+	
+	BeaconPrintToStreamW(L"===================SYSTEM INFORMATION===================\n\n");
+
+    while (pEnumerator) {
+        hr = pEnumerator->lpVtbl->Next(pEnumerator, WBEM_INFINITE, 1, &pclsObj, &uReturn);
+        if (0 == uReturn) {
+			if (hr == WBEM_E_ACCESS_DENIED) {
+				BeaconPrintf(CALLBACK_ERROR, "COM error WBEM_E_ACCESS_DENIED. Current COM security permissions don't allow for this operation in the current process.", hr);
+				goto cleanup;
+			}
+            break;
+        }
+		
+        hr = pclsObj->lpVtbl->Get(pclsObj, L"Caption", 0, &vtProp, 0, 0);	
+		BeaconPrintToStreamW(L"%-20s %s\n", L"OS Name:", vtProp.bstrVal);
+        OLEAUT32$VariantClear(&vtProp);
+		
+		
+		hr = pclsObj->lpVtbl->Get(pclsObj, L"Version", 0, &vtProp, 0, 0);	
+		BeaconPrintToStreamW(L"%-20s %s\n", L"OS Version:", vtProp.bstrVal);
+        OLEAUT32$VariantClear(&vtProp);
+		
+		hr = pclsObj->lpVtbl->Get(pclsObj, L"ProductType", 0, &vtProp, 0, 0);	
+		switch(vtProp.uintVal) {
+			case 1: BeaconPrintToStreamW(L"%-20s Standalone Workstation\n", L"OS Configuration:"); break;
+			case 2: BeaconPrintToStreamW(L"%-20s Domain Controller\n", L"OS Configuration:"); break;
+			case 3: BeaconPrintToStreamW(L"%-20s Server\n", L"OS Configuration:"); break;
+			default: BeaconPrintToStreamW(L"%-20s Unknown\n", L"OS Configuration:");
+		}
+		OLEAUT32$VariantClear(&vtProp);
+		
+		hr = pclsObj->lpVtbl->Get(pclsObj, L"RegisteredUser", 0, &vtProp, 0, 0);	
+		BeaconPrintToStreamW(L"%-20s %s\n", L"Registered Owner:", vtProp.bstrVal);
+        OLEAUT32$VariantClear(&vtProp);
+		
+		hr = pclsObj->lpVtbl->Get(pclsObj, L"WindowsDirectory", 0, &vtProp, 0, 0);	
+		BeaconPrintToStreamW(L"%-20s %s\n", L"Windows Directory:", vtProp.bstrVal);
+        OLEAUT32$VariantClear(&vtProp);
+		
+		hr = pclsObj->lpVtbl->Get(pclsObj, L"LastBootUpTime", 0, &vtProp, 0, 0);	
+		BeaconPrintToStreamW(L"%-20s %s\n", L"System Boot Time:", vtProp.bstrVal);
+        OLEAUT32$VariantClear(&vtProp);
+		
+		hr = pclsObj->lpVtbl->Get(pclsObj, L"Locale", 0, &vtProp, 0, 0);	
+		BeaconPrintToStreamW(L"%-20s %s\n", L"System Locale:", vtProp.bstrVal);
+        OLEAUT32$VariantClear(&vtProp);
+		
+		SomethingToPrint = 1;
+		
+        pclsObj->lpVtbl->Release(pclsObj);
+    }
+	
+	//Win32_ComputerSystem
+	OLEAUT32$SysFreeString(strQuery);
+	strQuery = OLEAUT32$SysAllocString(L"SELECT * FROM Win32_ComputerSystem");
+    hr = pSvc->lpVtbl->ExecQuery(pSvc, strQueryLanguage, strQuery, WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator);
+    if (FAILED(hr)) goto cleanup;
+
+    while (pEnumerator) {
+        hr = pEnumerator->lpVtbl->Next(pEnumerator, WBEM_INFINITE, 1, &pclsObj, &uReturn);
+        if (0 == uReturn) {
+            break;
+        }
+		
+		hr = pclsObj->lpVtbl->Get(pclsObj, L"Model", 0, &vtProp, 0, 0);	
+		BeaconPrintToStreamW(L"%-20s %s\n", L"System Model:", vtProp.bstrVal);
+        OLEAUT32$VariantClear(&vtProp);
+		
+		hr = pclsObj->lpVtbl->Get(pclsObj, L"SystemType", 0, &vtProp, 0, 0);	
+		BeaconPrintToStreamW(L"%-20s %s\n", L"System Type:", vtProp.bstrVal);
+        OLEAUT32$VariantClear(&vtProp);
+		
+		hr = pclsObj->lpVtbl->Get(pclsObj, L"Domain", 0, &vtProp, 0, 0);	
+		BeaconPrintToStreamW(L"%-20s %s\n", L"Domain:", vtProp.bstrVal);
+        OLEAUT32$VariantClear(&vtProp);
+
+        pclsObj->lpVtbl->Release(pclsObj);
+    }
+	
+	//Win32_QuickFixEngineering
+	OLEAUT32$SysFreeString(strQuery);
+	strQuery = OLEAUT32$SysAllocString(L"SELECT * FROM Win32_QuickFixEngineering");
+    hr = pSvc->lpVtbl->ExecQuery(pSvc, strQueryLanguage, strQuery, WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, NULL, &pEnumerator);
+    if (FAILED(hr)) goto cleanup;
+
+	BeaconPrintToStreamW(L"Hotfixes Installed:\n");
+    while (pEnumerator) {
+        hr = pEnumerator->lpVtbl->Next(pEnumerator, WBEM_INFINITE, 1, &pclsObj, &uReturn);
+        if (0 == uReturn) {
+            break;
+        }
+		
+		hr = pclsObj->lpVtbl->Get(pclsObj, L"HotFixID", 0, &vtProp, 0, 0);	
+		BeaconPrintToStreamW(L"%-20s %s\n", "", vtProp.bstrVal);
+        OLEAUT32$VariantClear(&vtProp);
+	
+        pclsObj->lpVtbl->Release(pclsObj);
+    }
+
+cleanup:
+    if (pEnumerator) pEnumerator->lpVtbl->Release(pEnumerator);
+    if (pLoc) pLoc->lpVtbl->Release(pLoc);
+    if (pSvc) pSvc->lpVtbl->Release(pSvc);
+	if (strNetworkResource) OLEAUT32$SysFreeString(strNetworkResource);
+    if (strQueryLanguage) OLEAUT32$SysFreeString(strQueryLanguage);
+    if (strQuery) OLEAUT32$SysFreeString(strQuery);
+    OLE32$CoUninitialize();
+	
+	
+	if(SomethingToPrint) {
+		BeaconOutputStreamW();
+	} else BeaconPrintf(CALLBACK_ERROR, "Failed to load system information.\n");
+	
+    return 0;
+}
+
+
+
+
+
+		
+		

+ 24 - 0
KIT/SystemInfo/systeminfo.cna

@@ -0,0 +1,24 @@
+# author REDMED-X
+
+beacon_command_register(
+	"systeminfo", "Enumerate system information.",
+	"INFO:\nEnumerate system information via WMI.\n" .
+	"USAGE:\nsysteminfo\n\n");
+	
+alias systeminfo {
+    $bid = $1;
+
+    # Read in the right BOF file
+    $handle = openf(script_resource("systeminfo.o"));
+    $data   = readb($handle, -1);
+    closef($handle);
+
+	$arg_data  = bof_pack($bid);
+
+	blog($bid, "Tasked to connect to ROOT\\CIMV2 to fetch system information..");
+    beacon_inline_execute($bid, $data, "go", $arg_data);
+
+}
+
+
+

+ 28 - 0
KIT/SystemInfo/systeminfo.h

@@ -0,0 +1,28 @@
+#include <windows.h>  
+
+//BeaconPrintToStreamW + BeaconOutputStreamW
+#define MAX_STRING 8192
+INT g_iGarbage = 1;
+LPSTREAM g_lpStream = (LPSTREAM)1;
+LPWSTR g_lpwPrintBuffer = (LPWSTR)1;
+DECLSPEC_IMPORT HRESULT WINAPI OLE32$CreateStreamOnHGlobal(HGLOBAL hGlobal, BOOL fDeleteOnRelease, LPSTREAM *ppstm);
+WINBASEAPI void *__cdecl MSVCRT$calloc(size_t number, size_t size);
+WINBASEAPI int __cdecl MSVCRT$_vsnwprintf_s(wchar_t *buffer, size_t sizeOfBuffer, size_t count, const wchar_t *format, va_list argptr);
+WINBASEAPI size_t __cdecl MSVCRT$wcslen(const wchar_t *_Str);
+WINBASEAPI void __cdecl MSVCRT$memset(void *dest, int c, size_t count);
+WINBASEAPI HANDLE WINAPI KERNEL32$GetProcessHeap();
+WINBASEAPI LPVOID WINAPI KERNEL32$HeapAlloc(HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes);
+WINBASEAPI void __cdecl MSVCRT$free(void *memblock);
+WINBASEAPI BOOL WINAPI KERNEL32$HeapFree(HANDLE, DWORD, PVOID);
+DECLSPEC_IMPORT int WINAPI KERNEL32$MultiByteToWideChar(UINT CodePage, DWORD dwFlags, _In_NLS_string_(cbMultiByte)LPCCH lpMultiByteStr, int cbMultiByte, LPWSTR lpWideCharStr, int cchWideChar);
+
+
+//Go
+DECLSPEC_IMPORT HRESULT WINAPI OLE32$CoInitializeEx(LPVOID pvReserved, DWORD dwCoInit);
+DECLSPEC_IMPORT void WINAPI OLE32$CoUninitialize(void);
+DECLSPEC_IMPORT HRESULT WINAPI OLE32$CoCreateInstance (REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID riid, LPVOID *ppv);
+DECLSPEC_IMPORT HRESULT WINAPI OLE32$CoInitializeSecurity(PSECURITY_DESCRIPTOR pSecDesc, LONG cAuthSvc, SOLE_AUTHENTICATION_SERVICE *asAuthSvc, void *pReserved1, DWORD dwAuthnLevel, DWORD dwImpLevel, void *pAuthList, DWORD dwCapabilities, void *pReserved3);
+DECLSPEC_IMPORT void WINAPI OLEAUT32$VariantClear(VARIANTARG *pvarg);
+WINBASEAPI BSTR WINAPI OLEAUT32$SysAllocString(const OLECHAR *);
+WINBASEAPI void WINAPI OLEAUT32$SysFreeString(BSTR);
+WINBASEAPI int __cdecl MSVCRT$printf(const char * _Format,...);

BIN
KIT/SystemInfo/systeminfo.o


+ 1 - 0
README.md

@@ -30,6 +30,7 @@ The following tools are currently in the operators' kit:
 |**[LoadLib](KIT/LoadLib)**|Load an on disk present DLL via RtlRemoteCall API in a remote process.|
 |**[PSremote](KIT/PSremote)**|List all running processes on a remote host.|
 |**[SilenceSysmon](KIT/SilenceSysmon)**|Silence the Sysmon service by patching its capability to write ETW events to the log.|
+|**[SystemInfo](KIT/SystemInfo)**|Enumerate system information via WMI (limited use case).|
 
 ## Usage
 Each individual tool has its own README file with usage information and compile instructions.