trustedsec / cs-situational-awareness-bof Goto Github PK
View Code? Open in Web Editor NEWSituational Awareness commands implemented using Beacon Object Files
License: GNU General Public License v2.0
Situational Awareness commands implemented using Beacon Object Files
License: GNU General Public License v2.0
I have experienced an issue using the wmi_query as well as the tasklist BOF in which trying to use either BOF on a remote machine with a token created using make_token returns Access Denied.
In a beacon running as the user DA ( a Domain Admin in the network) I am successfully able to use the wmi_query and tasklist BOFs remotely.
In a beacon running as SYSTEM, I use make_token with DA's creds. I am successfully able to use the created token, as demonstrated by doing a ls \dev-dc\c$ as well as using shell wmic ...
I am unable however to use wmi_query or tasklist remotely, receiving an Access Denied error. I'm running CobaltStrike version 4.7.2 and have confirmed this using the latest branch of CS-Situational-Awareness-BOF
Somewhere between commit c46f814 (May 7, 2021) and commit 63b4e7d (Sept 1, 2021), an error was introduced that persists to the most recent commit. Most, if not all, of the commands will trigger the following error on x64 systems (x86 was not tested):
Error: [-] no slot for function (reduce number of Win32 APIs called)
Examples:
`beacon> tasklist
Connecting to \. and retrieving list of currently running processes
[*] Running tasklist
[+] host called home, sent: 10272 bytes
[-] no slot for function (reduce number of Win32 APIs called)
`
beacon> driversigs [*] Running driversigs [+] host called home, sent: 7726 bytes [-] no slot for function (reduce number of Win32 APIs called)
Reproduction:
I've written some internal/private ones that have not changed, but inherit the same libraries/common code, and they issue the same error. It may have been introduced as soon as commit fffdf75 with its numerous additions to bofdefs.h; however, I have not attempted testing to confirm.
Not necessarily a coding issue per se, but wondering if you had ideas on how to query other AD domains (vs the current one) and listing all the domains in the forest with the ldapsearch
BOF ?
Would this necessarily require some code change ?
In go()
a call is made to task_list()
with a variable server
read from a Beacon with BeaconDataExtract
.
This is passed in to Wmi_Connect
as pwszServer
. Besides being null terminated, I don't see a length constraint on pwszServer
The possibility for a heap overrun exists because of the insecure use of wcscpy
to a buffer that is a maximum size of MAX_PATH*sizeof(wchar_t)
CS-Situational-Awareness-BOF/src/common/wmi.c
Line 116 in 075fa23
There is a correctness issue on this line due to a copy/paste error. pwszNameSpace
is the allocated string, but the variable pwszServer
is checked.
pwszNameSpace = (LPWSTR)KERNEL32$HeapAlloc(KERNEL32$GetProcessHeap(), HEAP_ZERO_MEMORY, MAX_PATH*sizeof(wchar_t));
- if (NULL == pwszServer)
+ if (NULL == pwszNameSpace)
CS-Situational-Awareness-BOF/src/common/wmi.c
Line 125 in 075fa23
The possibility for a wild free exists in validate_driver()
:
Take the case where the for loop completes successfully once. At this point, the variables certificate_context
, certificate_header
, and certificate
have been freed but not set back to NULL. On an nth pass through loop, take this case:
if the allocation for certificate_header
fails on line 98
and it jumps to the clear label on line 102
, both certificate
and certificate_context
are non-NULL from a previous time through the loop but will have free routines called on them resulting in a wild free. There are similar issues in the loop on the other goto clear
jumps. After freeing the memory, it should be set to NULL
.
clear:
if (certificate_context)
+ {
CRYPT32$CertFreeCertificateContext(certificate_context);
+ certificate_context = NULL;
+ }
if(certificate_header)
+ {
intFree(certificate_header);
+ certificate_header = NULL;
+ }
if(certificate)
+ {
intFree(certificate);
+ certificate = NULL;
+ }
Memory leak in getIPInfo()
. There are early function exits which do not release the memory belonging to info
.
IP_ADAPTER_INFO * info = intAlloc(sizeof(IP_ADAPTER_INFO) * 32); // have to keep stack < 4K
...
if(IPHLPAPI$GetNetworkParams(pFixedInfo, &netOutBufLen) == ERROR_BUFFER_OVERFLOW){
pFixedInfo = (FIXED_INFO *)intAlloc(netOutBufLen);
if (pFixedInfo == NULL)
{
BeaconPrintf(CALLBACK_ERROR, "could not get network adapter info");
return;
! Leaks memory belonging to info
}
if (IPHLPAPI$GetNetworkParams(pFixedInfo, &netOutBufLen) != NO_ERROR)
{
if (pFixedInfo){
intFree(pFixedInfo);
}
BeaconPrintf(CALLBACK_ERROR, "could not get network adapter info");
return;
! Leaks memory belonging to info
}
}
The early returns are on these lines:
Handle leak in PrintModules()
on early function return.
hProcess = KERNEL32$OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID);
...
// Get size needed before requesting hMods
if(!PSAPI$EnumProcessModulesEx(hProcess, 0, 0, &cbNeeded, LIST_MODULES_ALL)){
internal_printf("Failed to enumerate modules\n");
return 1;
! Fails to call CloseHandle on hProcess
}
The early return is here:
Registry handle leak in Reg_GetValue()
on early function return.
dwRet = ADVAPI32$RegConnectRegistryA(hostname, hivekey, &RemoteKey);
...
dwRet = ADVAPI32$RegOpenKeyExA(RemoteKey, keystring, 0, KEY_READ, &key);
...
ValueData = intAlloc(size);
if (ValueData == NULL){
BeaconPrintf(CALLBACK_ERROR, "Failed to allocate memory\n");
return E_OUTOFMEMORY;
! fails to free registry key handles done at the END: label
}
This is where the keys are normally freed:
END:
...
! early function exits fail to release allocated resources as done here
if(key)
ADVAPI32$RegCloseKey(key);
if(RemoteKey)
ADVAPI32$RegCloseKey(RemoteKey);
The early return is here:
Invalid permissions specified in call to ADVAPI32$OpenServiceA (SC_MANAGER_CONNECT is a permission for ADVAPI32$OpenSCManagerA
, not ADVAPI32$OpenServiceA
if ((scService = ADVAPI32$OpenServiceA(scManager, cpServiceName, SC_MANAGER_CONNECT | GENERIC_READ)) == NULL)
! SC_MANAGER_CONNECT is not a service permission
Even though it is incorrect, it doesn't cause any harm because SC_MANAGER_CONNECT
maps to 0x0001
which is SERVICE_QUERY_CONFIG
SC_MANAGER_CONNECT
should be removed because GENERIC_READ
is sufficient to cover the calls to get_service_config
and get_service_status
.
GENERIC_READ --->
STANDARD_RIGHTS_READ
SERVICE_QUERY_CONFIG
SERVICE_QUERY_STATUS
SERVICE_INTERROGATE
SERVICE_ENUMERATE_DEPENDENTS
See these places for instances of this issue::
Leak because Vserver.bstrVal is not freed after usage.
Vserver.bstrVal = OLEAUT32$SysAllocString(server);
Same issue here:
Release is not called on pSubfolders
ITaskFolderCollection *pSubfolders = NULL;
...
pCurFolder->lpVtbl->GetFolders(pCurFolder, 0, &pSubfolders);
Handle leak on hToken
because CloseHandle
path is skipped on early function exits
if (ADVAPI32$OpenProcessToken(KERNEL32$GetCurrentProcess(), TOKEN_READ, &hToken))
{
ADVAPI32$GetTokenInformation(hToken,
TokenType,
NULL,
dwLength,
&dwLength);
if (KERNEL32$GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
pTokenInfo = intAlloc(dwLength);
if (pTokenInfo == NULL)
{
//printf("ERROR: not enough memory to allocate the token structure.\r\n");
return NULL;
! doesn't call CloseHandle on hToken
}
}
if (!ADVAPI32$GetTokenInformation(hToken, TokenType,
(LPVOID)pTokenInfo,
dwLength,
&dwLength))
{
//printf("ERROR 0x%x: could not get token information.\r\n", GetLastError());
intFree(pTokenInfo);
return NULL;
! doesn't call CloseHandle on hToken
}
Early exits
The code is missing a KERNEL32$FindClose(hand) before this return statement https://github.com/trustedsec/CS-Situational-Awareness-BOF/blob/master/src/SA/dir/entry.c#L48
During an engagement I attempted to search for a user with a dash in the name e.g. - "netuser t-testuser domain.com" and the BOF returns the error Failed to get user info
I also attempted to wrap the username in quotes, and escape the dash with a backslash. All attempted returned the error above. I am able to find the user with a traditional net user lookup via beacon run net user t-testuser /domain
wmi_query always returns S_OK even on failure cases.
I am not sure this leads to any bugs, but it may not be the developer's intent.
HRESULT wmi_query(
LPWSTR pwszServer,
LPWSTR pwszNameSpace,
LPWSTR pwszQuery
)
{
HRESULT hr = S_OK;
...
hr = S_OK;
// Initialize COM
hr = Wmi_Initialize(&m_WMI);
if (FAILED(hr))
{
BeaconPrintf(CALLBACK_ERROR, "Wmi_Initialize failed: 0x%08lx", hr);
goto fail;
}
// Connect to WMI on host
hr = Wmi_Connect(&m_WMI, pwszServer, pwszNameSpace);
if (FAILED(hr))
{
BeaconPrintf(CALLBACK_ERROR, "Wmi_Connect failed: 0x%08lx", hr);
goto fail;
}
...
fail:
hr = Wmi_Finalize(&m_WMI);
! this overrides any previous value of hr from a `goto fail` and will result in it being set to S_OK
if (FAILED(hr))
! this code path will never be called
{
- BeaconPrintf(CALLBACK_ERROR, "Wmi_Destroy failed: 0x%08lx", hr);
+ BeaconPrintf(CALLBACK_ERROR, "Wmi_Finalize failed: 0x%08lx", hr);
}
return hr;
}
See the implementation of Wmi_Finalize
always returns S_OK
:
HRESULT Wmi_Finalize(
WMI* pWmi
)
{
HRESULT hr = S_OK;
SAFE_RELEASE(pWmi->pWbemServices);
SAFE_RELEASE(pWmi->pWbemLocator);
SAFE_FREE(pWmi->bstrLanguage);
SAFE_FREE(pWmi->bstrServer);
SAFE_FREE(pWmi->bstrNameSpace);
SAFE_FREE(pWmi->bstrNetworkResource);
SAFE_FREE(pWmi->bstrQuery);
// un-initialize the COM library
OLE32$CoUninitialize();
! always returns S_OK
return hr;
}
CS-Situational-Awareness-BOF/src/common/wmi.c
Line 584 in 9dfb052
OpenSCManagerA
and enumerate_services
return win32 errors, not HRESULT so error code should be checked against ERROR_SUCCESS
I am not sure this leads to any bugs, but it may not be the developer's intent.
VOID go(
IN PCHAR Buffer,
IN ULONG Length
)
{
const char * hostname = NULL;
const char * servicename = NULL;
- DWORD result = 0;
+ DWORD result = ERROR_SUCCESS;
...
if ((gscManager = ADVAPI32$OpenSCManagerA(hostname, SERVICES_ACTIVE_DATABASEA, SC_MANAGER_CONNECT | GENERIC_READ)) == NULL)
{
result = KERNEL32$GetLastError();
}
- if(result == S_OK)
+ if(result == ERROR_SUCCESS)
{
result = enumerate_services();
- if(result != S_OK)
+ if(result != ERROR_SUCCESS)
{
BeaconPrintf(CALLBACK_ERROR, "Failed to query service: %u", result);
}
DWORD enumerate_services()
{
DWORD dwResult = ERROR_SUCCESS;
...
return dwResult;
! returns ERROR_SUCCESS or GetLastError, not S_OK
}
enumerate_loaded_drivers()
leaks memory in early return
int enumerate_loaded_drivers()
{
// Create a handle to the service manager for calls to EnumServicesStatusExW.
SC_HANDLE scm_handle = ADVAPI32$OpenSCManagerA(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE);
if (!scm_handle)
{
internal_printf("[ERROR] Cannot open handle to service manager.\n");
return 1;
}
// Determine the bytes needed for allocation.
unsigned long bytes_needed = 0;
unsigned long services_returned = 0;
ADVAPI32$EnumServicesStatusExW(scm_handle, SC_ENUM_PROCESS_INFO, SERVICE_DRIVER, SERVICE_ACTIVE, NULL, 0, &bytes_needed, &services_returned, NULL, NULL);
// Retrieve a buffer of active driver services.
PBYTE services = (PBYTE)intAlloc(bytes_needed);
if (!ADVAPI32$EnumServicesStatusExW(scm_handle, SC_ENUM_PROCESS_INFO, SERVICE_DRIVER , SERVICE_ACTIVE, services, bytes_needed, &bytes_needed, &services_returned, NULL, NULL))
{
internal_printf("[ERROR] Cannot enumerate services -> %ld.\n", KERNEL32$GetLastError());
! leaks memory allocated for `services`
return 1;
}
LPENUM_SERVICE_STATUS_PROCESSW service = (LPENUM_SERVICE_STATUS_PROCESSW)services;
// Get the ImagePath for each service from registry, and pass that to the validate_driver() function.
for (unsigned long i = 0; i < services_returned; i++)
{
PWCHAR registry_path = (PWCHAR)intAlloc(MAX_PATH * 2);
if (registry_path)
{
MSVCRT$wcsncat(registry_path, L"SYSTEM\\CurrentControlSet\\Services\\", MAX_PATH);
MSVCRT$wcsncat(registry_path, service->lpServiceName, MAX_PATH);
}
{
BeaconPrintf(CALLBACK_ERROR, "Out of memory");
! leaks memory allocated for `services`
return 1;
}
HKEY key_handle;
ADVAPI32$RegOpenKeyExW(HKEY_LOCAL_MACHINE, registry_path, 0, KEY_QUERY_VALUE, &key_handle);
unsigned long length = 0;
ADVAPI32$RegQueryValueExW(key_handle, L"ImagePath", NULL, NULL, NULL, &length);
intFree(registry_path);
if (length)
{
PWCHAR driver_path = (PWCHAR)intAlloc(length);
! should check for failed allocation for `driver_path`
ADVAPI32$RegQueryValueExW(key_handle, L"ImagePath", NULL, NULL, (LPBYTE)driver_path, &length);
validate_driver(driver_path);
intFree(driver_path);
}
KERNEL32$CloseHandle(key_handle);
service++;
}
intFree(services);
KERNEL32$CloseHandle(scm_handle);
return 0;
}
SCM handle must be closed with CloseServiceHandle
not CloseHandle
int enumerate_loaded_drivers()
{
// Create a handle to the service manager for calls to EnumServicesStatusExW.
SC_HANDLE scm_handle = ADVAPI32$OpenSCManagerA(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE);
@@ scm_handle is not a kernel handle @@
...
- KERNEL32$CloseHandle(scm_handle);
+ ADVAPI32$CloseServiceHandle(scm_handle );
return 0;
Registry handle needs to be closed with RegCloseKey
not CloseHandle
int enumerate_loaded_drivers()
{
...
HKEY key_handle;
ADVAPI32$RegOpenKeyExW(HKEY_LOCAL_MACHINE, registry_path, 0, KEY_QUERY_VALUE, &key_handle);
unsigned long length = 0;
ADVAPI32$RegQueryValueExW(key_handle, L"ImagePath", NULL, NULL, NULL, &length);
intFree(registry_path);
if (length)
{
PWCHAR driver_path = (PWCHAR)intAlloc(length);
ADVAPI32$RegQueryValueExW(key_handle, L"ImagePath", NULL, NULL, (LPBYTE)driver_path, &length);
validate_driver(driver_path);
intFree(driver_path);
}
- KERNEL32$CloseHandle(key_handle);
+ ADVAPI32$RegCloseKey(key_handle);
service++;
}
I am not sure the effect here but I wanted to flag it. There are mismatches between the count of elements and the number of elements in calls to antiStringResolve
EServiceStatus = antiStringResolve(8, "SPACER", "STOPPED", "START_PENDING", "STOP_PENDING", "RUNNING", "CONTINUE_PENDING", "PAUSE_PENDING");
! 8 items declared but only 7 in va_args
...
EServiceStartup = antiStringResolve(6, "BOOT_DRIVER", "SYSTEM_START_DRIVER", "AUTO_START", "DEMAND_START", "DISABLED");
! 6 items declared but only 5 in va_args
EServiceStatus = antiStringResolve(8, "SPACER", "STOPPED", "START_PENDING", "STOP_PENDING", "RUNNING", "CONTINUE_PENDING", "PAUSE_PENDING");
! 8 items declared but only 7 in va_args
EServiceStartup = antiStringResolve(6, "BOOT_DRIVER", "SYSTEM_START_DRIVER", "AUTO_START", "DEMAND_START", "DISABLED");
! 6 items declared but only 5 in va_args
EServiceStatus = antiStringResolve(8, "SPACER", "STOPPED", "START_PENDING", "STOP_PENDING", "RUNNING", "CONTINUE_PENDING", "PAUSE_PENDING");
! 8 items declared but only 7 in va_args
antiStringResolve
will call va_arg
on the extra argument and I am not sure the result.
char ** antiStringResolve(unsigned int count, ...)
{
va_list strings;
va_start(strings, count);
char ** result = intAlloc(sizeof(char *) * count);
for(int i = 0; i < count; i++)
{
result[i] = (char *)va_arg(strings, char *);
}
va_end(strings);
return result;
}
Reg_EnumKey
loop missing a call to intFree
on item
. It frees the memory of the item contents (val->keypath
, val->hreg
), but not the item itself.
pregkeyval init_regkey(const char * curpath, DWORD dwcurpathsz, const char * childkey, DWORD dwchildkeysz, HKEY hreg)
{
pregkeyval item = (pregkeyval)intAlloc(sizeof(regkeyval));
@@ allocates memory for item @@
item->dwkeypathsz = dwcurpathsz + ((dwchildkeysz) ? dwchildkeysz + 1 : 0); //str\str does not include null or just str, if we don't have a child key
item->keypath = intAlloc(item->dwkeypathsz + 1);
memcpy(item->keypath, curpath, dwcurpathsz);
if(dwchildkeysz > 0)
{
item->keypath[dwcurpathsz] = '\\';
memcpy(item->keypath + dwcurpathsz + 1, childkey, dwchildkeysz);
}
item->hreg = hreg;
//item->keypath[item->dwkeypathsz] = 0;
return item;
}
void free_regkey(pregkeyval val)
{
if(val->keypath)
{
intFree(val->keypath);
}
if(val->hreg)
{
ADVAPI32$RegCloseKey(val->hreg);
}
}
DWORD Reg_EnumKey(const char * hostname, HKEY hivekey, DWORD Arch, const char* keystring, BOOL recursive){
...
keyStack->push(keyStack, init_regkey(keystring, strlen(keystring), NULL, 0, rootkey));
while((curitem = keyStack->pop(keyStack)) != NULL)
...
nextloop:
if(currentkeyname)
{intFree(currentkeyname); currentkeyname = NULL;}
if(currentvaluename)
{intFree(currentvaluename); currentvaluename = NULL;}
if(currentdata)
{intFree(currentdata); currentdata = NULL;}
retCode = ERROR_SUCCESS;
i = 0;
cSubKeys = 0;
cbMaxSubKey = 0;
cValues = 0;
cchMaxValue = 0;
cchMaxData = 0;
free_regkey(curitem);
! curitem itself not freed?
curitem = NULL;
} // end While
Copy Paste error leads to incorrect initialization. It doesn't cause a bug because the buffer size matches.
char szGroupName[255] = {0};
char szDomainName[255] = {0};
DWORD cchGroupName = _countof(szGroupName);
- DWORD cchDomainName = _countof(szGroupName);
+ DWORD cchDomainName = _countof(szDomainName);
Add argument to adcs_enum to specify the domain
NetGroupList does not properly handle domains with an very large number of groups. I'd guess more than 100 entries.
Specifically we never update our starting index as we continue to query
Example on MSDN shows what we are missing.
NetGroupListMember / Local variants should likely also be checked
Someone overlooked this when adding the alias.
beacon> help enumLocalSessions
[-] help error: no help is available for 'enumLocalSessions'
Tested this on multiple clients side by side with Certify and came up with conflicting results.
In multiple cases, adcs_enum lists the Domain Users group as having WriteProperty rights. A secondary check with Certify of the same template shows that is not the case (see below, a lot of data was redacted for obvious reasons). Additionally, we manually checked the ACLs on the templates with the clients and did not see WriteProperty being assigned to Domain Users.
// adcs_enum output
Template Name : User
Friendly Name : User
Extended Key Usage : Encrypting File System, Secure Email, Client Authentication
Permissions :
Owner : TEST\Enterprise Admins
Access Rights :
Principal : TEST\Domain Admins
Access mask : 00000100
Flags : 00000001
Enrollment Rights
Principal : TEST\Enterprise Admins
Access mask : 00000100
Flags : 00000001
Enrollment Rights
Principal : TEST\Domain Admins
Access mask : 00000130
Flags : 00000001
Enrollment Rights
WriteProperty Rights
Principal : TEST\Domain Users
Access mask : 00000130
Flags : 00000001
Enrollment Rights
WriteProperty Rights
// certify output
[*] Available Certificates Templates :
CA Name : ADCS.TEST.local\TestRootCA
Template Name : User
pkiextendedkeyusage : Client Authentication, Encrypting File System, Secure Email
Permissions
Enrollment Permissions
Enrollment Rights : TEST\Domain Admins
TEST\Domain Users
TEST\Enterprise Admins
Object Control Permissions
Owner : TEST\Enterprise Admins
WriteOwner Principals : TEST\Domain Admins
TEST\Enterprise Admins
WriteDacl Principals : TEST\Domain Admins
TEST\Enterprise Admins
WriteProperty Principals : TEST\Domain Admins
TEST\Enterprise Admins
In doing some syncs with your repo today, I noticed that these two modules were failing to build with the errors all originating with this one (using KALI with mingw):
x86_64-w64-mingw32-gcc -o sc_qtriggerinfo.x64.o -I ../../common -Os -c entry.c -DBOF
entry.c: In function ‘get_service_triggers’:
entry.c:49:2: error: unknown type name ‘PSERVICE_TRIGGER_INFO’; did you mean ‘LPSERVICE_SID_INFO’?
49 | PSERVICE_TRIGGER_INFO lpServiceConfig = NULL;
x86_64-w64-mingw32-gcc -o sc_enum.x64.o -I ../../common -Os -c entry.c -DBOF
entry.c: In function ‘get_service_triggers’:
entry.c:227:2: error: unknown type name ‘PSERVICE_TRIGGER_INFO’; did you mean ‘LPSERVICE_SID_INFO’?
227 | PSERVICE_TRIGGER_INFO lpServiceConfig = NULL;
| ^~~~~~~~~~~~~~~~~~~~~
So trying to troubleshoot (I prefer providing solutions rather than just complaining :) )...in sc_enum I wound up moving the #endif
on line 35 to line 18 and it compiles fine after doing that. But in looking at the revision history of the file, I noticed that the #endif
has always been there like that. So I investigated where the setting was coming from (it wasn't anywhere in your code that I could find) and changed the beginning of sc_enum to:
#define STR(x) #x
#include <windows.h>
#ifdef SERVICE_CONFIG_TRIGGER_INFO
#pragma message "SERVICE_CONFIG_TRIGGER_INFO already defined as " XSTR(SERVICE_CONFIG_TRIGGER_INFO)
#endif
#include "bofdefs.h"
#ifdef SERVICE_CONFIG_TRIGGER_INFO
#pragma message "SERVICE_CONFIG_TRIGGER_INFO already defined as " XSTR(SERVICE_CONFIG_TRIGGER_INFO)
#endif
#include "base.c"
#ifdef SERVICE_CONFIG_TRIGGER_INFO
#pragma message "SERVICE_CONFIG_TRIGGER_INFO already defined as " XSTR(SERVICE_CONFIG_TRIGGER_INFO)
#endif
#include "anticrash.c"
#ifdef SERVICE_CONFIG_TRIGGER_INFO
#pragma message "SERVICE_CONFIG_TRIGGER_INFO already defined as " XSTR(SERVICE_CONFIG_TRIGGER_INFO)
#endif
Which gave:
╰ $ make
x86_64-w64-mingw32-gcc -o sc_enum.x64.o -I ../../common -Os -c entry.c -DBOF
entry.c:5:9: note: ‘#pragma message: SERVICE_CONFIG_TRIGGER_INFO already defined as 8’
5 | #pragma message "SERVICE_CONFIG_TRIGGER_INFO already defined as " XSTR(SERVICE_CONFIG_TRIGGER_INFO)
Which tells me its coming from the windows.h include. I don't know what changed or if that was always there in windows.h (I assume not b/c it worked just fine for a long time until just now). Regardless, SEVICE_CONFIG_TRIGGER_INFO is already defined from windows.h but the structs are not, leading to the error. I am not sure if the proper fix is to define the struct regardless (which is what moving the #endif
basically did, or if there was some other checks that should be done instead and instead am chosing to report the issue to you as the author.
This BSTR for bstFriendlyName
is not deallocated. Needs a call to SysFreeString
HRESULT _adcs_get_CertificateTemplateExtendedKeyUsages(VARIANT* lpvarExtendedKeyUsages)
{
...
BSTR bstFriendlyName = NULL;
...
while(SUCCEEDED(hr) && lFetch > 0)
{
if (lFetch == 1)
{
pDisp = V_DISPATCH(&var);
pDisp->lpVtbl->QueryInterface(pDisp, &IID_IObjectId, (void**)&pObjectId);
SAFE_RELEASE(pDisp);
hr = pObjectId->lpVtbl->get_FriendlyName(
pObjectId,
&bstFriendlyName
);
if (FAILED(hr)) { internal_printf(" N/A\n"); }
else {
internal_printf(" %S\n", bstFriendlyName);
+ SAFE_FREE(bstFriendlyName);
}
SAFE_RELEASE(pObjectId);
}
OLEAUT32$VariantClear(&var);
hr = pEnum->lpVtbl->Next(pEnum, 1, &var, &lFetch);
} // end loop through IObjectIds via enumerator
SAFE_RELEASE(pObjectId);
hr = S_OK;
//internal_printf("\n _adcs_get_CertificateTemplateExtendedKeyUsages SUCCESS.\n");
fail:
OLEAUT32$VariantClear(&var);
return hr;
} // end _adcs_get_CertificateTemplateExtendedKeyUsages
Hi there,
would be great if the "netstat" BOF would display the PID of the process opened the socket as well.
Like doing a "netstat -aon" via cmd.
Cheers
items like objectSid / objectGUID need to be pulled using ldap_get_value_len it looks like
or something else needs to be done
regardless, even with current transforms objectSid at the very least is invalid
Hi there,
Wondering if netview_list is missing.
Thanks
title
dir does not work on a remote computer.
dir \remote-server\C$
[-] File not found: \remote-server\C$
ls \remote-server\C$ is Cobalt Strike's built in command that works.
service start, stop , create, had disappeared ?? in the last video in YouTube they were existing.
thx :))
A recent update to WMI.c (which fixed token impersonation, thanks for that!) changed the parameters that the WMI_Connect function requires; the Tasklist BOF uses WMI to perform it's actions and was not updated to reflect these changes, which causes it to fail when compiling.
The relevant code from src/SA/tasklist/entry.c:
HRESULT task_list(
LPWSTR pwszServer
)
{
HRESULT hr = S_OK;
WMI m_WMI;
size_t ullQuerySize = 0;
LPWSTR lpwszQuery = NULL;
BSTR** ppbstrResults = NULL;
DWORD dwRowCount = 0;
DWORD dwColumnCount = 0;
DWORD dwCurrentRowIndex = 0;
DWORD dwCurrentColumnIndex = 0;
// Initialize COM
hr = Wmi_Initialize(&m_WMI);
if (FAILED(hr))
{
BeaconPrintf(CALLBACK_ERROR, "Wmi_Initialize failed: 0x%08lx", hr);
goto fail;
}
// Connect to WMI on host
hr = Wmi_Connect(&m_WMI, pwszServer, NULL);
if (FAILED(hr))
{
BeaconPrintf(CALLBACK_ERROR, "Wmi_Connect failed: 0x%08lx", hr);
goto fail;
}
should be:
HRESULT task_list(
LPWSTR pwszResource
)
{
HRESULT hr = S_OK;
WMI m_WMI;
size_t ullQuerySize = 0;
LPWSTR lpwszQuery = NULL;
BSTR** ppbstrResults = NULL;
DWORD dwRowCount = 0;
DWORD dwColumnCount = 0;
DWORD dwCurrentRowIndex = 0;
DWORD dwCurrentColumnIndex = 0;
// Initialize COM
hr = Wmi_Initialize(&m_WMI);
if (FAILED(hr))
{
BeaconPrintf(CALLBACK_ERROR, "Wmi_Initialize failed: 0x%08lx", hr);
goto fail;
}
// Connect to WMI on host
hr = Wmi_Connect(&m_WMI, pwszResource);
if (FAILED(hr))
{
BeaconPrintf(CALLBACK_ERROR, "Wmi_Connect failed: 0x%08lx", hr);
goto fail;
}
I also changed SA.cna to use the resource model that wmi_query now does:
alias tasklist{
local('$args $resource')
$resource = "";
if ((size(@_) < 1) || (size(@_) > 2))
{
berror($1, beacon_command_detail("tasklist"));
berror($1, "Invalid number of arguments");
return;
}
$resource = iff(-istrue $2, "\\\\$2\\root\\cimv2", "\\\\.\\root\\cimv2");
$args = bof_pack($1, "Z", $resource);
beacon_inline_execute($1, readbof($1, "tasklist", "Connecting to $resource and retrieving list of currently running processes", "T1057"), "go", $args);
}
Looking for reverse lookup support with the nslookup BOF.
If I do nslookup 10.10.10.10 it only returns the A record for the IP but no hostname. If I try the below options I get DNS errors.
nslookup 10.10.10.10.in-addr.arpa
nslookup 10.10.10.10 PTR
trustedsec/CS-Situational-Awareness-BOF/blob/master/SA/SA.cna : Line 167
Change:
If this fails with an error about paging not being supported you can try tou se nonpagedldapsearch instead (its unregistered but has the same arguments)");
To:
If this fails with an error about paging not being supported you can try to use nonpagedldapsearch instead (its unregistered but has the same arguments)");
tou se
to to use
literally unusable /s
I am not a C++ expert, but I would suggest an additional look at this free:
All the other variables being freed are declared and initialized at function entry. However, ppValue is not declared or initialized until line 228:
There are several code paths which skip this declaration and initialization, notably on lines lines 182
, 193
, 201
, 213
, 218
, which goto end
on error conditions. If the initialization of ppValue
was skipped by the goto
, ldap_value_free
may be called on an uninitialized variable and hence a wild free.
I made a pull request not too long ago to include the nTSecurityDescriptor attribute in base64 to include ACL resolving via bofhound. Now it turns out I didn't test it thoroughly enough, as low-privileged domain users can't read this attribute unless specified via security descriptor control (see https://github.com/the-useless-one/pywerview/blob/master/pywerview/functions/net.py - search for 0x07). I'll see if I can get it working.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.