2025-05-22 20:03:22 +02:00
|
|
|
import prologue, nanoid, json
|
2025-05-18 12:51:26 +02:00
|
|
|
import sequtils, strutils, times
|
2025-05-09 12:04:14 +02:00
|
|
|
|
2025-07-16 10:33:13 +02:00
|
|
|
import ./handlers
|
2025-07-15 23:26:54 +02:00
|
|
|
import ../../types
|
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
|
|
|
#[
|
|
|
|
|
POST /{listener-uuid}/register
|
|
|
|
|
Called from agent to register itself to the conquest server
|
|
|
|
|
]#
|
|
|
|
|
proc register*(ctx: Context) {.async.} =
|
|
|
|
|
|
|
|
|
|
# Check headers
|
2025-05-13 23:42:04 +02:00
|
|
|
# If POST data is not JSON data, return 404 error code
|
|
|
|
|
if ctx.request.contentType != "application/json":
|
|
|
|
|
resp "", Http404
|
|
|
|
|
return
|
2025-05-12 21:53:37 +02:00
|
|
|
|
2025-05-13 23:42:04 +02:00
|
|
|
# The JSON data for the agent registration has to be in the following format
|
2025-05-12 21:53:37 +02:00
|
|
|
#[
|
|
|
|
|
{
|
|
|
|
|
"username": "username",
|
|
|
|
|
"hostname":"hostname",
|
2025-05-14 15:48:01 +02:00
|
|
|
"domain": "domain.local",
|
2025-05-12 21:53:37 +02:00
|
|
|
"ip": "ip-address",
|
2025-05-13 23:42:04 +02:00
|
|
|
"os": "operating-system",
|
2025-05-14 12:42:23 +02:00
|
|
|
"process": "agent.exe",
|
2025-05-13 23:42:04 +02:00
|
|
|
"pid": 1234,
|
2025-05-29 14:19:55 +02:00
|
|
|
"elevated": false.
|
|
|
|
|
"sleep": 10
|
2025-05-12 21:53:37 +02:00
|
|
|
}
|
|
|
|
|
]#
|
|
|
|
|
|
2025-05-13 23:42:04 +02:00
|
|
|
try:
|
|
|
|
|
let
|
|
|
|
|
postData: JsonNode = parseJson(ctx.request.body)
|
2025-05-14 12:42:23 +02:00
|
|
|
agentRegistrationData: AgentRegistrationData = postData.to(AgentRegistrationData)
|
|
|
|
|
agentUuid: string = generate(alphabet=join(toSeq('A'..'Z'), ""), size=8)
|
|
|
|
|
listenerUuid: string = ctx.getPathParams("listener")
|
2025-05-23 13:55:00 +02:00
|
|
|
date: DateTime = now()
|
2025-05-13 23:42:04 +02:00
|
|
|
|
2025-05-14 12:42:23 +02:00
|
|
|
let agent: Agent = newAgent(agentUuid, listenerUuid, date, agentRegistrationData)
|
2025-05-13 23:42:04 +02:00
|
|
|
|
|
|
|
|
# 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
|
2025-05-12 21:53:37 +02:00
|
|
|
|
2025-05-13 23:42:04 +02:00
|
|
|
except CatchableError:
|
|
|
|
|
# JSON data is invalid or does not match the expected format (described above)
|
|
|
|
|
resp "", Http404
|
2025-05-12 21:53:37 +02:00
|
|
|
|
2025-05-13 23:42:04 +02:00
|
|
|
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-05-09 12:04:14 +02:00
|
|
|
|
2025-05-22 20:03:22 +02:00
|
|
|
let tasksJson = getTasks(listener, agent)
|
|
|
|
|
|
|
|
|
|
# If agent/listener is invalid, return a 404 Not Found error code
|
|
|
|
|
if tasksJson == nil:
|
|
|
|
|
resp "", Http404
|
|
|
|
|
|
|
|
|
|
# Return all currently active tasks as a JsonObject
|
|
|
|
|
resp jsonResponse(tasksJson)
|
2025-05-12 21:53:37 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
#[
|
2025-05-22 20:03:22 +02:00
|
|
|
POST /{listener-uuid}/{agent-uuid}/{task-uuid}/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
|
|
|
let
|
|
|
|
|
listener = ctx.getPathParams("listener")
|
|
|
|
|
agent = ctx.getPathParams("agent")
|
|
|
|
|
task = ctx.getPathParams("task")
|
2025-05-12 21:53:37 +02:00
|
|
|
|
2025-05-22 20:03:22 +02:00
|
|
|
# Check headers
|
|
|
|
|
# If POST data is not JSON data, return 404 error code
|
|
|
|
|
if ctx.request.contentType != "application/json":
|
|
|
|
|
resp "", Http404
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
let
|
|
|
|
|
taskResultJson: JsonNode = parseJson(ctx.request.body)
|
2025-05-29 15:26:50 +02:00
|
|
|
taskResult: TaskResult = taskResultJson.to(TaskResult)
|
2025-05-22 20:03:22 +02:00
|
|
|
|
|
|
|
|
# Handle and display task result
|
|
|
|
|
handleResult(listener, agent, task, taskResult)
|
|
|
|
|
|
|
|
|
|
except CatchableError:
|
|
|
|
|
# JSON data is invalid or does not match the expected format (described above)
|
|
|
|
|
resp "", Http404
|
|
|
|
|
|
|
|
|
|
return
|