Implement listing agents; Add TODOs for further improvements

This commit is contained in:
Jakob Friedl
2025-05-14 12:42:23 +02:00
parent c4cbcecafa
commit 826aacafad
9 changed files with 93 additions and 29 deletions

View File

@@ -1,5 +1,5 @@
import terminal, strformat, times
import ../[types, globals]
import terminal, strformat
import ../[types, globals, utils]
import ../db/database
@@ -23,7 +23,8 @@ Options:
-h, --help""")
proc agentList*(cq: Conquest, args: varargs[string]) =
discard
let agents = cq.dbGetAllAgents()
cq.drawTable(agents)
proc agentBuild*(cq: Conquest, args: varargs[string]) =
discard
@@ -44,8 +45,6 @@ proc agentInteract*(cq: Conquest, args: varargs[string]) =
]#
proc register*(agent: Agent): bool =
let date: string = now().format("dd-MM-yyyy HH:mm:ss")
# The following line is required to be able to use the `cq` global variable for console output
{.cast(gcsafe).}:
@@ -62,7 +61,7 @@ proc register*(agent: Agent): bool =
return false
cq.add(agent.name, agent)
cq.writeLine(fgYellow, styleBright, fmt"[{date}] ", resetStyle, "Agent ", fgYellow, styleBright, agent.name, resetStyle, " connected to listener ", fgGreen, styleBright, agent.listener, resetStyle, ": ", fgYellow, styleBright, fmt"{agent.username}@{agent.hostname}", "\n")
cq.writeLine(fgYellow, styleBright, fmt"[{agent.firstCheckin}] ", resetStyle, "Agent ", fgYellow, styleBright, agent.name, resetStyle, " connected to listener ", fgGreen, styleBright, agent.listener, resetStyle, ": ", fgYellow, styleBright, fmt"{agent.username}@{agent.hostname}", "\n")
return true
#[

View File

@@ -1,2 +0,0 @@
# Compiler flags
--threads:on

View File

@@ -21,7 +21,8 @@ proc dbInit*(cq: Conquest) =
CREATE TABLE agents (
name TEXT PRIMARY KEY,
listener TEXT NOT NULL,
listener TEXT NOT NULL,
process TEXT NOT NULL,
pid INTEGER NOT NULL,
username TEXT NOT NULL,
hostname TEXT NOT NULL,
@@ -30,6 +31,7 @@ proc dbInit*(cq: Conquest) =
elevated BOOLEAN NOT NULL,
sleep INTEGER DEFAULT 10,
jitter REAL DEFAULT 0.1,
firstCheckin DATETIME NOT NULL,
FOREIGN KEY (listener) REFERENCES listeners(name)
);
@@ -40,6 +42,9 @@ proc dbInit*(cq: Conquest) =
except SqliteError:
cq.writeLine(fgGreen, "[+] ", cq.dbPath, ": Database file found.")
#[
Listeners
]#
proc dbStoreListener*(cq: Conquest, listener: Listener): bool =
try:
@@ -108,15 +113,18 @@ proc listenerExists*(cq: Conquest, listenerName: string): bool =
cq.writeLine(fgRed, styleBright, "[-] ", getCurrentExceptionMsg())
return false
#[
Agents
]#
proc dbStoreAgent*(cq: Conquest, agent: Agent): bool =
try:
let conquestDb = openDatabase(cq.dbPath, mode=dbReadWrite)
conquestDb.exec("""
INSERT INTO agents (name, listener, sleep, jitter, pid,username, hostname, ip, os, elevated)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
""", agent.name, agent.listener, agent.sleep, agent.jitter, agent.pid, agent.username, agent.hostname, agent.ip, agent.os, agent.elevated)
INSERT INTO agents (name, listener, sleep, jitter, process, pid, username, hostname, ip, os, elevated, firstCheckin)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
""", agent.name, agent.listener, agent.sleep, agent.jitter, agent.process, agent.pid, agent.username, agent.hostname, agent.ip, agent.os, agent.elevated, $agent.firstCheckin)
conquestDb.close()
except:
@@ -125,3 +133,36 @@ proc dbStoreAgent*(cq: Conquest, agent: Agent): bool =
return true
proc dbGetAllAgents*(cq: Conquest): seq[Agent] =
var agents: seq[Agent] = @[]
try:
let conquestDb = openDatabase(cq.dbPath, mode=dbReadWrite)
for row in conquestDb.iterate("SELECT name, listener, sleep, jitter, process, pid, username, hostname, ip, os, elevated, firstCheckin FROM agents;"):
let (name, listener, sleep, jitter, process, pid, username, hostname, ip, os, elevated, firstCheckin) = row.unpack((string, string, int, float, string, int, string, string, string, string, bool, string))
let a = Agent(
name: name,
listener: listener,
sleep: sleep,
jitter: jitter,
process: process,
pid: pid,
username: username,
hostname: hostname,
ip: ip,
os: os,
elevated: elevated,
firstCheckin: firstCheckin,
tasks: @[]
)
agents.add(a)
conquestDb.close()
except:
cq.writeLine(fgRed, styleBright, "[-] ", getCurrentExceptionMsg())
return agents

View File

