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

View File

@@ -1,45 +0,0 @@
import ./[shell, sleep, filesystem]
export shell, sleep, filesystem
#[
"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)
[ ] 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

@@ -1,87 +0,0 @@
import nanoid, sequtils, strutils, strformat, terminal, times
import ../../types
proc taskGetWorkingDirectory*(cq: Conquest) =
# Create a new task
let
date: string = now().format("dd-MM-yyyy HH:mm:ss")
task = Task(
id: generate(alphabet=join(toSeq('A'..'Z'), ""), size=8),
agent: cq.interactAgent.name,
command: GetWorkingDirectory,
args: @[],
)
# Add new task to the agent's task queue
cq.interactAgent.tasks.add(task)
cq.writeLine(fgBlack, styleBright, fmt"[{date}] [*] ", resetStyle, "Tasked agent to get current working directory.")
proc taskSetWorkingDirectory*(cq: Conquest, arguments: seq[string]) =
# Create a new task
let
date: string = now().format("dd-MM-yyyy HH:mm:ss")
task = Task(
id: generate(alphabet=join(toSeq('A'..'Z'), ""), size=8),
agent: cq.interactAgent.name,
command: SetWorkingDirectory,
args: arguments,
)
# Add new task to the agent's task queue
cq.interactAgent.tasks.add(task)
cq.writeLine(fgBlack, styleBright, fmt"[{date}] [*] ", resetStyle, fmt"Tasked agent to change current working directory.")
proc taskListDirectory*(cq: Conquest, arguments: seq[string]) =
# Create a new task
let
date: string = now().format("dd-MM-yyyy HH:mm:ss")
task = Task(
id: generate(alphabet=join(toSeq('A'..'Z'), ""), size=8),
agent: cq.interactAgent.name,
command: ListDirectory,
args: arguments,
)
# Add new task to the agent's task queue
cq.interactAgent.tasks.add(task)
cq.writeLine(fgBlack, styleBright, fmt"[{date}] [*] ", resetStyle, fmt"Tasked agent to list files and directories.")
proc taskRemoveFile*(cq: Conquest, arguments: seq[string]) =
# Create a new task
let
date: string = now().format("dd-MM-yyyy HH:mm:ss")
task = Task(
id: generate(alphabet=join(toSeq('A'..'Z'), ""), size=8),
agent: cq.interactAgent.name,
command: RemoveFile,
args: arguments,
)
# Add new task to the agent's task queue
cq.interactAgent.tasks.add(task)
cq.writeLine(fgBlack, styleBright, fmt"[{date}] [*] ", resetStyle, fmt"Tasked agent to remove file.")
proc taskRemoveDirectory*(cq: Conquest, arguments: seq[string]) =
# Create a new task
let
date: string = now().format("dd-MM-yyyy HH:mm:ss")
task = Task(
id: generate(alphabet=join(toSeq('A'..'Z'), ""), size=8),
agent: cq.interactAgent.name,
command: RemoveDirectory,
args: arguments,
)
# Add new task to the agent's task queue
cq.interactAgent.tasks.add(task)
cq.writeLine(fgBlack, styleBright, fmt"[{date}] [*] ", resetStyle, fmt"Tasked agent to remove directory.")

View File

@@ -1,19 +0,0 @@
import nanoid, sequtils, strutils, strformat, terminal, times
import ../../types
proc taskExecuteShell*(cq: Conquest, arguments: seq[string]) =
# Create a new task
let
date: string = now().format("dd-MM-yyyy HH:mm:ss")
task = Task(
id: generate(alphabet=join(toSeq('A'..'Z'), ""), size=8),
agent: cq.interactAgent.name,
command: ExecuteShell,
args: arguments,
)
# Add new task to the agent's task queue
cq.interactAgent.tasks.add(task)
cq.writeLine(fgBlack, styleBright, fmt"[{date}] [*] ", resetStyle, "Tasked agent to execute shell command.")

View File

@@ -1,28 +0,0 @@
import nanoid, sequtils, strutils, strformat, terminal, times
import ../../types
import ../../db/database
proc taskExecuteSleep*(cq: Conquest, delay: int) =
if delay < 0:
cq.writeLine(fgRed, styleBright, "[-] Invalid sleep delay value.")
return
# Update 'sleep' value in database
if not cq.dbUpdateSleep(cq.interactAgent.name, delay):
return
# Create a new task
let
date: string = now().format("dd-MM-yyyy HH:mm:ss")
task = Task(
id: generate(alphabet=join(toSeq('A'..'Z'), ""), size=8),
agent: cq.interactAgent.name,
command: Sleep,
args: @[$delay],
)
# Add new task to the agent's task queue
cq.interactAgent.tasks.add(task)
cq.writeLine(fgBlack, styleBright, fmt"[{date}] [*] ", resetStyle, "Tasked agent to update sleep settings.")

View File

@@ -1,5 +1,5 @@
import argparse, times, strformat, terminal, nanoid
import ./commands/commands
import ./task
import ../[types]
#[

48
server/agent/task.nim Normal file
View File

@@ -0,0 +1,48 @@
import nanoid, sequtils, strutils, strformat, terminal, times
import ../types
import ../db/database
# Generic task creation procedure
proc createTask(cq: Conquest, command: TaskCommand, args: seq[string], message: string) =
let
date = now().format("dd-MM-yyyy HH:mm:ss")
task = Task(
id: generate(alphabet=join(toSeq('A'..'Z'), ""), size=8),
agent: cq.interactAgent.name,
command: command,
args: args,
)
cq.interactAgent.tasks.add(task)
cq.writeLine(fgBlack, styleBright, fmt"[{date}] [*] ", resetStyle, message)
# Agent task functions
proc taskExecuteSleep*(cq: Conquest, delay: int) =
if delay < 0:
cq.writeLine(fgRed, styleBright, "[-] Invalid sleep delay value.")
return
# Update 'sleep' value in database
if not cq.dbUpdateSleep(cq.interactAgent.name, delay):
return
# Use the generic createTask function
createTask(cq, Sleep, @[$delay], "Tasked agent to update sleep settings.")
proc taskExecuteShell*(cq: Conquest, arguments: seq[string]) =
cq.createTask(ExecuteShell, arguments, "Tasked agent to execute shell command.")
proc taskGetWorkingDirectory*(cq: Conquest) =
cq.createTask(GetWorkingDirectory, @[], "Tasked agent to get current working directory.")
proc taskSetWorkingDirectory*(cq: Conquest, arguments: seq[string]) =
cq.createTask(SetWorkingDirectory, arguments, "Tasked agent to change current working directory.")
proc taskListDirectory*(cq: Conquest, arguments: seq[string]) =
cq.createTask(ListDirectory, arguments, "Tasked agent to list files and directories.")
proc taskRemoveFile*(cq: Conquest, arguments: seq[string]) =
cq.createTask(RemoveFile, arguments, "Tasked agent to remove file.")
proc taskRemoveDirectory*(cq: Conquest, arguments: seq[string]) =
cq.createTask(RemoveDirectory, arguments, "Tasked agent to remove directory.")