From d0ab25e521fdb050c3b2bc09539f651be396ced1 Mon Sep 17 00:00:00 2001 From: Spencer McIntyre <zeroSteiner@gmail.com> Date: Fri, 28 Oct 2022 15:54:46 -0400 Subject: [PATCH 1/3] Close memory and handle leaks --- .../source/extensions/incognito/list_tokens.c | 142 +++++++++--------- 1 file changed, 73 insertions(+), 69 deletions(-) diff --git a/c/meterpreter/source/extensions/incognito/list_tokens.c b/c/meterpreter/source/extensions/incognito/list_tokens.c index 2ea062cf..eef5ecb1 100644 --- a/c/meterpreter/source/extensions/incognito/list_tokens.c +++ b/c/meterpreter/source/extensions/incognito/list_tokens.c @@ -194,87 +194,90 @@ SavedToken *get_token_list(DWORD *num_tokens_enum, TOKEN_PRIVS *token_privs) { LPWSTR lpwsType = NULL; lpwsType = GetObjectInfo(hObject, ObjectTypeInformation); - if ((lpwsType != NULL) && !wcscmp(lpwsType, L"Token") && ImpersonateLoggedOnUser(hObject) != 0) + if (lpwsType) { - // ImpersonateLoggedOnUser() always returns true. Need to check whether impersonated token kept impersonate status - failure degrades to identification - // also revert to self after getting new token context - // only process if it was impersonation or higher - OpenThreadToken(GetCurrentThread(), MAXIMUM_ALLOWED, TRUE, &hObject2); - RevertToSelf(); - if (is_impersonation_token(hObject2)) + if (wcscmp(lpwsType, L"Token") && (ImpersonateLoggedOnUser(hObject))) { - // Reallocate space if necessary - if (*num_tokens_enum >= token_list_size) + // ImpersonateLoggedOnUser() always returns true. Need to check whether impersonated token kept impersonate status - failure degrades to identification + // also revert to self after getting new token context + // only process if it was impersonation or higher + OpenThreadToken(GetCurrentThread(), MAXIMUM_ALLOWED, TRUE, &hObject2); + RevertToSelf(); + if (is_impersonation_token(hObject2)) { - token_list_size *= 2; - token_list = (SavedToken*)realloc(token_list, token_list_size*sizeof(SavedToken)); - if (!token_list) + // Reallocate space if necessary + if (*num_tokens_enum >= token_list_size) { - goto cleanup; - } - } - - token_list[*num_tokens_enum].token = hObject; - get_domain_username_from_token(hObject, token_list[*num_tokens_enum].username); - - if (GetTokenInformation(hObject, TokenPrivileges, TokenPrivilegesInfo, BUF_SIZE, &returned_privileges_length)) - { - if (((TOKEN_PRIVILEGES*)TokenPrivilegesInfo)->PrivilegeCount > 0) - { - for (j = 0; j < ((TOKEN_PRIVILEGES*)TokenPrivilegesInfo)->PrivilegeCount; j++) + token_list_size *= 2; + token_list = (SavedToken*)realloc(token_list, token_list_size * sizeof(SavedToken)); + if (!token_list) { - returned_name_length = BUF_SIZE; - LookupPrivilegeNameW(NULL, &(((TOKEN_PRIVILEGES*)TokenPrivilegesInfo)->Privileges[j].Luid), privilege_name, &returned_name_length); - if (wcscmp(privilege_name, L"SeAssignPrimaryTokenPrivilege") == 0) + goto cleanup; + } + } + + token_list[*num_tokens_enum].token = hObject; + get_domain_username_from_token(hObject, token_list[*num_tokens_enum].username); + + if (GetTokenInformation(hObject, TokenPrivileges, TokenPrivilegesInfo, BUF_SIZE, &returned_privileges_length)) + { + if (((TOKEN_PRIVILEGES*)TokenPrivilegesInfo)->PrivilegeCount > 0) + { + for (j = 0; j < ((TOKEN_PRIVILEGES*)TokenPrivilegesInfo)->PrivilegeCount; j++) { - token_privs->SE_ASSIGNPRIMARYTOKEN_PRIVILEGE = TRUE; - } - else if (wcscmp(privilege_name, L"SeCreateTokenPrivilege") == 0) - { - token_privs->SE_CREATE_TOKEN_PRIVILEGE = TRUE; - } - else if (wcscmp(privilege_name, L"SeTcbPrivilege") == 0) - { - token_privs->SE_TCB_PRIVILEGE = TRUE; - } - else if (wcscmp(privilege_name, L"SeTakeOwnershipPrivilege") == 0) - { - token_privs->SE_TAKE_OWNERSHIP_PRIVILEGE = TRUE; - } - else if (wcscmp(privilege_name, L"SeBackupPrivilege") == 0) - { - token_privs->SE_BACKUP_PRIVILEGE = TRUE; - } - else if (wcscmp(privilege_name, L"SeRestorePrivilege") == 0) - { - token_privs->SE_RESTORE_PRIVILEGE = TRUE; - } - else if (wcscmp(privilege_name, L"SeDebugPrivilege") == 0) - { - token_privs->SE_DEBUG_PRIVILEGE = TRUE; - } - else if (wcscmp(privilege_name, L"SeImpersonatePrivilege") == 0) - { - token_privs->SE_IMPERSONATE_PRIVILEGE = TRUE; - } - else if (wcscmp(privilege_name, L"SeRelabelPrivilege") == 0) - { - token_privs->SE_RELABEL_PRIVILEGE = TRUE; - } - else if (wcscmp(privilege_name, L"SeLoadDriverPrivilege") == 0) - { - token_privs->SE_LOAD_DRIVER_PRIVILEGE = TRUE; + returned_name_length = BUF_SIZE; + LookupPrivilegeNameW(NULL, &(((TOKEN_PRIVILEGES*)TokenPrivilegesInfo)->Privileges[j].Luid), privilege_name, &returned_name_length); + if (wcscmp(privilege_name, L"SeAssignPrimaryTokenPrivilege") == 0) + { + token_privs->SE_ASSIGNPRIMARYTOKEN_PRIVILEGE = TRUE; + } + else if (wcscmp(privilege_name, L"SeCreateTokenPrivilege") == 0) + { + token_privs->SE_CREATE_TOKEN_PRIVILEGE = TRUE; + } + else if (wcscmp(privilege_name, L"SeTcbPrivilege") == 0) + { + token_privs->SE_TCB_PRIVILEGE = TRUE; + } + else if (wcscmp(privilege_name, L"SeTakeOwnershipPrivilege") == 0) + { + token_privs->SE_TAKE_OWNERSHIP_PRIVILEGE = TRUE; + } + else if (wcscmp(privilege_name, L"SeBackupPrivilege") == 0) + { + token_privs->SE_BACKUP_PRIVILEGE = TRUE; + } + else if (wcscmp(privilege_name, L"SeRestorePrivilege") == 0) + { + token_privs->SE_RESTORE_PRIVILEGE = TRUE; + } + else if (wcscmp(privilege_name, L"SeDebugPrivilege") == 0) + { + token_privs->SE_DEBUG_PRIVILEGE = TRUE; + } + else if (wcscmp(privilege_name, L"SeImpersonatePrivilege") == 0) + { + token_privs->SE_IMPERSONATE_PRIVILEGE = TRUE; + } + else if (wcscmp(privilege_name, L"SeRelabelPrivilege") == 0) + { + token_privs->SE_RELABEL_PRIVILEGE = TRUE; + } + else if (wcscmp(privilege_name, L"SeLoadDriverPrivilege") == 0) + { + token_privs->SE_LOAD_DRIVER_PRIVILEGE = TRUE; + } } } } - } - (*num_tokens_enum)++; + (*num_tokens_enum)++; + } + CloseHandle(hObject2); } - CloseHandle(hObject2); + free(lpwsType); } - else - { + else { CloseHandle(hObject); } } @@ -353,6 +356,7 @@ SavedToken *get_token_list(DWORD *num_tokens_enum, TOKEN_PRIVS *token_privs) { dprintf("[INCOGNITO] Failed next level impersonation with %u (%x)", GetLastError(), GetLastError()); } + CloseHandle(process); } dprintf("[INCOGNITO] Moving to next process from %p", pProcessInfo); From 80e8b721efb0959117be17cc079097bb1dfd1a04 Mon Sep 17 00:00:00 2001 From: Spencer McIntyre <zeroSteiner@gmail.com> Date: Thu, 10 Nov 2022 15:34:18 -0500 Subject: [PATCH 2/3] Close the handle when it wasn't copied Close the hObject handle when it wasn't copied into token_list. --- .../source/extensions/incognito/list_tokens.c | 134 ++++++++++-------- 1 file changed, 75 insertions(+), 59 deletions(-) diff --git a/c/meterpreter/source/extensions/incognito/list_tokens.c b/c/meterpreter/source/extensions/incognito/list_tokens.c index eef5ecb1..b35ba357 100644 --- a/c/meterpreter/source/extensions/incognito/list_tokens.c +++ b/c/meterpreter/source/extensions/incognito/list_tokens.c @@ -189,8 +189,7 @@ SavedToken *get_token_list(DWORD *num_tokens_enum, TOKEN_PRIVS *token_privs) { hObject = NULL; - if (DuplicateHandle(process, (HANDLE)(DWORD_PTR)((i + 1) * 4), - GetCurrentProcess(), &hObject, MAXIMUM_ALLOWED, FALSE, 0x02) != FALSE) + if (DuplicateHandle(process, (HANDLE)(DWORD_PTR)((i + 1) * 4), GetCurrentProcess(), &hObject, MAXIMUM_ALLOWED, FALSE, 0x02)) { LPWSTR lpwsType = NULL; lpwsType = GetObjectInfo(hObject, ObjectTypeInformation); @@ -273,8 +272,14 @@ SavedToken *get_token_list(DWORD *num_tokens_enum, TOKEN_PRIVS *token_privs) (*num_tokens_enum)++; } + else { + CloseHandle(hObject); + } CloseHandle(hObject2); } + else { + CloseHandle(hObject); + } free(lpwsType); } else { @@ -285,76 +290,87 @@ SavedToken *get_token_list(DWORD *num_tokens_enum, TOKEN_PRIVS *token_privs) // Also process primary // if has impersonate privs, only needs read access - if (OpenProcessToken(process, MAXIMUM_ALLOWED, &hObject) && ImpersonateLoggedOnUser(hObject)) + if (OpenProcessToken(process, MAXIMUM_ALLOWED, &hObject)) { - // ImpersonateLoggedOnUser() always returns true. Need to check whether impersonated token kept impersonate status - failure degrades to identification - // also revert to self after getting new token context - // only process if it was impersonation or higher - if (OpenThreadToken(GetCurrentThread(), MAXIMUM_ALLOWED, TRUE, &hObject2)) - { - RevertToSelf(); - if (is_impersonation_token(hObject2)) + if (ImpersonateLoggedOnUser(hObject)) { + // ImpersonateLoggedOnUser() always returns true. Need to check whether impersonated token kept impersonate status - failure degrades to identification + // also revert to self after getting new token context + // only process if it was impersonation or higher + if (OpenThreadToken(GetCurrentThread(), MAXIMUM_ALLOWED, TRUE, &hObject2)) { - token_list[*num_tokens_enum].token = hObject; - get_domain_username_from_token(hObject, token_list[*num_tokens_enum].username); - (*num_tokens_enum)++; - - if (GetTokenInformation(hObject, TokenPrivileges, TokenPrivilegesInfo, BUF_SIZE, &returned_privileges_length)) + RevertToSelf(); + if (is_impersonation_token(hObject2)) { - for (i = 0; i < ((TOKEN_PRIVILEGES*)TokenPrivilegesInfo)->PrivilegeCount; i++) + token_list[*num_tokens_enum].token = hObject; + get_domain_username_from_token(hObject, token_list[*num_tokens_enum].username); + (*num_tokens_enum)++; + + if (GetTokenInformation(hObject, TokenPrivileges, TokenPrivilegesInfo, BUF_SIZE, &returned_privileges_length)) { - returned_name_length = BUF_SIZE; - LookupPrivilegeNameW(NULL, &(((TOKEN_PRIVILEGES*)TokenPrivilegesInfo)->Privileges[i].Luid), privilege_name, &returned_name_length); - if (wcscmp(privilege_name, L"SeAssignPrimaryTokenPrivilege") == 0) + for (i = 0; i < ((TOKEN_PRIVILEGES*)TokenPrivilegesInfo)->PrivilegeCount; i++) { - token_privs->SE_ASSIGNPRIMARYTOKEN_PRIVILEGE = TRUE; - } - else if (wcscmp(privilege_name, L"SeCreateTokenPrivilege") == 0) - { - token_privs->SE_CREATE_TOKEN_PRIVILEGE = TRUE; - } - else if (wcscmp(privilege_name, L"SeTcbPrivilege") == 0) - { - token_privs->SE_TCB_PRIVILEGE = TRUE; - } - else if (wcscmp(privilege_name, L"SeTakeOwnershipPrivilege") == 0) - { - token_privs->SE_TAKE_OWNERSHIP_PRIVILEGE = TRUE; - } - else if (wcscmp(privilege_name, L"SeBackupPrivilege") == 0) - { - token_privs->SE_BACKUP_PRIVILEGE = TRUE; - } - else if (wcscmp(privilege_name, L"SeRestorePrivilege") == 0) - { - token_privs->SE_RESTORE_PRIVILEGE = TRUE; - } - else if (wcscmp(privilege_name, L"SeDebugPrivilege") == 0) - { - token_privs->SE_DEBUG_PRIVILEGE = TRUE; - } - else if (wcscmp(privilege_name, L"SeImpersonatePrivilege") == 0) - { - token_privs->SE_IMPERSONATE_PRIVILEGE = TRUE; - } - else if (wcscmp(privilege_name, L"SeRelabelPrivilege") == 0) - { - token_privs->SE_RELABEL_PRIVILEGE = TRUE; - } - else if (wcscmp(privilege_name, L"SeLoadDriverPrivilege") == 0) - { - token_privs->SE_LOAD_DRIVER_PRIVILEGE = TRUE; + returned_name_length = BUF_SIZE; + LookupPrivilegeNameW(NULL, &(((TOKEN_PRIVILEGES*)TokenPrivilegesInfo)->Privileges[i].Luid), privilege_name, &returned_name_length); + if (wcscmp(privilege_name, L"SeAssignPrimaryTokenPrivilege") == 0) + { + token_privs->SE_ASSIGNPRIMARYTOKEN_PRIVILEGE = TRUE; + } + else if (wcscmp(privilege_name, L"SeCreateTokenPrivilege") == 0) + { + token_privs->SE_CREATE_TOKEN_PRIVILEGE = TRUE; + } + else if (wcscmp(privilege_name, L"SeTcbPrivilege") == 0) + { + token_privs->SE_TCB_PRIVILEGE = TRUE; + } + else if (wcscmp(privilege_name, L"SeTakeOwnershipPrivilege") == 0) + { + token_privs->SE_TAKE_OWNERSHIP_PRIVILEGE = TRUE; + } + else if (wcscmp(privilege_name, L"SeBackupPrivilege") == 0) + { + token_privs->SE_BACKUP_PRIVILEGE = TRUE; + } + else if (wcscmp(privilege_name, L"SeRestorePrivilege") == 0) + { + token_privs->SE_RESTORE_PRIVILEGE = TRUE; + } + else if (wcscmp(privilege_name, L"SeDebugPrivilege") == 0) + { + token_privs->SE_DEBUG_PRIVILEGE = TRUE; + } + else if (wcscmp(privilege_name, L"SeImpersonatePrivilege") == 0) + { + token_privs->SE_IMPERSONATE_PRIVILEGE = TRUE; + } + else if (wcscmp(privilege_name, L"SeRelabelPrivilege") == 0) + { + token_privs->SE_RELABEL_PRIVILEGE = TRUE; + } + else if (wcscmp(privilege_name, L"SeLoadDriverPrivilege") == 0) + { + token_privs->SE_LOAD_DRIVER_PRIVILEGE = TRUE; + } } } } + else { + CloseHandle(hObject); + } + CloseHandle(hObject2); } - - CloseHandle(hObject2); + else { + CloseHandle(hObject); + } + } + else { + dprintf("[INCOGNITO] Failed next level impersonation, ImpersonateLoggedOnUser failed with %u (%x)", GetLastError(), GetLastError()); + CloseHandle(hObject); } } else { - dprintf("[INCOGNITO] Failed next level impersonation with %u (%x)", GetLastError(), GetLastError()); + dprintf("[INCOGNITO] Failed next level impersonation, OpenProcessToken failed with %u (%x)", GetLastError(), GetLastError()); } CloseHandle(process); } From f5bae3b63cf72d8929604eff5914738cb573bbec Mon Sep 17 00:00:00 2001 From: Grant Willcox <gwillcox@rapid7.com> Date: Thu, 10 Nov 2022 15:56:05 -0600 Subject: [PATCH 3/3] Cleanup handles if memory allocation fails before exiting get_token_list --- c/meterpreter/source/extensions/incognito/list_tokens.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/c/meterpreter/source/extensions/incognito/list_tokens.c b/c/meterpreter/source/extensions/incognito/list_tokens.c index b35ba357..02d8da7d 100644 --- a/c/meterpreter/source/extensions/incognito/list_tokens.c +++ b/c/meterpreter/source/extensions/incognito/list_tokens.c @@ -211,6 +211,9 @@ SavedToken *get_token_list(DWORD *num_tokens_enum, TOKEN_PRIVS *token_privs) token_list = (SavedToken*)realloc(token_list, token_list_size * sizeof(SavedToken)); if (!token_list) { + CloseHandle(hObject2); + CloseHandle(hObject); + CloseHandle(process); goto cleanup; } }