System/Windows
Windows LUID 값과 Token을 이용한 Privilege 변경
Tribal
2018. 3. 28. 01:34
LUID
Process와 Thread 가질 수 있는 권한에 대한 64bit 크기의 식별자, Access Token의 정보에 포함되어 있다.
LUID(Locally Unique IDentifier) 목록(line 번호가 LUID 값)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | #define SE_CREATE_TOKEN_NAME TEXT("SeCreateTokenPrivilege") #define SE_ASSIGNPRIMARYTOKEN_NAME TEXT("SeAssignPrimaryTokenPrivilege") #define SE_LOCK_MEMORY_NAME TEXT("SeLockMemoryPrivilege") #define SE_INCREASE_QUOTA_NAME TEXT("SeIncreaseQuotaPrivilege") #define SE_UNSOLICITED_INPUT_NAME TEXT("SeUnsolicitedInputPrivilege") #define SE_MACHINE_ACCOUNT_NAME TEXT("SeMachineAccountPrivilege") #define SE_TCB_NAME TEXT("SeTcbPrivilege") #define SE_SECURITY_NAME TEXT("SeSecurityPrivilege") #define SE_TAKE_OWNERSHIP_NAME TEXT("SeTakeOwnershipPrivilege") #define SE_LOAD_DRIVER_NAME TEXT("SeLoadDriverPrivilege") #define SE_SYSTEM_PROFILE_NAME TEXT("SeSystemProfilePrivilege") #define SE_SYSTEMTIME_NAME TEXT("SeSystemtimePrivilege") #define SE_PROF_SINGLE_PROCESS_NAME TEXT("SeProfileSingleProcessPrivilege") #define SE_INC_BASE_PRIORITY_NAME TEXT("SeIncreaseBasePriorityPrivilege") #define SE_CREATE_PAGEFILE_NAME TEXT("SeCreatePagefilePrivilege") #define SE_CREATE_PERMANENT_NAME TEXT("SeCreatePermanentPrivilege") #define SE_BACKUP_NAME TEXT("SeBackupPrivilege") #define SE_RESTORE_NAME TEXT("SeRestorePrivilege") #define SE_SHUTDOWN_NAME TEXT("SeShutdownPrivilege") #define SE_DEBUG_NAME TEXT("SeDebugPrivilege") #define SE_AUDIT_NAME TEXT("SeAuditPrivilege") #define SE_SYSTEM_ENVIRONMENT_NAME TEXT("SeSystemEnvironmentPrivilege") #define SE_CHANGE_NOTIFY_NAME TEXT("SeChangeNotifyPrivilege") #define SE_REMOTE_SHUTDOWN_NAME TEXT("SeRemoteShutdownPrivilege") #define SE_UNDOCK_NAME TEXT("SeUndockPrivilege") #define SE_SYNC_AGENT_NAME TEXT("SeSyncAgentPrivilege") #define SE_ENABLE_DELEGATION_NAME TEXT("SeEnableDelegationPrivilege") #define SE_MANAGE_VOLUME_NAME TEXT("SeManageVolumePrivilege") #define SE_IMPERSONATE_NAME TEXT("SeImpersonatePrivilege") #define SE_CREATE_GLOBAL_NAME TEXT("SeCreateGlobalPrivilege") #define SE_TRUSTED_CREDMAN_ACCESS_NAME TEXT("SeTrustedCredManAccessPrivilege") #define SE_RELABEL_NAME TEXT("SeRelabelPrivilege") #define SE_INC_WORKING_SET_NAME TEXT("SeIncreaseWorkingSetPrivilege") #define SE_TIME_ZONE_NAME TEXT("SeTimeZonePrivilege") #define SE_CREATE_SYMBOLIC_LINK_NAME TEXT("SeCreateSymbolicLinkPrivilege") | cs |
※ LUID 항목별 설명(MSDN) : https://msdn.microsoft.com/en-us/library/windows/desktop/bb530716(v=vs.85).aspx
현재 Process의 Privilege 확인 코드
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | #include <Windows.h> #include <tchar.h> #include <cstdio> #include <sddl.h> DWORD GetPrivilege(void) { DWORD dwLen; BOOL bRes; HANDLE hToken; if (!OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &hToken)) { fprintf(stderr, "[-] OpenProcessToken error : %u\n", GetLastError()); return FALSE; } bRes = GetTokenInformation( hToken, TokenPrivileges, NULL, 0, &dwLen ); if (!bRes) { CloseHandle(hToken); delete[] pBuffer; return FALSE; } BYTE* pBuffer = new BYTE[dwLen]; if (pBuffer == NULL) { CloseHandle(hToken); return FALSE; } bRes = GetTokenInformation( hToken, TokenPrivileges, pBuffer, dwLen, &dwLen ); if (!bRes) { CloseHandle(hToken); delete[] pBuffer; return FALSE; } TOKEN_PRIVILEGES* pPrivs = (TOKEN_PRIVILEGES*)pBuffer; for (DWORD i = 0; i < pPrivs->PrivilegeCount; i++) { printf("LUID : %u %u, Attriutes : %u\n", pPrivs->Privileges[i].Luid.HighPart, pPrivs->Privileges[i].Luid.LowPart, pPrivs->Privileges[i].Attributes); } delete[] pBuffer; CloseHandle(hToken); if (!bRes) return FALSE; return TRUE; } int main(void) { if (!GetPrivilege()) return -1; return 0; } | cs |
- 11번째 줄 : 현재 Process의 Access Token을 가져옴
- 20번째 줄 : 2번째 인자인 TokenPrivilege를 질의로 하여 dwLen에 Privilege 배열의 전체 크기를 받아옴
- 34번째 줄 : Privilege 배열의 전체 크기를 받아올 수 있도록 메모리 할당
- 41번째 줄 : 다시 한 번 질의를 하여 할당해둔 메모리에 질의에 대한 결과 저장
- 55번째 줄 : LUID와 Attributes 출력
현재 Process의 Privilege 확인 코드 결과
Attributes 값
1 2 3 4 5 6 7 8 9 10 11 12 | // Privilege attributes // #define SE_PRIVILEGE_ENABLED_BY_DEFAULT (0x00000001L) #define SE_PRIVILEGE_ENABLED (0x00000002L) #define SE_PRIVILEGE_REMOVED (0X00000004L) #define SE_PRIVILEGE_USED_FOR_ACCESS (0x80000000L) #define SE_PRIVILEGE_VALID_ATTRIBUTES (SE_PRIVILEGE_ENABLED_BY_DEFAULT | \ SE_PRIVILEGE_ENABLED | \ SE_PRIVILEGE_REMOVED | \ SE_PRIVILEGE_USED_FOR_ACCESS) | cs |
Privilege 세팅 코드
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | #include <Windows.h> #include <tchar.h> #include <cstdio> #include <sddl.h> static BOOL g_flag; DWORD GetPrivilege(void) { DWORD dwLen; BOOL bRes; HANDLE hToken; if (!OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &hToken)) { fprintf(stderr, "[-] OpenProcessToken error : %u\n", GetLastError()); return FALSE; } bRes = GetTokenInformation( hToken, TokenPrivileges, NULL, 0, &dwLen ); BYTE* pBuffer = new BYTE[dwLen]; if (pBuffer == NULL) { CloseHandle(hToken); return FALSE; } bRes = GetTokenInformation( hToken, TokenPrivileges, pBuffer, dwLen, &dwLen ); if (!bRes) { CloseHandle(hToken); delete[] pBuffer; return FALSE; } TOKEN_PRIVILEGES* pPrivs = (TOKEN_PRIVILEGES*)pBuffer; if(g_flag) puts("================== Before ================"); else puts("================== After ================"); for (DWORD i = 0; i < pPrivs->PrivilegeCount; i++) { printf("LUID : %u %u, Attriutes : %u\n", pPrivs->Privileges[i].Luid.HighPart, pPrivs->Privileges[i].Luid.LowPart, pPrivs->Privileges[i].Attributes); } delete[] pBuffer; CloseHandle(hToken); if (!bRes) return FALSE; return TRUE; } BOOL SetPrivilege(void) { HANDLE hToken; LUID luid; if (!OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES| TOKEN_QUERY, &hToken)) { fprintf(stderr, "[-] OpenProcessToken error : %u\n", GetLastError()); return FALSE; } if (!LookupPrivilegeValue( NULL, SE_DEBUG_NAME, &luid)) { fprintf(stderr, "[-] LookupPrivilegeValue error : %u\n", GetLastError()); return FALSE; } TOKEN_PRIVILEGES tp; tp.PrivilegeCount = 1; tp.Privileges[0].Luid = luid; tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; if (!AdjustTokenPrivileges( hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), (PTOKEN_PRIVILEGES)NULL, (PDWORD)NULL)) { fprintf(stderr, "[-] AdjustTokenPrivileges error : %u\n", GetLastError()); return FALSE; } CloseHandle(hToken); return TRUE; } int main(void) { g_flag = TRUE; if (!GetPrivilege()) return 0; if (!SetPrivilege()) return 0; g_flag = FALSE; if (!GetPrivilege()) return 0; return 0; } | cs |
- 7번째 줄 : 위에서 본 것과 동일한 Privilege를 확인하는 함수이다.
- 74번째 줄 : 2번째 인자로 Privilege를 적용시키기 위한 TOKEN_ADJUST_PRIVILEGES를 추가하였다.
- 83번째 줄 : SE_DEBUG_NAME에 해당하는 LUID 값(20)을 가져온다. 저 값을 확인해보면 20인 것을 확인할 수 있다.
- 92번째 줄 : 세팅하기 위한 TOKEN_PRIVILEGE를 추가한다.
- 97번째 줄 : TokenPrivileges를 세팅한다.
- 119번째 줄 : 다시 확인해보면 20이 2(SE_PRIVILEGE_ENABLED)로 변경된 것을 확인할 수 있다.
Privilege 세팅 코드 결과(관리자로 실행, Before에 출력되었던 LUID만 결과를 볼 수 있음)
LUID가 20(SE_DEBUG_NAME)인 Attributes가 2로 변경된 것을 확인할 수 있다.