Documentation Index
Fetch the complete documentation index at: https://mintlify.com/HavocFramework/Havoc/llms.txt
Use this file to discover all available pages before exploring further.
Overview
Thedotnet command provides capabilities for executing .NET assemblies directly within the Demon process. It bootstraps the Common Language Runtime (CLR) and provides in-memory execution of managed code.
Syntax
Subcommands
list-versions
Enumerate all installed .NET Framework versions on the target system.inline-execute
Execute a .NET assembly in-memory within the current Demon process.Local path to the .NET assembly (DLL or EXE) to execute
Command-line arguments to pass to the assembly’s entry point
How It Works
Theinline-execute command follows this execution flow:
- CLR Bootstrap: Creates an instance of the CLR (v4.0.30319 by default) within the Demon process
- AMSI Bypass: Loads
amsi.dlland patches it in-memory to bypass AMSI scanning - AppDomain Creation: Creates an AppDomain named “DefaultDomain”
- Assembly Load: Loads the assembly into memory from the uploaded bytes
- Entry Point Discovery: Finds the assembly’s entry point method
- Execution: Invokes the entry point with supplied arguments
- Output Capture: Captures console output and returns it to the teamserver
Return Values
Execution status:
DOTNET_INFO_PATCHED(0x1) - AMSI successfully patchedDOTNET_INFO_NET_VERSION(0x2) - CLR version informationDOTNET_INFO_ENTRYPOINT(0x3) - Entry point found and executingDOTNET_INFO_FINISHED(0x4) - Execution completedDOTNET_INFO_FAILED(0x5) - Execution failed
Captured console output from the assembly execution
Examples
List Installed .NET Versions
Execute Seatbelt
Execute Rubeus
Execute SharpHound
Execute Custom .NET Tool
Execute Without Arguments
OPSEC Considerations
Indicators of Compromise
- CLR Loading: CLR loaded into unexpected process (e.g., explorer.exe)
- AMSI Patching: In-memory modification of amsi.dll
- AppDomain Creation: New AppDomain created in non-.NET process
- Assembly Load Events: ETW events for assembly loading
- JIT Compilation: Memory regions with JIT-compiled code
Detection Vectors
- CLR in Unusual Processes: Beacon processes shouldn’t normally host the CLR
- AMSI Patch Signatures: Memory scanning for known AMSI bypass patterns
- ETW Telemetry: Microsoft-Windows-DotNETRuntime provider events
- Image Load Events: clr.dll, clrjit.dll loading into unexpected processes
Mitigation Strategies
- Fork & Run
- In-Process (Current)
Use external modules like Advantages:
InvokeAssembly that execute in sacrificial processes:- CLR loaded in sacrificial process
- Beacon process remains clean
- Process can be killed after execution
Best Practices
- Use Sparingly: Only execute .NET assemblies when necessary
- Short-Lived Sessions: Consider using a separate agent for .NET execution
- Clean Processes: Execute in sacrificial processes when possible (use modules)
- Monitor Detection: Be aware that CLR loading may trigger alerts
- Test First: Validate assemblies in lab environments
Permanent Impact
Implications
- CLR remains loaded for the lifetime of the Demon process
- Subsequent
dotnet inline-executecalls reuse the existing CLR instance - AppDomains are reused across executions
- Memory footprint increases and persists
- Process may behave differently under analysis
When to Use
Good Use Cases:- Executing multiple .NET tools in succession
- When speed is critical
- In compromised environments with weak detection
- When you don’t care about CLR indicators
- Operating in heavily monitored environments
- Maintaining long-term access
- Executing a single .NET tool (use fork & run instead)
- Advanced EDR is present
Assembly Requirements
Compatible Assemblies
- .NET Framework assemblies (not .NET Core/.NET 5+)
- Assemblies targeting v4.0.30319 or earlier
- Executables (EXE) with entry point methods
- Class libraries (DLL) with defined entry points
Unsupported
- .NET Core / .NET 5+ assemblies
- Assemblies with unmanaged dependencies
- Assemblies requiring specific CLR versions outside v4.0.30319
Output Capture
Console output from the assembly is automatically captured and returned:Console.WriteLine()output is captured- Error streams are captured
- Output is returned via named pipe to teamserver
- Large outputs are handled in chunks
CLR Configuration
The CLR is initialized with:- Version: v4.0.30319 (hardcoded)
- AppDomain: “DefaultDomain”
- Pipe Name: Generated using template from teamserver config
Related Commands
inline-execute- Execute BOF/COFF files (different from .NET)- External modules:
InvokeAssembly- Execute .NET in sacrificial processPowerpick- Execute PowerShell (also loads CLR)
Troubleshooting
Assembly Failed to Load
- Verify assembly is .NET Framework (not Core)
- Check assembly is not corrupted
- Ensure assembly targets compatible framework version
No Output Returned
- Assembly may not write to console
- Check assembly executed successfully (look for DOTNET_INFO_FINISHED)
- Verify pipe communication is working
Execution Hangs
- Assembly may be waiting for user input
- Long-running operations may appear as hangs
- Check
job listfor active jobs
Notes
- Assembly files are chunked for upload (max 30MB per chunk)
- AMSI bypass is applied automatically before execution
- Assembly execution is performed in a job thread
- Arguments are passed as a single string to the Main() method
- The AppDomain name is “DefaultDomain” by default
- Multiple assemblies can be executed sequentially in the same CLR instance
