Implemented listing agents by listener UUID
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import terminal, strformat, strutils
|
||||
import terminal, strformat, strutils, tables
|
||||
import ../[types, globals, utils]
|
||||
import ../db/database
|
||||
|
||||
@@ -16,6 +16,7 @@ Usage:
|
||||
Commands:
|
||||
|
||||
list List all agents.
|
||||
info Display details for a specific agent.
|
||||
kill Terminate the connection of an active listener and remove it from the interface.
|
||||
interact Interact with an active agent.
|
||||
|
||||
@@ -23,10 +24,46 @@ Options:
|
||||
-h, --help""")
|
||||
|
||||
# List agents
|
||||
proc agentList*(cq: Conquest, args: varargs[string]) =
|
||||
proc agentList*(cq: Conquest) =
|
||||
let agents = cq.dbGetAllAgents()
|
||||
cq.drawTable(agents)
|
||||
|
||||
proc agentList*(cq: Conquest, listener: string) =
|
||||
|
||||
# Check if listener exists
|
||||
if not cq.dbListenerExists(listener.toUpperAscii):
|
||||
cq.writeLine(fgRed, styleBright, fmt"[-] Listener {listener.toUpperAscii} does not exist.")
|
||||
return
|
||||
|
||||
let agents = cq.dbGetAllAgentsByListener(listener.toUpperAscii)
|
||||
cq.drawTable(agents)
|
||||
|
||||
# Display agent properties and details
|
||||
proc agentInfo*(cq: Conquest, name: string) =
|
||||
# Check if agent supplied via -n parameter exists in database
|
||||
if not cq.dbAgentExists(name.toUpperAscii):
|
||||
cq.writeLine(fgRed, styleBright, fmt"[-] Agent {name.toUpperAscii} does not exist.")
|
||||
return
|
||||
|
||||
let agent = cq.agents[name.toUpperAscii]
|
||||
|
||||
# TODO: Improve formating
|
||||
cq.writeLine(fmt"""
|
||||
Agent name (UUID): {agent.name}
|
||||
Connected to listener: {agent.listener}
|
||||
──────────────────────────────────────────
|
||||
Username: {agent.username}
|
||||
Hostname: {agent.hostname}
|
||||
Domain: {agent.domain}
|
||||
IP-Address: {agent.ip}
|
||||
Operating system: {agent.os}
|
||||
──────────────────────────────────────────
|
||||
Process name: {agent.process}
|
||||
Process ID: {$agent.pid}
|
||||
Process elevated: {$agent.elevated}
|
||||
First checkin: {agent.firstCheckin}
|
||||
""")
|
||||
|
||||
# Terminate agent and remove it from the database
|
||||
proc agentKill*(cq: Conquest, name: string) =
|
||||
|
||||
@@ -67,7 +104,7 @@ proc register*(agent: Agent): bool =
|
||||
# Check if listener that is requested exists
|
||||
# TODO: Verify that the listener accessed is also the listener specified in the URL
|
||||
# This can be achieved by extracting the port number from the `Host` header and matching it to the one queried from the database
|
||||
if not cq.dbListenerExists(agent.listener):
|
||||
if not cq.dbListenerExists(agent.listener.toUpperAscii):
|
||||
cq.writeLine(fgRed, styleBright, fmt"[-] Agent from {agent.ip} attempted to register to non-existent listener: {agent.listener}.", "\n")
|
||||
return false
|
||||
|
||||
|
||||
@@ -165,6 +165,41 @@ proc dbGetAllAgents*(cq: Conquest): seq[Agent] =
|
||||
|
||||
return agents
|
||||
|
||||
proc dbGetAllAgentsByListener*(cq: Conquest, listenerName: string): 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, domain, ip, os, elevated, firstCheckin FROM agents WHERE listener = ?;", listenerName):
|
||||
let (name, listener, sleep, jitter, process, pid, username, hostname, domain, ip, os, elevated, firstCheckin) = row.unpack((string, string, int, float, string, int, string, string, string, string, string, bool, string))
|
||||
|
||||
let a = Agent(
|
||||
name: name,
|
||||
listener: listener,
|
||||
sleep: sleep,
|
||||
pid: pid,
|
||||
username: username,
|
||||
hostname: hostname,
|
||||
domain: domain,
|
||||
ip: ip,
|
||||
os: os,
|
||||
elevated: elevated,
|
||||
firstCheckin: firstCheckin,
|
||||
jitter: jitter,
|
||||
process: process,
|
||||
tasks: @[]
|
||||
)
|
||||
|
||||
agents.add(a)
|
||||
|
||||
conquestDb.close()
|
||||
except:
|
||||
cq.writeLine(fgRed, styleBright, "[-] ", getCurrentExceptionMsg())
|
||||
|
||||
return agents
|
||||
|
||||
proc dbDeleteAgentByName*(cq: Conquest, name: string): bool =
|
||||
try:
|
||||
let conquestDb = openDatabase(cq.dbPath, mode=dbReadWrite)
|
||||
|
||||
@@ -1,3 +1,11 @@
|
||||
import ./types
|
||||
|
||||
# Global variable for handling listeners, agents and console output
|
||||
var cq*: Conquest
|
||||
|
||||
# Colors
|
||||
# https://colors.sh/
|
||||
# TODO Replace all colored output with custom colors
|
||||
const yellow* = "\e[48;5;232m"
|
||||
const resetColor* = "\e[0m"
|
||||
|
||||
|
||||
@@ -20,22 +20,28 @@ var parser = newParser:
|
||||
help("Starts a new HTTP listener.")
|
||||
option("-h", "-host", default=some("0.0.0.0"), help="IPv4 address to listen on.", required=false)
|
||||
option("-p", "-port", help="Port to listen on.", required=true)
|
||||
# TODO: Future features:
|
||||
# flag("--dns", help="Use the DNS protocol for C2 communication.")
|
||||
# flag("--doh", help="Use DNS over HTTPS for C2 communication.)
|
||||
command("stop"):
|
||||
help("Stop an active listener.")
|
||||
option("-n", "-name", help="Name of the listener to stop.", required=true)
|
||||
option("-n", "-name", help="Name of the listener.", required=true)
|
||||
|
||||
command("agent"):
|
||||
help("Manage, build and interact with agents.")
|
||||
|
||||
command("list"):
|
||||
help("List all agents.")
|
||||
option("-n", "-name", help="Name of the listener.")
|
||||
# TODO: Add a flag that allows the user to only list agents that are connected to a specific listener (-n <uuid>)
|
||||
|
||||
command("info"):
|
||||
help("Display details for a specific agent.")
|
||||
option("-n", "-name", help="Name of the agent.", required=true)
|
||||
|
||||
command("kill"):
|
||||
help("Terminate the connection of an active listener and remove it from the interface.")
|
||||
option("-n", "-name", help="Name of the agent to stop.", required=true)
|
||||
option("-n", "-name", help="Name of the agent.", required=true)
|
||||
|
||||
command("interact"):
|
||||
help("Interact with an active agent.")
|
||||
@@ -81,7 +87,12 @@ proc handleConsoleCommand*(cq: Conquest, args: varargs[string]) =
|
||||
of "agent":
|
||||
case opts.agent.get.command
|
||||
of "list":
|
||||
cq.agentList()
|
||||
if opts.agent.get.list.get.name == "":
|
||||
cq.agentList()
|
||||
else:
|
||||
cq.agentList(opts.agent.get.list.get.name)
|
||||
of "info":
|
||||
cq.agentInfo(opts.agent.get.info.get.name)
|
||||
of "kill":
|
||||
cq.agentKill(opts.agent.get.kill.get.name)
|
||||
of "interact":
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import re, strutils
|
||||
import re, strutils, strformat, terminal
|
||||
|
||||
import ./types
|
||||
|
||||
@@ -38,7 +38,16 @@ proc border(left, mid, right: string, widths: seq[int]): string =
|
||||
proc row(cells: seq[string], widths: seq[int]): string =
|
||||
var row = vert
|
||||
for i, cell in cells:
|
||||
row.add(" " & cell.alignLeft(widths[i] - 2) & " " & vert)
|
||||
# Truncate content of a cell with "..." when the value to be inserted is longer than the designated width
|
||||
let w = widths[i] - 2
|
||||
let c = if cell.len > w:
|
||||
if w >= 3:
|
||||
cell[0 ..< w - 3] & "..."
|
||||
else:
|
||||
".".repeat(max(0, w))
|
||||
else:
|
||||
cell
|
||||
row.add(" " & c.alignLeft(w) & " " & vert)
|
||||
return row
|
||||
|
||||
proc drawTable*(cq: Conquest, listeners: seq[Listener]) =
|
||||
@@ -62,7 +71,7 @@ proc drawTable*(cq: Conquest, listeners: seq[Listener]) =
|
||||
proc drawTable*(cq: Conquest, agents: seq[Agent]) =
|
||||
|
||||
let headers: seq[string] = @["Name", "Address", "Username", "Hostname", "Operating System", "Process", "PID"]
|
||||
let widths = @[10, 17, 25, 20, 22, 15, 8]
|
||||
let widths = @[10, 17, 20, 20, 20, 15, 7]
|
||||
|
||||
cq.writeLine(border(topLeft, topMid, topRight, widths))
|
||||
cq.writeLine(row(headers, widths))
|
||||
|
||||
Reference in New Issue
Block a user