home *** CD-ROM | disk | FTP | other *** search
/ DEFCON 15 / DefCon15.bin / Speakers / Jennings / Extras / incognito / list_tokens.c < prev    next >
C/C++ Source or Header  |  2007-07-07  |  10KB  |  305 lines

  1. #define _CRT_SECURE_NO_DEPRECATE 1
  2. #include <stdio.h>
  3. #include <assert.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include <aclapi.h>
  7. #include <accctrl.h>
  8. #include <psapi.h>
  9. #include <tlhelp32.h>
  10. #include <lm.h>
  11. #include <wchar.h>
  12. #include "list_tokens.h"
  13. #include "token_info.h"
  14. #include "handle_arguments.h"
  15.  
  16.  
  17. typedef LONG   NTSTATUS;
  18. typedef VOID   *POBJECT;
  19.  
  20. typedef enum _OBJECT_INFORMATION_CLASS{
  21.    ObjectBasicInformation,
  22.       ObjectNameInformation,
  23.       ObjectTypeInformation,
  24.       ObjectAllTypesInformation,
  25.       ObjectHandleInformation
  26. } OBJECT_INFORMATION_CLASS;
  27.  
  28. typedef struct _SYSTEM_HANDLE {
  29.    ULONG           uIdProcess;
  30.    UCHAR           ObjectType;
  31.    UCHAR           Flags;
  32.    USHORT          Handle;
  33.    POBJECT         pObject;
  34.    ACCESS_MASK     GrantedAccess;
  35. } SYSTEM_HANDLE, *PSYSTEM_HANDLE;
  36.  
  37. typedef struct _SYSTEM_HANDLE_INFORMATION {
  38.    ULONG                   uCount;
  39.    SYSTEM_HANDLE   Handles[1];
  40. } SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;
  41.  
  42. typedef struct _UNICODE_STRING {
  43.    USHORT Length;
  44.    USHORT MaximumLength;
  45.    PWSTR  Buffer;
  46. } UNICODE_STRING;
  47.  
  48. #define STATUS_SUCCESS                          ((NTSTATUS)0x00000000L)
  49. #define STATUS_INFO_LENGTH_MISMATCH             ((NTSTATUS)0xC0000004L)
  50. #define STATUS_BUFFER_OVERFLOW                  ((NTSTATUS)0x80000005L)
  51. #define SystemHandleInformation                 16
  52.  
  53. typedef NTSTATUS (WINAPI *NTQUERYSYSTEMINFORMATION)(DWORD SystemInformationClass, 
  54.                                                     PVOID SystemInformation,
  55.                                                     DWORD SystemInformationLength, 
  56.                                                     PDWORD ReturnLength);
  57.  
  58. typedef NTSTATUS (WINAPI *NTQUERYOBJECT)(HANDLE ObjectHandle, 
  59.                                          OBJECT_INFORMATION_CLASS ObjectInformationClass, 
  60.                                          PVOID ObjectInformation,
  61.                                          DWORD Length, 
  62.                                          PDWORD ResultLength);
  63.  
  64. NTQUERYOBJECT              NtQueryObject ;
  65. NTQUERYSYSTEMINFORMATION   NtQuerySystemInformation; 
  66.  
  67. LPWSTR         GetObjectInfo(HANDLE hObject, OBJECT_INFORMATION_CLASS objInfoClass);
  68.  
  69. typedef UNICODE_STRING OBJECT_NAME_INFORMATION;
  70. typedef UNICODE_STRING *POBJECT_NAME_INFORMATION;
  71.  
  72. LPWSTR GetObjectInfo(HANDLE hObject, OBJECT_INFORMATION_CLASS objInfoClass)
  73. {
  74.    LPWSTR data = NULL;
  75.    DWORD dwSize = sizeof(OBJECT_NAME_INFORMATION);
  76.    POBJECT_NAME_INFORMATION pObjectInfo = (POBJECT_NAME_INFORMATION) malloc(dwSize);
  77.    
  78.    NTSTATUS ntReturn = NtQueryObject(hObject, objInfoClass, pObjectInfo, dwSize, &dwSize);   
  79.    if((ntReturn == STATUS_BUFFER_OVERFLOW) || (ntReturn == STATUS_INFO_LENGTH_MISMATCH)){
  80.       pObjectInfo =realloc(pObjectInfo ,dwSize);
  81.       ntReturn = NtQueryObject(hObject, objInfoClass, pObjectInfo, dwSize, &dwSize);
  82.    }
  83.    if((ntReturn >= STATUS_SUCCESS) && (pObjectInfo->Buffer != NULL))
  84.    {
  85.       data = (LPWSTR)calloc(pObjectInfo->Length, sizeof(WCHAR));
  86.       CopyMemory(data, pObjectInfo->Buffer, pObjectInfo->Length);
  87.    }
  88.    free(pObjectInfo);
  89.    return data;
  90. }
  91.  
  92. static int compare_token_names(const unique_user_token *a, const unique_user_token *b)
  93. {
  94.     return _stricmp(a->username, b->username);
  95. }
  96.  
  97. SavedToken *get_token_list(DWORD *num_tokens_enum)
  98. {
  99.     DWORD total=0, i, num_tokens=0, token_list_size = BUF_SIZE, dwSize = sizeof(SYSTEM_HANDLE_INFORMATION);
  100.     HANDLE process;
  101.     PSYSTEM_HANDLE_INFORMATION pHandleInfo;
  102.     NTSTATUS ntReturn;
  103.     SavedToken *token_list = (SavedToken*)calloc(token_list_size, sizeof(SavedToken)); 
  104.  
  105.     NtQuerySystemInformation = (NTQUERYSYSTEMINFORMATION)GetProcAddress(GetModuleHandle("NTDLL.DLL"), "NtQuerySystemInformation");
  106.     NtQueryObject= (NTQUERYOBJECT)GetProcAddress(GetModuleHandle("NTDLL.DLL"), "NtQueryObject");
  107.  
  108.     pHandleInfo = (PSYSTEM_HANDLE_INFORMATION)malloc(dwSize);
  109.     ntReturn = NtQuerySystemInformation(SystemHandleInformation, pHandleInfo, dwSize, &dwSize);
  110.    
  111.     if(ntReturn == STATUS_INFO_LENGTH_MISMATCH){
  112.         free(pHandleInfo);
  113.         pHandleInfo = (PSYSTEM_HANDLE_INFORMATION)malloc(dwSize);
  114.         ntReturn = NtQuerySystemInformation(SystemHandleInformation, pHandleInfo, dwSize, &dwSize);
  115.     }
  116.  
  117.     *num_tokens_enum = 0;
  118.  
  119.     if(ntReturn == STATUS_SUCCESS)
  120.     {
  121.         for(i = 0; i < pHandleInfo->uCount; i++)
  122.         {          
  123.             process = OpenProcess(MAXIMUM_ALLOWED,FALSE, pHandleInfo->Handles[i].uIdProcess);   
  124.             if(process != INVALID_HANDLE_VALUE)
  125.             {
  126.                 HANDLE hObject = NULL;
  127.                 if(DuplicateHandle(process, (HANDLE)pHandleInfo->Handles[i].Handle,
  128.                     GetCurrentProcess(), &hObject, MAXIMUM_ALLOWED, FALSE, 0x02) != FALSE)                  
  129.                 {
  130.                     LPWSTR lpwsType=NULL ;              
  131.                     lpwsType = GetObjectInfo(hObject, ObjectTypeInformation);
  132.                     
  133.                     if ((lpwsType!=NULL) && !wcscmp(lpwsType, L"Token") )
  134.                     {
  135.                         // Reallocate space if necessary
  136.                         if(*num_tokens_enum >= token_list_size)
  137.                         {
  138.                             token_list_size *= 2;
  139.                             token_list = (SavedToken*)realloc(token_list, token_list_size*sizeof(SavedToken));
  140.                             if (!token_list)
  141.                                 goto cleanup;
  142.                         }
  143.                         token_list[*num_tokens_enum].token = hObject;
  144.                         get_domain_username_from_token(hObject, token_list[*num_tokens_enum].username);
  145.                         (*num_tokens_enum)++;
  146.                     }
  147.                     else
  148.                         CloseHandle(hObject);
  149.                 }
  150.                 CloseHandle(process);
  151.             }
  152.         }
  153.     }
  154.  
  155. cleanup:
  156.     free(pHandleInfo);
  157.  
  158.     return token_list;
  159. }
  160.  
  161. void list_unique_tokens(TOKEN_ORDER token_order)
  162. {
  163.     DWORD num_unique_tokens = 0, num_tokens = 0, i;
  164.     unique_user_token *uniq_tokens = calloc(BUF_SIZE, sizeof(unique_user_token));
  165.     SavedToken *token_list = NULL;
  166.     BOOL bTokensAvailable = FALSE;
  167.  
  168.     // Enumerate tokens
  169.     output_string("[*] Enumerating tokens\n");
  170.     token_list = get_token_list(&num_tokens);
  171.  
  172.     if (!token_list)
  173.     {
  174.         output_string("[-] Failed to enumerate tokens with error code: %d\n", GetLastError());
  175.         return;
  176.     }
  177.  
  178.     // Process all tokens to get determinue unique names and delegation abilities
  179.     for (i=0;i<num_tokens;i++)
  180.     if (token_list[i].token)
  181.     {
  182.         process_user_token(token_list[i].token, uniq_tokens, &num_unique_tokens, token_order);
  183.         CloseHandle(token_list[i].token);
  184.     }
  185.  
  186.     if (token_list)
  187.         free(token_list);
  188.  
  189.     // Sort by name and then display all delegation and impersonation tokens
  190.     qsort(uniq_tokens, num_unique_tokens, sizeof(unique_user_token), compare_token_names);
  191.  
  192.     output_string("[*] Listing unique users found...\n\n");
  193.     output_string("Delegation Tokens Available\n");
  194.     output_string("============================================\n");
  195.  
  196.     for (i=0;i<num_unique_tokens;i++)
  197.     if (uniq_tokens[i].delegation_available)
  198.     {
  199.         bTokensAvailable = TRUE;
  200.         output_string("%s \n", uniq_tokens[i].username);
  201.     }
  202.  
  203.     if (!bTokensAvailable)
  204.         output_string("No tokens available\n");
  205.  
  206.     output_string("\nImpersonation Tokens Available\n");
  207.     output_string("============================================\n");
  208.  
  209.     bTokensAvailable = FALSE;
  210.  
  211.     for (i=0;i<num_unique_tokens;i++)
  212.     if (!uniq_tokens[i].delegation_available && uniq_tokens[i].impersonation_available)
  213.     {
  214.         bTokensAvailable = TRUE;
  215.         output_string("%s \n", uniq_tokens[i].username);
  216.     }
  217.  
  218.     if (!bTokensAvailable)
  219.         output_string( "No tokens available\n");
  220.  
  221.     for (i=0;i<num_unique_tokens;i++)
  222.         free(uniq_tokens[i].username);
  223.  
  224.     free(uniq_tokens);
  225. }
  226.  
  227. void process_user_token(HANDLE token, unique_user_token *uniq_tokens, DWORD *num_tokens, TOKEN_ORDER token_order)
  228. {
  229.     DWORD i, j, num_groups=0;
  230.     char *full_name, **group_name_array = NULL;
  231.     BOOL user_exists = FALSE;
  232.  
  233.     // If token is NULL then return
  234.     if (!token)
  235.         return;
  236.  
  237.     // Get token user or groups
  238.     if (token_order == BY_USER)
  239.     {
  240.         full_name = calloc(BUF_SIZE, sizeof(char));
  241.         num_groups = 1;
  242.         if (!get_domain_username_from_token(token, full_name))
  243.             goto cleanup;
  244.     }
  245.     else if (token_order == BY_GROUP)
  246.         if (!get_domain_groups_from_token(token, &group_name_array, &num_groups))
  247.             goto cleanup;
  248.     
  249.     for (i=0;i<num_groups;i++)
  250.     {
  251.         if (token_order == BY_GROUP)
  252.             full_name = (char*)group_name_array[i];
  253.  
  254.         // Check
  255.         if (!_stricmp("None", strchr(full_name, '\\') + 1) || !_stricmp("Everyone", strchr(full_name, '\\') + 1)
  256.             || !_stricmp("LOCAL", strchr(full_name, '\\') + 1) || !_stricmp("NULL SID", strchr(full_name, '\\') + 1))
  257.             continue;
  258.  
  259.         // Check to see if username has been seen before
  260.         for (j=0;j<*num_tokens;j++)
  261.         {
  262.             // If found then increment the number and set delegation flag if appropriate
  263.             if (!_stricmp(uniq_tokens[j].username, full_name))
  264.             {
  265.                 uniq_tokens[j].token_num++;
  266.                 user_exists = TRUE;
  267.                 if (is_delegation_token(token))
  268.                     uniq_tokens[j].delegation_available = TRUE;
  269.                 if (is_impersonation_token(token))
  270.                     uniq_tokens[j].impersonation_available = TRUE;
  271.                 break;
  272.             }
  273.         }
  274.  
  275.         // If token user has not been seen yet then create new entry
  276.         if (!user_exists)
  277.         {
  278.             strcpy(uniq_tokens[*num_tokens].username, full_name);
  279.             uniq_tokens[*num_tokens].token_num = 1;
  280.             uniq_tokens[*num_tokens].delegation_available = FALSE;
  281.             uniq_tokens[*num_tokens].impersonation_available = FALSE;
  282.  
  283.             if (is_delegation_token(token))
  284.                 uniq_tokens[*num_tokens].delegation_available = TRUE;
  285.             if (is_impersonation_token(token))
  286.                 uniq_tokens[*num_tokens].impersonation_available = TRUE;
  287.  
  288.             (*num_tokens)++;
  289.         }
  290.         else
  291.             user_exists = FALSE;
  292.  
  293.         // Cleanup
  294.         if (token_order == BY_GROUP && group_name_array[i])
  295.             free(group_name_array[i]);
  296.     }
  297.  
  298.     // Cleanup
  299. cleanup:
  300.     if (token_order == BY_GROUP && group_name_array)
  301.         free(group_name_array);
  302.     else if (token_order == BY_USER && full_name)
  303.         free(full_name);
  304. }
  305.