From ee93445739efe7491eefe27f5415bd47236d6eec Mon Sep 17 00:00:00 2001 From: Jakob Friedl <71284620+jakobfriedl@users.noreply.github.com> Date: Wed, 13 Aug 2025 21:42:58 +0200 Subject: [PATCH] Refine profile structure. --- data/profile.toml | 53 +++++++++++++++++++++++++++++++++----- src/server/core/server.nim | 45 +++++++++++++++++--------------- src/server/db/database.nim | 4 +-- 3 files changed, 73 insertions(+), 29 deletions(-) diff --git a/data/profile.toml b/data/profile.toml index 5d7d2f8..c2c200e 100644 --- a/data/profile.toml +++ b/data/profile.toml @@ -1,37 +1,78 @@ # Conquest default configuration file +# https://hstechdocs.helpsystems.com/manuals/cobaltstrike/current/userguide/content/topics/malleable-c2_profile-language.htm#_Toc65482837 -name = "cq-default-config" +name = "cq-default-profile" +# Important file paths and locations conquest_directory = "/mnt/c/Users/jakob/Documents/Projects/conquest" private_key_file = "/mnt/c/Users/jakob/Documents/Projects/conquest/data/keys/conquest-server_x25519_private.key" database_file = "/mnt/c/Users/jakob/Documents/Projects/conquest/data/conquest.db" +# General agent settings [agent] sleep = 5 user_agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36" +# ---------------------------------------------------------- +# HTTP GET +# ---------------------------------------------------------- +# Defines URI endpoints for HTTP GET requests [http-get] uri = [ "/tasks", "/api/v1.2/status.js" ] -[http-get.agent.headers] -Content-Type = "text/plain" -Authorization = { encoding = "base64url", prepend = "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.", append = ".KMUFsIDTnFmyG3nMiGM6H9FNFUROf3wh7SmqJp-QV30" } +# Defines where the heartbeat is placed within the HTTP GET request +# Allows for data transformation using encoding (base64, base64url, ...), appending and prepending of strings +# Metadata can be stored in a Header (e.g. JWT Token, Session Cookie), URI parameter, appended to the URI or request body +[http-get.agent.heartbeat] +encoding = "base64url" +prepend = "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9." +append = ".KMUFsIDTnFmyG3nMiGM6H9FNFUROf3wh7SmqJp-QV30" +placement = { type = "header", name = "Authorization" } +# placement = { type = "header", name = "Cookie" } +# placement = { type = "parameter", name = "id" } +# placement = { type = "uri-append" } +# placement = { type = "body" } +# Defines arbitrary URI parameters that are added to the request +[http-get.agent.parameters] + +# Defines arbitrary headers that are added by the agent when performing a HTTP GET request +[http-get.agent.headers] +Cache-Control = "no-cache" + +# Defines arbitrary headers that are added by the server [http-get.server.headers] Server = "nginx" +X-CONQUEST-VERSION = "0.1" +# Defines how the server's response to the task retrieval request is rendered +# Allows same data transformation options as the agent metadata, allowing it to be embedded in benign content +[http-get.server.output] +placement = { type = "body" } + +# ---------------------------------------------------------- +# HTTP POST +# ---------------------------------------------------------- +# Defines URI endpoints for HTTP POST requests [http-post] uri = [ "/results", "/api/v2/get.js" ] +request_methods = [ + "POST", + "PUT" +] [http-post.agent.headers] -Content-Type = "application/octet-stream" +Cache-Control = "no-cache" [http-post.server.headers] Server = "nginx" -Accept = "application/octet-stream" \ No newline at end of file +X-CONQUEST-VERSION = "0.1" + +[http-post.server.output] +placement = { type = "body" } \ No newline at end of file diff --git a/src/server/core/server.nim b/src/server/core/server.nim index 0163114..6644614 100644 --- a/src/server/core/server.nim +++ b/src/server/core/server.nim @@ -119,13 +119,13 @@ proc handleConsoleCommand(cq: Conquest, args: string) = cq.writeLine("") -proc header(cq: Conquest) = - cq.writeLine("") - cq.writeLine("┏┏┓┏┓┏┓┓┏┏┓┏╋") - cq.writeLine("┗┗┛┛┗┗┫┗┻┗ ┛┗ V0.1") - cq.writeLine(" ┗ @jakobfriedl") - cq.writeLine("─".repeat(21)) - cq.writeLine("") +proc header() = + echo "" + echo "┏┏┓┏┓┏┓┓┏┏┓┏╋" + echo "┗┗┛┛┗┗┫┗┻┗ ┛┗ V0.1" + echo " ┗ @jakobfriedl" + echo "─".repeat(21) + echo "" proc init*(T: type Conquest, profile: Profile): Conquest = var cq = new Conquest @@ -141,33 +141,36 @@ proc init*(T: type Conquest, profile: Profile): Conquest = return cq -proc startServer*(profile: string) = +proc startServer*(profilePath: string) = # Handle CTRL+C, proc exit() {.noconv.} = echo "Received CTRL+C. Type \"exit\" to close the application.\n" setControlCHook(exit) - let profile = parseFile(profile).getTable - # # dump table.getTable() - # let headers = table["http-get"]["agent"]["headers"].getTable() - # for key, value in headers: - # if value.kind == TomlValueKind.Table: - # echo value["encoding"] - # echo value["append"] - # echo value["prepend"] - # echo key + header() - # Initialize framework try: + # Load and parse profile + let profile = parseFile(profilePath).getTable + styledEcho(fgGreen, styleBright, "[+] Using profile \"", profile["name"].getStr(), "\" (", profilePath ,").") + styledEcho(fgGreen, styleBright, "[+] ", profile["private_key_file"].getStr(), ": Private key found.") + + # # dump table.getTable() + # let headers = table["http-get"]["agent"]["headers"].getTable() + # for key, value in headers: + # if value.kind == TomlValueKind.Table: + # echo value["encoding"] + # echo value["append"] + # echo value["prepend"] + # echo key + + # Initialize framework context cq = Conquest.init(profile) except CatchableError as err: echo err.msg quit(0) - - # Print header - cq.header() # Initialize database cq.dbInit() diff --git a/src/server/db/database.nim b/src/server/db/database.nim index fd1d44f..e74648a 100644 --- a/src/server/db/database.nim +++ b/src/server/db/database.nim @@ -41,7 +41,7 @@ proc dbInit*(cq: Conquest) = """) - cq.writeLine(fgGreen, "[+] ", cq.dbPath, ": Database created.") + cq.writeLine(fgGreen, styleBright, "[+] ", cq.dbPath, ": Database created.") conquestDb.close() except SqliteError as err: - cq.writeLine(fgGreen, "[+] ", cq.dbPath, ": Database file found.") + cq.writeLine(fgGreen, styleBright, "[+] ", cq.dbPath, ": Database file found.")