Refine profile structure.

This commit is contained in:
Jakob Friedl
2025-08-13 21:42:58 +02:00
parent 415cd7ebf8
commit ee93445739
3 changed files with 73 additions and 29 deletions

View File

@@ -1,37 +1,78 @@
# Conquest default configuration file # 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" 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" 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" database_file = "/mnt/c/Users/jakob/Documents/Projects/conquest/data/conquest.db"
# General agent settings
[agent] [agent]
sleep = 5 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" 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] [http-get]
uri = [ uri = [
"/tasks", "/tasks",
"/api/v1.2/status.js" "/api/v1.2/status.js"
] ]
[http-get.agent.headers] # Defines where the heartbeat is placed within the HTTP GET request
Content-Type = "text/plain" # Allows for data transformation using encoding (base64, base64url, ...), appending and prepending of strings
Authorization = { encoding = "base64url", prepend = "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.", append = ".KMUFsIDTnFmyG3nMiGM6H9FNFUROf3wh7SmqJp-QV30" } # 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] [http-get.server.headers]
Server = "nginx" 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] [http-post]
uri = [ uri = [
"/results", "/results",
"/api/v2/get.js" "/api/v2/get.js"
] ]
request_methods = [
"POST",
"PUT"
]
[http-post.agent.headers] [http-post.agent.headers]
Content-Type = "application/octet-stream" Cache-Control = "no-cache"
[http-post.server.headers] [http-post.server.headers]
Server = "nginx" Server = "nginx"
Accept = "application/octet-stream" X-CONQUEST-VERSION = "0.1"
[http-post.server.output]
placement = { type = "body" }

View File

@@ -119,13 +119,13 @@ proc handleConsoleCommand(cq: Conquest, args: string) =
cq.writeLine("") cq.writeLine("")
proc header(cq: Conquest) = proc header() =
cq.writeLine("") echo ""
cq.writeLine("┏┏┓┏┓┏┓┓┏┏┓┏╋") echo "┏┏┓┏┓┏┓┓┏┏┓┏╋"
cq.writeLine("┗┗┛┛┗┗┫┗┻┗ ┛┗ V0.1") echo "┗┗┛┛┗┗┫┗┻┗ ┛┗ V0.1"
cq.writeLine(" ┗ @jakobfriedl") echo " ┗ @jakobfriedl"
cq.writeLine("".repeat(21)) echo "".repeat(21)
cq.writeLine("") echo ""
proc init*(T: type Conquest, profile: Profile): Conquest = proc init*(T: type Conquest, profile: Profile): Conquest =
var cq = new Conquest var cq = new Conquest
@@ -141,33 +141,36 @@ proc init*(T: type Conquest, profile: Profile): Conquest =
return cq return cq
proc startServer*(profile: string) = proc startServer*(profilePath: string) =
# Handle CTRL+C, # Handle CTRL+C,
proc exit() {.noconv.} = proc exit() {.noconv.} =
echo "Received CTRL+C. Type \"exit\" to close the application.\n" echo "Received CTRL+C. Type \"exit\" to close the application.\n"
setControlCHook(exit) setControlCHook(exit)
let profile = parseFile(profile).getTable header()
# # 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
try: 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) cq = Conquest.init(profile)
except CatchableError as err: except CatchableError as err:
echo err.msg echo err.msg
quit(0) quit(0)
# Print header
cq.header()
# Initialize database # Initialize database
cq.dbInit() cq.dbInit()

View File

@@ -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() conquestDb.close()
except SqliteError as err: except SqliteError as err:
cq.writeLine(fgGreen, "[+] ", cq.dbPath, ": Database file found.") cq.writeLine(fgGreen, styleBright, "[+] ", cq.dbPath, ": Database file found.")