@@ -1,5 +1,5 @@
import prologue, nanoid
import terminal, sequtils, strutils
import terminal, sequtils, strutils, times
import ../[types]
import ../agent/agent
@@ -26,6 +26,7 @@ proc register*(ctx: Context) {.async.} =
"hostname":"hostname",
"ip": "ip-address",
"os": "operating-system",
"process": "agent.exe",
"pid": 1234,
"elevated": false
}
@@ -34,11 +35,12 @@ proc register*(ctx: Context) {.async.} =
try:
let
postData: JsonNode = parseJson(ctx.request.body)
agentRegistrationData = postData.to(AgentRegistrationData)
agentUuid = generate(alphabet=join(toSeq('A'..'Z'), ""), size=8)
listenerUuid = ctx.getPathParams("listener")
agentRegistrationData: AgentRegistrationData = postData.to(AgentRegistrationData)
agentUuid: string = generate(alphabet=join(toSeq('A'..'Z'), ""), size=8)
listenerUuid: string = ctx.getPathParams("listener")
date: string = now().format("dd-MM-yyyy HH:mm:ss")
let agent: Agent = newAgent(agentUuid, listenerUuid, agentRegistrationData)
let agent: Agent = newAgent(agentUuid, listenerUuid, date, agentRegistrationData)
# Fully register agent and add it to database
if not agent.register():

View File

@@ -1,8 +1,8 @@
import strformat, strutils, sequtils, checksums/sha1, nanoid, terminal
import prologue
import ./[api, utils]
import ../types
import ./api
import ../[types, utils]
import ../db/database
proc listenerUsage*(cq: Conquest) =

3
server/nim.cfg Normal file
View File

@@ -0,0 +1,3 @@
# Compiler flags
--threads:on
-d:httpxServerName="nginx"

View File

@@ -31,6 +31,7 @@ var parser = newParser:
command("list"):
help("List all agents.")
# TODO: Add a flag that allows the user to only list agents that are connected to a specific listener (-n <uuid>)
command("build"):
help("Build an agent to connect to an active listener.")
@@ -112,7 +113,6 @@ proc header(cq: Conquest) =
Conquest framework entry point
]#
proc main() =
# Handle CTRL+C,
proc exit() {.noconv.} =
echo "Received CTRL+C. Type \"exit\" to close the application.\n"

View File

@@ -1,6 +1,6 @@
import prompt
import prologue
import tables
import tables, times
#[
Agent
@@ -35,14 +35,17 @@ type
hostname*: string
ip*: string
os*: string
process*: string
pid*: int
elevated*: bool
# TODO: Add additional fields: domain, ...
Agent* = ref object
name*: string
listener*: string
sleep*: int
jitter*: float
process*: string
pid*: int
username*: string
hostname*: string
@@ -50,11 +53,14 @@ type
os*: string
elevated*: bool
tasks*: seq[Task]
firstCheckin*: string
lastCheckin*: string
proc newAgent*(name, listener, username, hostname, ip, os: string, pid: int, elevated: bool): Agent =
proc newAgent*(name, listener, username, hostname, process, ip, os, firstCheckin: string, pid: int, elevated: bool): Agent =
var agent = new Agent
agent.name = name
agent.listener = listener
agent.process = process
agent.pid = pid
agent.username = username
agent.hostname = hostname
@@ -64,13 +70,15 @@ proc newAgent*(name, listener, username, hostname, ip, os: string, pid: int, ele
agent.sleep = 10
agent.jitter = 0.2
agent.tasks = @[]
agent.firstCheckin = firstCheckin
return agent
proc newAgent*(name, listener: string, postData: AgentRegistrationData): Agent =
proc newAgent*(name, listener, firstCheckin: string, postData: AgentRegistrationData): Agent =
var agent = new Agent
agent.name = name
agent.listener = listener
agent.process = postData.process
agent.pid = postData.pid
agent.username = postData.username
agent.hostname = postData.hostname
@@ -80,10 +88,10 @@ proc newAgent*(name, listener: string, postData: AgentRegistrationData): Agent =
agent.sleep = 10
agent.jitter = 0.2
agent.tasks = @[]
agent.firstCheckin = firstCheckin
return agent
#[
Listener
]#
@@ -118,7 +126,7 @@ proc stringToProtocol*(protocol: string): Protocol =
#[
Conquest
Conquest framework
]#
type
Conquest* = ref object

View File

@@ -1,6 +1,6 @@
import re, strutils
import ../types
import ./types
proc validateIPv4Address*(ip: string): bool =
let ipv4Pattern = re"^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4}$"
@@ -45,7 +45,7 @@ proc drawTable*(cq: Conquest, listeners: seq[Listener]) =
# Column headers and widths
let headers = @["Name", "Address", "Port", "Protocol", "Agents"]
let widths = @[10, 15, 7, 10, 8]
let widths = @[10, 17, 7, 10, 8]
cq.writeLine(border(topLeft, topMid, topRight, widths))
cq.writeLine(row(headers, widths))
@@ -60,4 +60,17 @@ proc drawTable*(cq: Conquest, listeners: seq[Listener]) =
proc drawTable*(cq: Conquest, agents: seq[Agent]) =
discard
let headers: seq[string] = @["Name", "Address", "Username", "Hostname", "Operating System", "Process", "PID"]
let widths = @[10, 17, 25, 20, 22, 15, 8]
cq.writeLine(border(topLeft, topMid, topRight, widths))
cq.writeLine(row(headers, widths))
cq.writeLine(border(midLeft, midMid, midRight, widths))
# TODO: Highlight elevated processes
for a in agents:
let row = @[a.name, a.ip, a.username, a.hostname, a.os, a.process, $a.pid]
cq.writeLine(row(row, widths))
cq.writeLine(border(botLeft, botMid, botRight, widths))