ccob / bof.net Goto Github PK
View Code? Open in Web Editor NEWA .NET Runtime for Cobalt Strike's Beacon Object Files
A .NET Runtime for Cobalt Strike's Beacon Object Files
Hi, thank you for sharing this great code.
Unfortunately I always receive a
[-] download [id: -1555981019] closed: Missed start message/metadata.
error in Cobalt when trying to download files larger 1MB. What could be the issue here?
My code on the assembly side for simple testing of the download looks like this:
using BOFNET;
using System.IO;
namespace dlfix
{
internal class Program
{
class DLFIX : BeaconObject
{
public DLFIX(BeaconApi api) : base(api) { }
public override void Go(string[] args)
{
BeaconConsole.WriteLine("[+] TESTING DOWNLOAD");
byte[] filebyte = File.ReadAllBytes(@"C:\temp\Testing");
MemoryStream stream = new MemoryStream();
using (var writer = new BinaryWriter(stream))
{
writer.Write(filebyte);
stream.Position = 0;
DownloadFile("notexisting.bin", stream);
}
}
}
}
}
A BSTR friendlyName
is declared but not freed in the main body of getAppDomain
and the memory is leaked as a result
while((hr = icrh->NextDomain(hDomainEnum, &iu)) == S_OK){
! BSTR friendlyName; <<< BSTR declared
...
! hr = appDomain->get_FriendlyName(&friendlyName); <<< BSTR allocated and returned
if(friendlyName && wcscmp(friendlyName, appDomainName) == 0){
iu->Release();
found = true;
+ SysFreeString on friendlyName
break;
}
hr = appDomain->Load_2(SysAllocString(L"BOFNET"), &assembly);
if(assembly == nullptr){
iu->Release();
+ SysFreeString on friendlyName
continue;
}
found = true;
iu->Release();
+ SysFreeString on friendlyName
break;
}
BOF.NET/bofs/bofnet_execute.cpp
Line 115 in 1ef41fe
Hey,
Really appreciate the effort that's gone into supporting the undocumented BOF functionality.
I've run into an issue with DownloadFile()
. It appears to work fine with bofnet_execute
but throws a NullReferenceException
error with bofnet_job
. This may be down to the way I'm using it. If so, would appreciate some code samples on usage if you have the time.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using BOFNET;
namespace BOFNET_TestFileDownload
{
class Program : BeaconObject
{
public Program(BeaconApi api) : base(api) { }
public override void Go(string[] args)
{
MemoryStream ms = new MemoryStream();
using (FileStream file = new FileStream(@"C:\temp\Testing.txt", FileMode.Open, FileAccess.Read))
file.CopyTo(ms);
ms.Position = 0;
DownloadFile("testfile.txt", ms);
ms.Close();
BeaconConsole.WriteLine($"[+] File sent!");
}
static void Main(string[] args)
{
}
}
}
beacon> bofnet_execute BOFNET_TestFileDownload.Program
[*] Attempting to execute BOFNET BOFNET_TestFileDownload.Program
[+] host called home, sent: 6809 bytes
[*] started download of testfile.txt (24 bytes)
[*] download of testfile.txt is complete
[+] received output:
[+] File sent!
beacon> bofnet_job BOFNET_TestFileDownload.Program
[*] Attempting to start BOFNET BOFNET_TestFileDownload.Program as a job
[+] host called home, sent: 6836 bytes
[+] received output:
[+] Started Task BOFNET_TestFileDownload.Program with job id 4
beacon> bofnet_jobstatus 4
[*] Attempting to execute BOFNET BOFNET.Bofs.Jobs.JobStatus
[+] host called home, sent: 6808 bytes
[+] received output:
Type: Program, Id: 4, Active: False, Console Data: True
Job execution failed with exception:
System.NullReferenceException: Object reference not set to an instance of an object.
at BOFNET.BeaconObject.DownloadFile(String fileName, Stream fileData)
at BOFNET_TestFileDownload.Program.Go(String[] args)
at BOFNET.BeaconJob.DoTask(Object args)
[+] Job completed and console drained, removing from active job list
TrustedSec recently updated their Situational Awareness BOF toolkit to support/fix remote WMI queries using tokens created with make_token. See issue: trustedsec/CS-Situational-Awareness-BOF#94
The issue related to the "CoInitializeSecurity" call:
hr = OLE32$CoInitializeSecurity( //Failure of this function does not necessarily mean we failed to initialize, it will fail on repeated calls, but the values from the original call are retained
NULL,
-1,
NULL,
NULL,
RPC_C_AUTHN_LEVEL_DEFAULT,
RPC_C_IMP_LEVEL_IMPERSONATE,
NULL,
EOAC_NONE,
NULL);
Specifically the EOAC_NONE flag was changed to EOAC_DYNAMIC_CLOAKING so that subsequent WMI calls would use the thread token (see more here: https://learn.microsoft.com/en-us/windows/win32/api/objidl/ne-objidl-eole_authentication_capabilities)
From the MSDN page on CoInitializeSecurity(https://learn.microsoft.com/en-us/windows/win32/api/combaseapi/nf-combaseapi-coinitializesecurity):
The CoInitializeSecurity function initializes the security layer and sets the specified values as the security default. If a process does not call CoInitializeSecurity, COM calls it automatically the first time an interface is marshaled or unmarshaled, registering the system default security. No default security packages are registered until then.
This function is called exactly once per process, either explicitly or implicitly. It can be called by the client, server, or both.
The issue arises when BOF.NET is initialized in a process before any other COM interface, i.e. before a Situational Awareness BOF that uses WMI has been called.
Because BOF.NET fails to call CoInitializeSecurity, COM calls it automatically and without the requisite flags to allow the use of tokens created with make_token. Subsequently, all WMI related functionalities in the beacon process that require the use of an alternate token will fail and this can't be remedied.
To fix this, I have modified the ICorRuntimeHost function in bofnet_execute.cpp by adding a call to CoInitializeSecurity. An entry for CoInitializeSecurity must be made in utils.h also.
I also added a call to CoUninitialize at the bottom of the function to close the COM library once BOF.NET is done with it. This was causing a further issue with the TrustedSec BOF's which would try to intialize COM and fail because BOF.NET had already initialized it but hadn't closed it.
static ICorRuntimeHost* loadCLR(bool v4){
BOF_LOCAL(OLE32, CoInitializeEx);
BOF_LOCAL(OLE32, CoCreateInstance);
BOF_LOCAL(OLE32, CLSIDFromString);
BOF_LOCAL(OLE32, CoUninitialize);
BOF_LOCAL(OLE32, CoInitializeSecurity);
BOF_LOCAL(KERNEL32, LoadLibraryA);
GUID IID_RTH, CLSID_RTH, IID_MH, CLSID_MH, CLSID_RH, IID_RH, IID_RHI;
HRESULT hr;
ICorRuntimeHost* result = nullptr;
ICLRMetaHost* pMetaHost = nullptr;
ICLRRuntimeInfo* pRuntimeInfo = nullptr;
ICLRRuntimeHost* pClrRuntimeHost = nullptr;
CLRCreateInstancePtr pCLRCreateInstance = nullptr;
HMODULE hMod = NULL;
CLSIDFromString(L"{cb2f6722-ab3a-11d2-9c40-00c04fa30a3e}", &IID_RTH);
CLSIDFromString(L"{cb2f6723-ab3a-11d2-9c40-00c04fa30a3e}", &CLSID_RTH);
CLSIDFromString(L"{d332db9e-b9b3-4125-8207-a14884f53216}", &IID_MH);
CLSIDFromString(L"{9280188D-0E8E-4867-B30C-7FA83884E8DE}", &CLSID_MH);
CLSIDFromString(L"{bd39d1d2-ba2f-486a-89b0-b4b0cb466891}", &IID_RHI);
CLSIDFromString(L"{90f1a06e-7712-4762-86b5-7a5eba6bdb02}", &CLSID_RH);
CLSIDFromString(L"{90f1a06c-7712-4762-86b5-7a5eba6bdb02}", &IID_RH);
if( (hMod = LoadLibraryA("mscoree.dll")) != NULL){
pCLRCreateInstance = (CLRCreateInstancePtr)GetProcAddress(hMod,"CLRCreateInstance");
if(pCLRCreateInstance == nullptr){
log("[=]Failed to get v2 ICorRuntimeHost: 0x%x, will try .NET 2 method", hr);
v4 = false;
}
}
hr = CoInitializeEx(nullptr, COINIT_MULTITHREADED);
hr = CoInitializeSecurity( //Failure of this function does not necessarily mean we failed to initialize, it will fail on repeated calls, but the values from the original call are retained
NULL,
-1,
NULL,
NULL,
RPC_C_AUTHN_LEVEL_DEFAULT,
RPC_C_IMP_LEVEL_IMPERSONATE,
NULL,
EOAC_DYNAMIC_CLOAKING,
NULL);
if(v4 && (hr = pCLRCreateInstance(CLSID_MH, IID_MH, (LPVOID*)&pMetaHost) == S_OK)){
if((hr = pMetaHost->GetRuntime(L"v4.0.30319", IID_RHI, (LPVOID*)&pRuntimeInfo)) == S_OK){
if((hr = pRuntimeInfo->GetInterface(CLSID_RH, IID_RH, (LPVOID*)&pClrRuntimeHost)) == S_OK){;
hr = pClrRuntimeHost->Start();
hr = pRuntimeInfo->GetInterface(CLSID_RTH, IID_RTH, (LPVOID *)&result);
}else{
log("Failed to get CLR runtime host: 0x%x", hr);
}
}else{
log("Failed to get v4 runtime info: 0x%x", hr);
}
}else{
if( (hr = CoCreateInstance(CLSID_RTH, nullptr, CLSCTX_ALL, IID_RTH,(LPVOID*)&result)) == S_OK){
hr = result->Start();
}else{
log("Failed to get v2 ICorRuntimeHost: 0x%x", hr);
}
}
CoUninitialize();
return result;
}
I have attempted to build the solution and although it successfully created BOFNET.dll and bofnet.cna, it did not create bofnet_execute.cpp.x64.obj. From the cobalt strike server, the cna script needs to be in the same repository as the .obj file.
Therefore, how are we expected to build the bofnet_execute.cpp.x64.obj file?
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.