Improved logging format.

This commit is contained in:
Jakob Friedl
2025-08-21 15:08:52 +02:00
parent f69adc53a2
commit c9df7aba64
18 changed files with 91 additions and 115 deletions

View File

@@ -1,6 +1,6 @@
import terminal, strformat, strutils, tables, times, system, parsetoml
import ./[task, logger]
import ./task
import ../utils
import ../db/database
import ../../common/types
@@ -49,7 +49,7 @@ proc agentList*(cq: Conquest, listener: string) =
else:
# Check if listener exists
if not cq.dbListenerExists(listener.toUpperAscii):
cq.writeLine(fgRed, styleBright, fmt"[-] Listener {listener.toUpperAscii} does not exist.")
cq.writeLine(fgRed, styleBright, fmt"[ - ] Listener {listener.toUpperAscii} does not exist.")
return
cq.drawTable(cq.dbGetAllAgentsByListener(listener.toUpperAscii))
@@ -59,7 +59,7 @@ proc agentList*(cq: Conquest, listener: string) =
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.")
cq.writeLine(fgRed, styleBright, fmt"[ - ] Agent {name.toUpperAscii} does not exist.")
return
let agent = cq.agents[name.toUpperAscii]
@@ -87,7 +87,7 @@ proc agentKill*(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.")
cq.writeLine(fgRed, styleBright, fmt"[ - ] Agent {name.toUpperAscii} does not exist.")
return
# TODO: Stop the process of the agent on the target system
@@ -96,30 +96,29 @@ proc agentKill*(cq: Conquest, name: string) =
# Remove the agent from the database
if not cq.dbDeleteAgentByName(name.toUpperAscii):
cq.writeLine(fgRed, styleBright, "[-] Failed to terminate agent: ", getCurrentExceptionMsg())
cq.writeLine(fgRed, styleBright, "[ - ] Failed to terminate agent: ", getCurrentExceptionMsg())
return
cq.delAgent(name)
cq.writeLine(fgYellow, styleBright, "[+] ", resetStyle, "Terminated agent ", fgYellow, styleBright, name.toUpperAscii, resetStyle, ".")
cq.writeLine(fgYellow, styleBright, "[ + ] ", resetStyle, "Terminated agent ", fgYellow, styleBright, name.toUpperAscii, resetStyle, ".")
# Switch to interact mode
proc agentInteract*(cq: Conquest, name: string) =
# Verify that agent exists
if not cq.dbAgentExists(name.toUpperAscii):
cq.writeLine(fgRed, styleBright, fmt"[-] Agent {name.toUpperAscii} does not exist.")
cq.writeLine(fgRed, styleBright, fmt"[ - ] Agent {name.toUpperAscii} does not exist.")
return
let agent = cq.agents[name.toUpperAscii]
var command: string = ""
# Change prompt indicator to show agent interaction
cq.interactAgent = agent
cq.setIndicator(fmt"[{agent.agentId}]> ")
cq.setStatusBar(@[("[mode]", "interact"), ("[username]", fmt"{agent.username}"), ("[hostname]", fmt"{agent.hostname}"), ("[ip]", fmt"{agent.ip}"), ("[domain]", fmt"{agent.domain}")])
cq.writeLine(fgYellow, styleBright, "[+] ", resetStyle, fmt"Started interacting with agent ", fgYellow, styleBright, agent.agentId, resetStyle, ". Type 'help' to list available commands.\n")
cq.interactAgent = agent
cq.log(fmt"Started interacting with agent {agent.agentId}.")
cq.writeLine(fgBlack, styleBright, fmt"[{getTimestamp()}] ", fgYellow, "[ + ] ", resetStyle, fmt"Started interacting with agent ", fgYellow, styleBright, agent.agentId, resetStyle, ". Type 'help' to list available commands.\n")
while command.replace(" ", "") != "back":
command = cq.readLine()

View File

@@ -37,7 +37,7 @@ proc serializeConfiguration(cq: Conquest, listener: Listener, sleep: int): seq[b
wipeKey(aesKey)
cq.writeLine(fgBlack, styleBright, "[*] ", resetStyle, "Profile configuration serialized.")
cq.writeLine(fgBlack, styleBright, fmt"[{getTimestamp()}] [ * ] ", resetStyle, "Profile configuration serialized.")
return encMaterial & encData
proc replaceAfterPrefix(content, prefix, value: string): string =
@@ -63,10 +63,10 @@ proc compile(cq: Conquest, placeholderLength: int): string =
.replaceAfterPrefix("-o:", exeFile)
writeFile(configFile, config)
cq.writeLine(fgBlack, styleBright, "[*] ", resetStyle, fmt"Placeholder created ({placeholder.len()} bytes).")
cq.writeLine(fgBlack, styleBright, fmt"[{getTimestamp()}] [ * ] ", resetStyle, fmt"Placeholder created ({placeholder.len()} bytes).")
# Build agent by executing the ./build.sh script on the system.
cq.writeLine(fgBlack, styleBright, "[*] ", resetStyle, "Compiling agent.")
cq.writeLine(fgBlack, styleBright, fmt"[{getTimestamp()}] [ * ] ", resetStyle, "Compiling agent.")
try:
# Using the startProcess function from the 'osproc' module, it is possible to retrieve the output as it is received, line-by-line instead of all at once
@@ -81,19 +81,19 @@ proc compile(cq: Conquest, placeholderLength: int): string =
# Check if the build succeeded or not
if exitCode == 0:
cq.writeLine(fgGreen, "[*] ", resetStyle, "Agent payload generated successfully.")
cq.writeLine(fgBlack, styleBright, fmt"[{getTimestamp()}] ", fgGreen, "[ + ] ", resetStyle, "Agent payload generated successfully.")
return exeFile
else:
cq.writeLine(fgRed, styleBright, "[-] ", resetStyle, "Build script exited with code ", $exitCode)
cq.writeLine(fgBlack, styleBright, fmt"[{getTimestamp()}] ", fgRed, "[ - ] ", resetStyle, "Build script exited with code ", $exitCode)
return ""
except CatchableError as err:
cq.writeLine(fgRed, styleBright, "[-] ", resetStyle, "An error occurred: ", err.msg)
cq.writeLine(fgBlack, styleBright, fmt"[{getTimestamp()}] ", fgRed, "[ - ] ", resetStyle, "An error occurred: ", err.msg)
return ""
proc patch(cq: Conquest, unpatchedExePath: string, configuration: seq[byte]): bool =
cq.writeLine(fgBlack, styleBright, "[*] ", resetStyle, "Patching profile configuration into agent.")
cq.writeLine(fgBlack, styleBright, fmt"[{getTimestamp()}] [ * ] ", resetStyle, "Patching profile configuration into agent.")
try:
var exeBytes = readFile(unpatchedExePath)
@@ -103,17 +103,17 @@ proc patch(cq: Conquest, unpatchedExePath: string, configuration: seq[byte]): bo
if placeholderPos == -1:
raise newException(CatchableError, "Placeholder not found.")
cq.writeLine(fgBlack, styleBright, "[+] ", resetStyle, fmt"Placeholder found at offset 0x{placeholderPos:08X}.")
cq.writeLine(fgBlack, styleBright, fmt"[{getTimestamp()}] [ + ] ", resetStyle, fmt"Placeholder found at offset 0x{placeholderPos:08X}.")
# Patch placeholder bytes
for i, c in Bytes.toString(configuration):
exeBytes[placeholderPos + i] = c
writeFile(unpatchedExePath, exeBytes)
cq.writeLine(fgGreen, "[+] ", resetStyle, fmt"Agent payload patched successfully: {unpatchedExePath}.")
cq.writeLine(fgBlack, styleBright, fmt"[{getTimestamp()}] ", fgGreen, "[ + ] ", resetStyle, fmt"Agent payload patched successfully: {unpatchedExePath}.")
except CatchableError as err:
cq.writeLine(fgRed, styleBright, "[-] ", resetStyle, "An error occurred: ", err.msg)
cq.writeLine(fgBlack, styleBright, fmt"[{getTimestamp()}] ", fgRed, styleBright, "[ - ] ", resetStyle, "An error occurred: ", err.msg)
return false
return true
@@ -123,7 +123,7 @@ proc agentBuild*(cq: Conquest, listener, sleep: string): bool {.discardable.} =
# Verify that listener exists
if not cq.dbListenerExists(listener.toUpperAscii):
cq.writeLine(fgRed, styleBright, fmt"[-] Listener {listener.toUpperAscii} does not exist.")
cq.writeLine(fgRed, styleBright, fmt"[ - ] Listener {listener.toUpperAscii} does not exist.")
return false
let listener = cq.listeners[listener.toUpperAscii]

View File

@@ -1,7 +1,5 @@
import strformat, strutils, sequtils, terminal
import strformat, strutils, terminal
import prologue, parsetoml
import sugar
import ../utils
import ../api/routes
@@ -42,7 +40,7 @@ proc listenerStart*(cq: Conquest, host: string, portStr: string) =
# Validate arguments
try:
if not validatePort(portStr):
raise newException(CatchableError,fmt"[-] Invalid port number: {portStr}")
raise newException(CatchableError,fmt"[ - ] Invalid port number: {portStr}")
let port = portStr.parseInt
@@ -90,10 +88,10 @@ proc listenerStart*(cq: Conquest, host: string, portStr: string) =
# Start serving
discard listener.runAsync()
cq.add(listenerInstance)
cq.writeLine(fgGreen, "[+] ", resetStyle, "Started listener", fgGreen, fmt" {name} ", resetStyle, fmt"on {host}:{portStr}.")
cq.writeLine(fgGreen, "[ + ] ", resetStyle, "Started listener", fgGreen, fmt" {name} ", resetStyle, fmt"on {host}:{portStr}.")
except CatchableError as err:
cq.writeLine(fgRed, styleBright, "[-] Failed to start listener: ", err.msg)
cq.writeLine(fgRed, styleBright, "[ - ] Failed to start listener: ", err.msg)
proc restartListeners*(cq: Conquest) =
let listeners: seq[Listener] = cq.dbGetAllListeners()
@@ -131,13 +129,13 @@ proc restartListeners*(cq: Conquest) =
discard listener.runAsync()
cq.add(l)
cq.writeLine(fgGreen, "[+] ", resetStyle, "Restarted listener", fgGreen, fmt" {l.listenerId} ", resetStyle, fmt"on {l.address}:{$l.port}.")
cq.writeLine(fgGreen, "[ + ] ", resetStyle, "Restarted listener", fgGreen, fmt" {l.listenerId} ", resetStyle, fmt"on {l.address}:{$l.port}.")
# Delay before serving another listener to avoid crashing the application
waitFor sleepAsync(100)
except CatchableError as err:
cq.writeLine(fgRed, styleBright, "[-] Failed to restart listener: ", err.msg)
cq.writeLine(fgRed, styleBright, "[ - ] Failed to restart listener: ", err.msg)
cq.writeLine("")
@@ -147,14 +145,14 @@ proc listenerStop*(cq: Conquest, name: string) =
# Check if listener supplied via -n parameter exists in database
if not cq.dbListenerExists(name.toUpperAscii):
cq.writeLine(fgRed, styleBright, fmt"[-] Listener {name.toUpperAscii} does not exist.")
cq.writeLine(fgRed, styleBright, fmt"[ - ] Listener {name.toUpperAscii} does not exist.")
return
# Remove database entry
if not cq.dbDeleteListenerByName(name.toUpperAscii):
cq.writeLine(fgRed, styleBright, "[-] Failed to stop listener: ", getCurrentExceptionMsg())
cq.writeLine(fgRed, styleBright, "[ - ] Failed to stop listener: ", getCurrentExceptionMsg())
return
cq.delListener(name)
cq.writeLine(fgGreen, "[+] ", resetStyle, "Stopped listener ", fgGreen, name.toUpperAscii, resetStyle, ".")
cq.writeLine(fgGreen, "[ + ] ", resetStyle, "Stopped listener ", fgGreen, name.toUpperAscii, resetStyle, ".")

View File

@@ -1,4 +1,4 @@
import terminal, times, strformat, strutils
import times, strformat, strutils
import std/[dirs, paths]
import ../../common/[types, profile]
@@ -11,21 +11,17 @@ proc makeAgentLogDirectory*(cq: Conquest, agentId: string): bool =
return false
proc log*(cq: Conquest, logEntry: string) =
if cq.interactAgent == nil:
return
let
date = now().format("dd-MM-yyyy")
timestamp = now().format("dd-MM-yyyy HH:mm:ss")
cqDir = cq.profile.getString("conquest_directory")
agentLogPath = fmt"{cqDir}/data/logs/{cq.interactAgent.agentId}/{date}.log"
agentLogPath = fmt"{cqDir}/data/logs/{cq.interactAgent.agentId}/{date}.session.log"
# Write log entry to file
let file = open(agentLogPath, fmAppend)
file.writeLine(fmt"[{timestamp}] {logEntry}")
file.writeLine(fmt"{logEntry}")
file.flushFile()
proc extractStrings(args: string): string =
proc extractStrings*(args: string): string =
if not args.startsWith("("):
return args
@@ -34,24 +30,4 @@ proc extractStrings(args: string): string =
for str in args[1..^2].split(", "):
if str.startsWith("\""):
message &= str
return message.replace("\"", "")
template info*(cq: Conquest, args: varargs[untyped]) =
cq.writeLine(fgBlack, styleBright, "[*] ", resetStyle, args)
cq.log("[*] " & extractStrings($(args)))
template error*(cq: Conquest, args: varargs[untyped]) =
cq.writeLine(fgRed, styleBright, "[-] ", resetStyle, args)
cq.log("[-] " & extractStrings($(args)))
template warn*(cq: Conquest, args: varargs[untyped]) =
cq.writeLine(fgYellow, "[!] ", resetStyle, args)
cq.log("[!] " & extractStrings($(args)))
template success*(cq: Conquest, args: varargs[untyped]) =
cq.writeLine(fgGreen, "[+] ", resetStyle, args)
cq.log("[+] " & extractStrings($(args)))
template output*(cq: Conquest, args: varargs[untyped]) =
cq.writeLine(args)
cq.log("[>] " & extractStrings($(args)))
return message.replace("\"", "")

View File

@@ -1,10 +1,10 @@
import prompt, terminal, argparse, parsetoml
import strutils, strformat, times, system, tables
import ./[agent, listener, builder, logger]
import ./[agent, listener, builder]
import ../[globals, utils]
import ../db/database
import ../../common/[types, utils, crypto, profile]
import ../../common/[types, crypto, profile]
#[
Argument parsing
@@ -67,8 +67,7 @@ proc handleConsoleCommand(cq: Conquest, args: string) =
# Return if no command (or just whitespace) is entered
if args.replace(" ", "").len == 0: return
let date: string = now().format("dd-MM-yyyy HH:mm:ss")
cq.writeLine(fgBlue, styleBright, fmt"[{date}] ", resetStyle, styleBright, args)
cq.writeLine(fgBlue, styleBright, fmt"[{getTimestamp()}] ", resetStyle, styleBright, args)
try:
let opts = parser.parse(args.split(" ").filterIt(it.len > 0))
@@ -115,7 +114,7 @@ proc handleConsoleCommand(cq: Conquest, args: string) =
# Handle invalid arguments
except CatchableError:
cq.writeLine(fgRed, styleBright, "[-] ", getCurrentExceptionMsg())
cq.writeLine(fgRed, styleBright, "[ - ] ", getCurrentExceptionMsg())
cq.writeLine("")
@@ -150,8 +149,8 @@ proc startServer*(profilePath: string) =
try:
# Load and parse profile
let profile = parseFile(profilePath)
styledEcho(fgBlack, styleBright, "[*] ", "Using profile \"", profile.getString("name"), "\" (", profilePath ,").")
styledEcho(fgBlack, styleBright, "[*] ", "Using private key \"", profile.getString("private_key_file"), "\".")
styledEcho(fgBlack, styleBright, "[ * ] ", "Using profile \"", profile.getString("name"), "\" (", profilePath ,").")
styledEcho(fgBlack, styleBright, "[ * ] ", "Using private key \"", profile.getString("private_key_file"), "\".")
# Initialize framework context
cq = Conquest.init(profile)

View File

@@ -1,6 +1,5 @@
import times, strformat, terminal, tables, sequtils, strutils
import ./logger
import ../utils
import ../protocol/parser
import ../../modules/manager
@@ -49,15 +48,13 @@ proc handleHelp(cq: Conquest, parsed: seq[string]) =
cq.displayHelp()
except ValueError:
# Command was not found
cq.writeLine(fgRed, styleBright, fmt"[-] The command '{parsed[1]}' does not exist." & '\n')
cq.writeLine(fgRed, styleBright, fmt"[ - ] The command '{parsed[1]}' does not exist." & '\n')
proc handleAgentCommand*(cq: Conquest, input: string) =
# Return if no command (or just whitespace) is entered
if input.replace(" ", "").len == 0: return
let date: string = now().format("dd-MM-yyyy HH:mm:ss")
cq.writeLine(fgBlue, styleBright, fmt"[{date}] ", fgYellow, fmt"[{cq.interactAgent.agentId}] ", resetStyle, styleBright, input)
cq.log(fmt"Agent command received: {input}")
cq.writeLine(fgBlue, styleBright, fmt"[{getTimestamp()}] ", fgYellow, fmt"[{cq.interactAgent.agentId}] ", resetStyle, styleBright, input)
# Convert user input into sequence of string arguments
let parsedArgs = parseInput(input)
@@ -80,8 +77,8 @@ proc handleAgentCommand*(cq: Conquest, input: string) =
# Add task to queue
cq.interactAgent.tasks.add(task)
cq.info(fgBlack, styleBright, fmt"[{date}] [*] ", resetStyle, fmt"Tasked agent to {command.description.toLowerAscii()}")
cq.writeLine(fgBlack, styleBright, fmt"[{getTimestamp()}] [ * ] ", resetStyle, fmt"Tasked agent to {command.description.toLowerAscii()}")
except CatchableError:
cq.error(getCurrentExceptionMsg() & "\n")
cq.writeLine(getCurrentExceptionMsg() & "\n")
return