Files
conquest/src/server/api/routes.nim

129 lines
3.9 KiB
Nim
Raw Normal View History

import prologue, json, terminal, strformat
import sequtils, strutils, times, base64
2025-07-16 10:33:13 +02:00
import ./handlers
import ../[utils, globals]
import ../../common/[types, utils]
proc error404*(ctx: Context) {.async.} =
resp "", Http404
2025-05-12 21:53:37 +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
# If POST data is not binary data, return 404 error code
if ctx.request.contentType != "application/octet-stream":
resp "", Http404
return
2025-05-12 21:53:37 +02:00
try:
let agentId = register(ctx.request.body.toBytes())
resp "Ok", Http200
2025-05-12 21:53:37 +02:00
except CatchableError:
resp "", Http404
2025-05-12 21:53:37 +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-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.} =
let
listener = ctx.getPathParams("listener")
agent = ctx.getPathParams("agent")
try:
var response: seq[byte]
let tasks: seq[seq[byte]] = getTasks(listener, agent)
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.")
except CatchableError:
resp "", Http404
2025-05-12 21:53:37 +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.} =
# Check headers
# If POST data is not binary data, return 404 error code
if ctx.request.contentType != "application/octet-stream":
resp "", Http404
return
try:
handleResult(ctx.request.body.toBytes())
except CatchableError:
resp "", Http404
return