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 ../[types, globals, utils]
|
||||||
import ../db/database
|
import ../db/database
|
||||||
|
|
||||||
@@ -16,6 +16,7 @@ Usage:
|
|||||||
Commands:
|
Commands:
|
||||||
|
|
||||||
list List all agents.
|
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.
|
kill Terminate the connection of an active listener and remove it from the interface.
|
||||||
interact Interact with an active agent.
|
interact Interact with an active agent.
|
||||||
|
|
||||||
@@ -23,10 +24,46 @@ Options:
|
|||||||
-h, --help""")
|
-h, --help""")
|
||||||
|
|
||||||
# List agents
|
# List agents
|
||||||
proc agentList*(cq: Conquest, args: varargs[string]) =
|
proc agentList*(cq: Conquest) =
|
||||||
let agents = cq.dbGetAllAgents()
|
let agents = cq.dbGetAllAgents()
|
||||||
cq.drawTable(agents)
|
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
|
# Terminate agent and remove it from the database
|
||||||
proc agentKill*(cq: Conquest, name: string) =
|
proc agentKill*(cq: Conquest, name: string) =
|
||||||
|
|
||||||
@@ -67,7 +104,7 @@ proc register*(agent: Agent): bool =
|
|||||||
# Check if listener that is requested exists
|
# Check if listener that is requested exists
|
||||||
# TODO: Verify that the listener accessed is also the listener specified in the URL
|
# 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
|
# 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")
|
cq.writeLine(fgRed, styleBright, fmt"[-] Agent from {agent.ip} attempted to register to non-existent listener: {agent.listener}.", "\n")
|
||||||
return false
|
return false
|
||||||
|
|
||||||
|
|||||||
@@ -165,6 +165,41 @@ proc dbGetAllAgents*(cq: Conquest): seq[Agent] =
|
|||||||
|
|
||||||
return agents
|
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 =
|
proc dbDeleteAgentByName*(cq: Conquest, name: string): bool =
|
||||||
try:
|
try:
|
||||||
let conquestDb = openDatabase(cq.dbPath, mode=dbReadWrite)
|
let conquestDb = openDatabase(cq.dbPath, mode=dbReadWrite)
|
||||||
|
|||||||
@@ -1,3 +1,11 @@
|
|||||||
import ./types
|
import ./types
|
||||||
|
|
||||||
|
# Global variable for handling listeners, agents and console output
|
||||||
var cq*: Conquest
|
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.")
|
help("Starts a new HTTP listener.")
|
||||||
option("-h", "-host", default=some("0.0.0.0"), help="IPv4 address to listen on.", required=false)
|
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)
|
option("-p", "-port", help="Port to listen on.", required=true)
|
||||||
|
# TODO: Future features:
|
||||||
# flag("--dns", help="Use the DNS protocol for C2 communication.")
|
# flag("--dns", help="Use the DNS protocol for C2 communication.")
|
||||||
# flag("--doh", help="Use DNS over HTTPS for C2 communication.)
|
# flag("--doh", help="Use DNS over HTTPS for C2 communication.)
|
||||||
command("stop"):
|
command("stop"):
|
||||||
help("Stop an active listener.")
|
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"):
|
command("agent"):
|
||||||
help("Manage, build and interact with agents.")
|
help("Manage, build and interact with agents.")
|
||||||
|
|
||||||
command("list"):
|
command("list"):
|
||||||
help("List all agents.")
|
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>)
|
# 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"):
|
command("kill"):
|
||||||
help("Terminate the connection of an active listener and remove it from the interface.")
|
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"):
|
command("interact"):
|
||||||
help("Interact with an active agent.")
|
help("Interact with an active agent.")
|
||||||
@@ -81,7 +87,12 @@ proc handleConsoleCommand*(cq: Conquest, args: varargs[string]) =
|
|||||||
of "agent":
|
of "agent":
|
||||||
case opts.agent.get.command
|
case opts.agent.get.command
|
||||||
of "list":
|
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":
|
of "kill":
|
||||||
cq.agentKill(opts.agent.get.kill.get.name)
|
cq.agentKill(opts.agent.get.kill.get.name)
|
||||||
of "interact":
|
of "interact":
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import re, strutils
|
import re, strutils, strformat, terminal
|
||||||
|
|
||||||
import ./types
|
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 =
|
proc row(cells: seq[string], widths: seq[int]): string =
|
||||||
var row = vert
|
var row = vert
|
||||||
for i, cell in cells:
|
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
|
return row
|
||||||
|
|
||||||
proc drawTable*(cq: Conquest, listeners: seq[Listener]) =
|
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]) =
|
proc drawTable*(cq: Conquest, agents: seq[Agent]) =
|
||||||
|
|
||||||
let headers: seq[string] = @["Name", "Address", "Username", "Hostname", "Operating System", "Process", "PID"]
|
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(border(topLeft, topMid, topRight, widths))
|
||||||
cq.writeLine(row(headers, widths))
|
cq.writeLine(row(headers, widths))
|
||||||
|
|||||||
Reference in New Issue
Block a user