A custom .NET Framework payload agent for the Tuoni C2 framework. This project consists of two components: a .NET Framework agent template (the executable that runs on target machines) and a Java/Gradle plugin that packages the agent for deployment through the Tuoni server.
tuoni-dotnet-agent/
├── DotNetAgent/ # .NET Framework 4.6.2 payload agent template (C#)
│ ├── Program.cs # Entry point
│ ├── Encryption.cs # RSA + AES-GCM encryption
│ ├── GlobalConf.cs # PE overlay configuration extraction
│ ├── Listener.cs # C2 message handler
│ ├── ListenerManager.cs # Listener lifecycle management
│ ├── Logger.cs # Debug logging
│ ├── MessagesManager.cs # Central command dispatcher
│ ├── Metadata.cs # System information collection
│ ├── NamedPipeCommunication.cs # IPC via named pipes
│ ├── NativeCommand.cs # Built-in command execution
│ ├── NativeCommandLsHelper.cs # Directory listing helper
│ ├── NativeCommandPsHelper.cs # Process listing helper
│ ├── PluginCommand.cs # Plugin shellcode communication
│ ├── PluginExecution.cs # Shellcode execution via VirtualAlloc
│ ├── ProcessRunner.cs # Process spawning with output streaming
│ ├── TLV.cs # Type-Length-Value protocol
│ ├── DotNetAgent.csproj # MSBuild project file
│ ├── DotNetAgent.sln # Visual Studio solution
│ └── App.config # .NET Framework runtime config
│
└── DotNetAgentPlugin/ # Tuoni plugin (Java/Gradle)
├── src/main/java/com/shelldot/tuoni/examples/plugin/dotnetpayload/
│ ├── DotnetPayloadPlugin.java # Plugin entry point
│ ├── DotnetPayloadPluginTemplate.java # Payload template & serialization
│ ├── DotnetPayloadPluginConfiguration.java # Configuration schema
│ ├── configuration/
│ │ ├── JacksonJsonConfiguration.java # JSON config adapter
│ │ └── SimpleConfigurationSchema.java # Schema wrapper
│ └── utils/
│ └── ShellcodeUtil.java # Binary resource loader
├── src/main/resources/
│ ├── META-INF/services/ # SPI service registration
│ └── templates/ # Embedded DotNetAgent.exe (built from DotNetAgent/)
├── build.gradle.kts # Gradle build (Kotlin DSL)
├── settings.gradle.kts # Gradle settings
├── gradle.properties # Build optimization flags
└── gradle/libs.versions.toml # Dependency version catalog
| Software | Version | Notes |
|---|---|---|
| Windows | 10/11 or Server 2016+ | The agent uses Windows-only APIs (P/Invoke to kernel32, ntdll, advapi32, bcrypt) |
| Visual Studio | 2022 or later | With ".NET desktop development" workload installed |
| .NET Framework Targeting Pack | 4.6.2 | Included with VS .NET desktop workload, or install separately |
| MSBuild | 15.0+ | Included with Visual Studio; also available via Build Tools for Visual Studio |
| Java JDK | 21 | Required for building the Tuoni plugin |
| Gradle | 9.1+ | Or use the included Gradle wrapper (gradlew / gradlew.bat) |
Using Visual Studio:
- Open
DotNetAgent/DotNetAgent.slnin Visual Studio - Set the build configuration to Release
- Build the solution (Ctrl+Shift+B)
Using MSBuild from command line:
cd DotNetAgent
msbuild DotNetAgent.csproj /p:Configuration=ReleaseUsing Developer Command Prompt:
cd DotNetAgent
msbuild /p:Configuration=ReleaseThe compiled executable will be at: DotNetAgent/bin/Release/DotNetAgent.exe
The Gradle build automatically copies DotNetAgent.exe from the Release output into the JAR. You must complete Step 1 first.
Using the Gradle wrapper (recommended):
cd DotNetAgentPlugin
./gradlew buildOn Windows (CMD):
cd DotNetAgentPlugin
gradlew.bat buildThe plugin JAR will be at: DotNetAgentPlugin/build/libs/tuoni-example-plugin-dotnet-payload-0.0.1.jar
The entire project can be built inside Docker using the provided Makefile. This requires only Docker and Make — no Windows, Visual Studio, or Java installation needed.
# Build the plugin JAR and agent EXE
make build
# Build and install to Tuoni server (copies JAR to /srv/tuoni/plugins/server/ and restarts)
make install
# Remove build artifacts
make clean
# List all available targets
make helpBuild outputs are extracted to the build/ directory:
build/tuoni-example-plugin-dotnet-payload-0.0.1.jar— the plugin JARbuild/DotNetAgent.exe— the compiled .NET agent
| Artifact | Path | Description |
|---|---|---|
| Agent EXE | DotNetAgent/bin/Release/DotNetAgent.exe |
The .NET payload executable |
| Plugin JAR (fat) | DotNetAgentPlugin/build/libs/tuoni-example-plugin-dotnet-payload-0.0.1.jar |
Shadow JAR with all dependencies, ready for Tuoni server |
| Plugin JAR (shallow) | DotNetAgentPlugin/build/libs/dotnet-payload-plugin-0.0.1-shallow.jar |
JAR without bundled dependencies (not for deployment) |
- Build both the agent and plugin JAR as described above
- Copy
tuoni-example-plugin-dotnet-payload-0.0.1.jarto your Tuoni server's plugin directory - The plugin registers itself with the following metadata:
- Plugin ID:
shelldot.payloads.examples.dotnetpayload - Plugin Name:
.NET Payload Plugin - Plugin Version:
0.0.1 - Plugin Provider:
shelldot - Payload Template:
custom-dotnet-payload - Target Platform: Windows x64
- Plugin ID:
For more details on deploying plugins, see the Tuoni documentation.
The agent uses a two-layer architecture that separates network communication from command execution:
┌──────────────┐ ┌───────────────────────┐ ┌──────────────────┐
│ Tuoni C2 │◄───────►│ Listener Shellcode │◄───────►│ .NET Agent │
│ Server │ network │ (injected at deploy) │ named │ (DotNetAgent.exe)│
│ │ │ │ pipe │ │
└──────────────┘ └───────────────────────┘ (IPC) └──────────────────┘
- Tuoni C2 Server — sends commands and receives results over the network
- Listener Shellcode — a shellcode blob provided by the Tuoni framework at deployment time; handles network communication with the C2 server and relays messages to/from the .NET agent via a named pipe
- .NET Agent — the core payload; receives commands over the named pipe, executes them, and queues results for the listener to pick up
The agent uses a hybrid encryption scheme:
- RSA (asymmetric) — used only for the initial metadata exchange. The C2 server's public key is embedded in the agent's configuration. The agent encrypts its metadata (which includes a freshly generated AES key) using this public key.
- AES-GCM (symmetric) — used for all subsequent communication. A random 128-bit key is generated at startup. Each message uses a random 12-byte IV/nonce and produces a 16-byte authentication tag. Encryption is performed via Windows CNG (
bcrypt.dll) P/Invoke calls.
This project is licensed under the MIT License.