diff --git a/agents/monarch/nim.cfg b/agents/monarch/nim.cfg index 59c194a..d57a63a 100644 --- a/agents/monarch/nim.cfg +++ b/agents/monarch/nim.cfg @@ -1,5 +1,5 @@ # Agent configuration --d:ListenerUuid="HVVOGEOM" +-d:ListenerUuid="KPDHWZNT" -d:ListenerIp="localhost" --d:ListenerPort=5555 --d:SleepDelay=10 \ No newline at end of file +-d:ListenerPort=7777 +-d:SleepDelay=10 diff --git a/server/agent/agent.nim b/server/agent/agent.nim index 49e2aa2..a8722ee 100644 --- a/server/agent/agent.nim +++ b/server/agent/agent.nim @@ -1,4 +1,4 @@ -import terminal, strformat, strutils, sequtils, tables, json, times, base64 +import terminal, strformat, strutils, sequtils, tables, json, times, base64, system, osproc, streams import ./interact import ../[types, globals, utils] import ../db/database @@ -108,6 +108,56 @@ proc agentInteract*(cq: Conquest, name: string) = cq.interactAgent = nil +# Agent generation +proc agentBuild*(cq: Conquest, listener, sleep, payload: string) = + + # Verify that listener exists + if not cq.dbListenerExists(listener.toUpperAscii): + cq.writeLine(fgRed, styleBright, fmt"[-] Listener {listener.toUpperAscii} does not exist.") + return + + let listener = cq.listeners[listener.toUpperAscii] + + # Create/overwrite nim.cfg file to set agent configuration + let agentConfigFile = fmt"../agents/{payload}/nim.cfg" + + # The following shows the format of the agent configuration file that defines compile-time variables + let config = fmt""" + # Agent configuration + -d:ListenerUuid="{listener.name}" + -d:ListenerIp="{listener.address}" + -d:ListenerPort={listener.port} + -d:SleepDelay={sleep} + """.replace(" ", "") + writeFile(agentConfigFile, config) + + cq.writeLine(fgBlack, styleBright, "[*] ", resetStyle, "Configuration file created.") + + # Build agent by executing the ./build.sh script on the system. + let agentBuildScript = fmt"../agents/{payload}/build.sh" + + cq.writeLine(fgBlack, styleBright, "[*] ", resetStyle, "Building 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 + let process = startProcess(agentBuildScript, options={poUsePath, poStdErrToStdOut}) + let outputStream = process.outputStream + + var line: string + while outputStream.readLine(line): + cq.writeLine(line) + + let exitCode = process.waitForExit() + + # Check if the build succeeded or not + if exitCode == 0: + cq.writeLine(fgGreen, "[+] ", resetStyle, "Agent payload generated successfully.") + else: + cq.writeLine(fgRed, styleBright, "[-] ", resetStyle, "Build script exited with code ", $exitCode) + + except CatchableError as err: + cq.writeLine(fgRed, styleBright, "[-] ", resetStyle, "An error occurred: ", err.msg) + #[ Agent API Functions relevant for dealing with the agent API, such as registering new agents, querying tasks and posting results diff --git a/server/server.nim b/server/server.nim index 7c7f7b2..7831eb4 100644 --- a/server/server.nim +++ b/server/server.nim @@ -9,6 +9,7 @@ import agent/agent, listener/listener, db/database ]# var parser = newParser: help("Conquest Command & Control") + nohelpflag() command("listener"): help("Manage, start and stop listeners.") @@ -17,33 +18,41 @@ var parser = newParser: help("List all active listeners.") command("start"): help("Starts a new HTTP listener.") - 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("-i", "--ip", default=some("localhost"), help="IPv4 address to listen on.", required=false) + option("-p", "--port", help="Port to listen on.", required=true) + # TODO: Future features: # flag("--dns", help="Use the DNS protocol for C2 communication.") # flag("--doh", help="Use DNS over HTTPS for C2 communication.) command("stop"): help("Stop an active listener.") - option("-n", "-name", help="Name of the listener.", required=true) + option("-n", "--name", help="Name of the listener.", required=true) command("agent"): help("Manage, build and interact with agents.") command("list"): help("List all agents.") - option("-l", "-listener", help="Name of the listener.") + option("-l", "--listener", help="Name of the listener.") command("info"): help("Display details for a specific agent.") - option("-n", "-name", help="Name of the agent.", required=true) + option("-n", "--name", help="Name of the agent.", required=true) command("kill"): help("Terminate the connection of an active listener and remove it from the interface.") - option("-n", "-name", help="Name of the agent.", required=true) + option("-n", "--name", help="Name of the agent.", required=true) + # flag("--self-delete", help="Remove agent executable from target system.") command("interact"): help("Interact with an active agent.") - option("-n", "-name", help="Name of the agent.", required=true) + option("-n", "--name", help="Name of the agent.", required=true) + + command("build"): + help("Generate a new agent to connect to an active listener.") + option("-l", "--listener", help="Name of the listener.", required=true) + option("-s", "--sleep", help="Sleep delay in seconds.", default=some("10") ) + option("-p", "--payload", help="Agent type", choices = @["monarch"], default=some("monarch")) command("help"): nohelpflag() @@ -76,7 +85,7 @@ proc handleConsoleCommand*(cq: Conquest, args: varargs[string]) = of "list": cq.listenerList() of "start": - cq.listenerStart(opts.listener.get.start.get.host, opts.listener.get.start.get.port) + cq.listenerStart(opts.listener.get.start.get.ip, opts.listener.get.start.get.port) of "stop": cq.listenerStop(opts.listener.get.stop.get.name) else: @@ -92,6 +101,8 @@ proc handleConsoleCommand*(cq: Conquest, args: varargs[string]) = cq.agentKill(opts.agent.get.kill.get.name) of "interact": cq.agentInteract(opts.agent.get.interact.get.name) + of "build": + cq.agentBuild(opts.agent.get.build.get.listener, opts.agent.get.build.get.sleep, opts.agent.get.build.get.payload) else: cq.agentUsage() @@ -101,7 +112,7 @@ proc handleConsoleCommand*(cq: Conquest, args: varargs[string]) = cq.writeLine(err.help) # Handle invalid arguments - except UsageError: + except CatchableError: cq.writeLine(fgRed, styleBright, "[-] ", getCurrentExceptionMsg()) cq.writeLine("")