Implement listing agents; Add TODOs for further improvements
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
import terminal, strformat, times
|
import terminal, strformat
|
||||||
import ../[types, globals]
|
import ../[types, globals, utils]
|
||||||
import ../db/database
|
import ../db/database
|
||||||
|
|
||||||
|
|
||||||
@@ -23,7 +23,8 @@ Options:
|
|||||||
-h, --help""")
|
-h, --help""")
|
||||||
|
|
||||||
proc agentList*(cq: Conquest, args: varargs[string]) =
|
proc agentList*(cq: Conquest, args: varargs[string]) =
|
||||||
discard
|
let agents = cq.dbGetAllAgents()
|
||||||
|
cq.drawTable(agents)
|
||||||
|
|
||||||
proc agentBuild*(cq: Conquest, args: varargs[string]) =
|
proc agentBuild*(cq: Conquest, args: varargs[string]) =
|
||||||
discard
|
discard
|
||||||
@@ -44,8 +45,6 @@ proc agentInteract*(cq: Conquest, args: varargs[string]) =
|
|||||||
]#
|
]#
|
||||||
proc register*(agent: Agent): bool =
|
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
|
# The following line is required to be able to use the `cq` global variable for console output
|
||||||
{.cast(gcsafe).}:
|
{.cast(gcsafe).}:
|
||||||
|
|
||||||
@@ -62,7 +61,7 @@ proc register*(agent: Agent): bool =
|
|||||||
return false
|
return false
|
||||||
|
|
||||||
cq.add(agent.name, agent)
|
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
|
return true
|
||||||
#[
|
#[
|
||||||
|
|||||||
@@ -1,2 +0,0 @@
|
|||||||
# Compiler flags
|
|
||||||
--threads:on
|
|
||||||
@@ -22,6 +22,7 @@ proc dbInit*(cq: Conquest) =
|
|||||||
CREATE TABLE agents (
|
CREATE TABLE agents (
|
||||||
name TEXT PRIMARY KEY,
|
name TEXT PRIMARY KEY,
|
||||||
listener TEXT NOT NULL,
|
listener TEXT NOT NULL,
|
||||||
|
process TEXT NOT NULL,
|
||||||
pid INTEGER NOT NULL,
|
pid INTEGER NOT NULL,
|
||||||
username TEXT NOT NULL,
|
username TEXT NOT NULL,
|
||||||
hostname TEXT NOT NULL,
|
hostname TEXT NOT NULL,
|
||||||
@@ -30,6 +31,7 @@ proc dbInit*(cq: Conquest) =
|
|||||||
elevated BOOLEAN NOT NULL,
|
elevated BOOLEAN NOT NULL,
|
||||||
sleep INTEGER DEFAULT 10,
|
sleep INTEGER DEFAULT 10,
|
||||||
jitter REAL DEFAULT 0.1,
|
jitter REAL DEFAULT 0.1,
|
||||||
|
firstCheckin DATETIME NOT NULL,
|
||||||
FOREIGN KEY (listener) REFERENCES listeners(name)
|
FOREIGN KEY (listener) REFERENCES listeners(name)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -40,6 +42,9 @@ proc dbInit*(cq: Conquest) =
|
|||||||
except SqliteError:
|
except SqliteError:
|
||||||
cq.writeLine(fgGreen, "[+] ", cq.dbPath, ": Database file found.")
|
cq.writeLine(fgGreen, "[+] ", cq.dbPath, ": Database file found.")
|
||||||
|
|
||||||
|
#[
|
||||||
|
Listeners
|
||||||
|
]#
|
||||||
proc dbStoreListener*(cq: Conquest, listener: Listener): bool =
|
proc dbStoreListener*(cq: Conquest, listener: Listener): bool =
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -108,15 +113,18 @@ proc listenerExists*(cq: Conquest, listenerName: string): bool =
|
|||||||
cq.writeLine(fgRed, styleBright, "[-] ", getCurrentExceptionMsg())
|
cq.writeLine(fgRed, styleBright, "[-] ", getCurrentExceptionMsg())
|
||||||
return false
|
return false
|
||||||
|
|
||||||
|
#[
|
||||||
|
Agents
|
||||||
|
]#
|
||||||
proc dbStoreAgent*(cq: Conquest, agent: Agent): bool =
|
proc dbStoreAgent*(cq: Conquest, agent: Agent): bool =
|
||||||
|
|
||||||
try:
|
try:
|
||||||
let conquestDb = openDatabase(cq.dbPath, mode=dbReadWrite)
|
let conquestDb = openDatabase(cq.dbPath, mode=dbReadWrite)
|
||||||
|
|
||||||
conquestDb.exec("""
|
conquestDb.exec("""
|
||||||
INSERT INTO agents (name, listener, sleep, jitter, pid,username, hostname, ip, os, elevated)
|
INSERT INTO agents (name, listener, sleep, jitter, process, pid, username, hostname, ip, os, elevated, firstCheckin)
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
|
||||||
""", agent.name, agent.listener, agent.sleep, agent.jitter, agent.pid, agent.username, agent.hostname, agent.ip, agent.os, agent.elevated)
|
""", 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()
|
conquestDb.close()
|
||||||
except:
|
except:
|
||||||
@@ -125,3 +133,36 @@ proc dbStoreAgent*(cq: Conquest, agent: Agent): bool =
|
|||||||
|
|
||||||
return true
|
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
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import prologue, nanoid
|
import prologue, nanoid
|
||||||
import terminal, sequtils, strutils
|
import terminal, sequtils, strutils, times
|
||||||
|
|
||||||
import ../[types]
|
import ../[types]
|
||||||
import ../agent/agent
|
import ../agent/agent
|
||||||
@@ -26,6 +26,7 @@ proc register*(ctx: Context) {.async.} =
|
|||||||
"hostname":"hostname",
|
"hostname":"hostname",
|
||||||
"ip": "ip-address",
|
"ip": "ip-address",
|
||||||
"os": "operating-system",
|
"os": "operating-system",
|
||||||
|
"process": "agent.exe",
|
||||||
"pid": 1234,
|
"pid": 1234,
|
||||||
"elevated": false
|
"elevated": false
|
||||||
}
|
}
|
||||||
@@ -34,11 +35,12 @@ proc register*(ctx: Context) {.async.} =
|
|||||||
try:
|
try:
|
||||||
let
|
let
|
||||||
postData: JsonNode = parseJson(ctx.request.body)
|
postData: JsonNode = parseJson(ctx.request.body)
|
||||||
agentRegistrationData = postData.to(AgentRegistrationData)
|
agentRegistrationData: AgentRegistrationData = postData.to(AgentRegistrationData)
|
||||||
agentUuid = generate(alphabet=join(toSeq('A'..'Z'), ""), size=8)
|
agentUuid: string = generate(alphabet=join(toSeq('A'..'Z'), ""), size=8)
|
||||||
listenerUuid = ctx.getPathParams("listener")
|
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
|
# Fully register agent and add it to database
|
||||||
if not agent.register():
|
if not agent.register():
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import strformat, strutils, sequtils, checksums/sha1, nanoid, terminal
|
import strformat, strutils, sequtils, checksums/sha1, nanoid, terminal
|
||||||
import prologue
|
import prologue
|
||||||
|
|
||||||
import ./[api, utils]
|
import ./api
|
||||||
import ../types
|
import ../[types, utils]
|
||||||
import ../db/database
|
import ../db/database
|
||||||
|
|
||||||
proc listenerUsage*(cq: Conquest) =
|
proc listenerUsage*(cq: Conquest) =
|
||||||
|
|||||||
3
server/nim.cfg
Normal file
3
server/nim.cfg
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# Compiler flags
|
||||||
|
--threads:on
|
||||||
|
-d:httpxServerName="nginx"
|
||||||
@@ -31,6 +31,7 @@ var parser = newParser:
|
|||||||
|
|
||||||
command("list"):
|
command("list"):
|
||||||
help("List all agents.")
|
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"):
|
command("build"):
|
||||||
help("Build an agent to connect to an active listener.")
|
help("Build an agent to connect to an active listener.")
|
||||||
@@ -112,7 +113,6 @@ proc header(cq: Conquest) =
|
|||||||
Conquest framework entry point
|
Conquest framework entry point
|
||||||
]#
|
]#
|
||||||
proc main() =
|
proc main() =
|
||||||
|
|
||||||
# Handle CTRL+C,
|
# Handle CTRL+C,
|
||||||
proc exit() {.noconv.} =
|
proc exit() {.noconv.} =
|
||||||
echo "Received CTRL+C. Type \"exit\" to close the application.\n"
|
echo "Received CTRL+C. Type \"exit\" to close the application.\n"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import prompt
|
import prompt
|
||||||
import prologue
|
import prologue
|
||||||
import tables
|
import tables, times
|
||||||
|
|
||||||
#[
|
#[
|
||||||
Agent
|
Agent
|
||||||
@@ -35,14 +35,17 @@ type
|
|||||||
hostname*: string
|
hostname*: string
|
||||||
ip*: string
|
ip*: string
|
||||||
os*: string
|
os*: string
|
||||||
|
process*: string
|
||||||
pid*: int
|
pid*: int
|
||||||
elevated*: bool
|
elevated*: bool
|
||||||
|
|
||||||
|
# TODO: Add additional fields: domain, ...
|
||||||
Agent* = ref object
|
Agent* = ref object
|
||||||
name*: string
|
name*: string
|
||||||
listener*: string
|
listener*: string
|
||||||
sleep*: int
|
sleep*: int
|
||||||
jitter*: float
|
jitter*: float
|
||||||
|
process*: string
|
||||||
pid*: int
|
pid*: int
|
||||||
username*: string
|
username*: string
|
||||||
hostname*: string
|
hostname*: string
|
||||||
@@ -50,11 +53,14 @@ type
|
|||||||
os*: string
|
os*: string
|
||||||
elevated*: bool
|
elevated*: bool
|
||||||
tasks*: seq[Task]
|
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
|
var agent = new Agent
|
||||||
agent.name = name
|
agent.name = name
|
||||||
agent.listener = listener
|
agent.listener = listener
|
||||||
|
agent.process = process
|
||||||
agent.pid = pid
|
agent.pid = pid
|
||||||
agent.username = username
|
agent.username = username
|
||||||
agent.hostname = hostname
|
agent.hostname = hostname
|
||||||
@@ -64,13 +70,15 @@ proc newAgent*(name, listener, username, hostname, ip, os: string, pid: int, ele
|
|||||||
agent.sleep = 10
|
agent.sleep = 10
|
||||||
agent.jitter = 0.2
|
agent.jitter = 0.2
|
||||||
agent.tasks = @[]
|
agent.tasks = @[]
|
||||||
|
agent.firstCheckin = firstCheckin
|
||||||
|
|
||||||
return agent
|
return agent
|
||||||
|
|
||||||
proc newAgent*(name, listener: string, postData: AgentRegistrationData): Agent =
|
proc newAgent*(name, listener, firstCheckin: string, postData: AgentRegistrationData): Agent =
|
||||||
var agent = new Agent
|
var agent = new Agent
|
||||||
agent.name = name
|
agent.name = name
|
||||||
agent.listener = listener
|
agent.listener = listener
|
||||||
|
agent.process = postData.process
|
||||||
agent.pid = postData.pid
|
agent.pid = postData.pid
|
||||||
agent.username = postData.username
|
agent.username = postData.username
|
||||||
agent.hostname = postData.hostname
|
agent.hostname = postData.hostname
|
||||||
@@ -80,10 +88,10 @@ proc newAgent*(name, listener: string, postData: AgentRegistrationData): Agent =
|
|||||||
agent.sleep = 10
|
agent.sleep = 10
|
||||||
agent.jitter = 0.2
|
agent.jitter = 0.2
|
||||||
agent.tasks = @[]
|
agent.tasks = @[]
|
||||||
|
agent.firstCheckin = firstCheckin
|
||||||
|
|
||||||
return agent
|
return agent
|
||||||
|
|
||||||
|
|
||||||
#[
|
#[
|
||||||
Listener
|
Listener
|
||||||
]#
|
]#
|
||||||
@@ -118,7 +126,7 @@ proc stringToProtocol*(protocol: string): Protocol =
|
|||||||
|
|
||||||
|
|
||||||
#[
|
#[
|
||||||
Conquest
|
Conquest framework
|
||||||
]#
|
]#
|
||||||
type
|
type
|
||||||
Conquest* = ref object
|
Conquest* = ref object
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import re, strutils
|
import re, strutils
|
||||||
|
|
||||||
import ../types
|
import ./types
|
||||||
|
|
||||||
proc validateIPv4Address*(ip: string): bool =
|
proc validateIPv4Address*(ip: string): bool =
|
||||||
let ipv4Pattern = re"^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4}$"
|
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
|
# Column headers and widths
|
||||||
let headers = @["Name", "Address", "Port", "Protocol", "Agents"]
|
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(border(topLeft, topMid, topRight, widths))
|
||||||
cq.writeLine(row(headers, widths))
|
cq.writeLine(row(headers, widths))
|
||||||
@@ -60,4 +60,17 @@ proc drawTable*(cq: Conquest, listeners: seq[Listener]) =
|
|||||||
|
|
||||||
|
|
||||||
proc drawTable*(cq: Conquest, agents: seq[Agent]) =
|
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))
|
||||||
Reference in New Issue
Block a user