#144 Token Privileges
WindowsのTokenで遊んでみました。Tokenは、ユーザーのアクセス権限を管理するチケットのようなものですが、自分で書き換えることもできます。
例えば、下記のような特権情報もTokenに含まれています。
>whoami /priv
PRIVILEGES INFORMATION
----------------------
Privilege Name Description State
========================================= ================================================================== ========
SeIncreaseQuotaPrivilege Adjust memory quotas for a process Disabled
SeSecurityPrivilege Manage auditing and security log Disabled
SeTakeOwnershipPrivilege Take ownership of files or other objects Disabled
SeLoadDriverPrivilege Load and unload device drivers Disabled
SeSystemProfilePrivilege Profile system performance Disabled
SeSystemtimePrivilege Change the system time Disabled
SeProfileSingleProcessPrivilege Profile single process Disabled
SeIncreaseBasePriorityPrivilege Increase scheduling priority Disabled
SeCreatePagefilePrivilege Create a pagefile Disabled
SeBackupPrivilege Back up files and directories Disabled
SeRestorePrivilege Restore files and directories Disabled
SeShutdownPrivilege Shut down the system Disabled
SeDebugPrivilege Debug programs Disabled
SeSystemEnvironmentPrivilege Modify firmware environment values Disabled
SeChangeNotifyPrivilege Bypass traverse checking Enabled
SeRemoteShutdownPrivilege Force shutdown from a remote system Disabled
SeUndockPrivilege Remove computer from docking station Disabled
SeManageVolumePrivilege Perform volume maintenance tasks Disabled
SeImpersonatePrivilege Impersonate a client after authentication Enabled
SeCreateGlobalPrivilege Create global objects Enabled
SeIncreaseWorkingSetPrivilege Increase a process working set Disabled
SeTimeZonePrivilege Change the time zone Disabled
SeCreateSymbolicLinkPrivilege Create symbolic links Disabled
SeDelegateSessionUserImpersonatePrivilege Obtain an impersonation token for another user in the same session Disabled
それでは、書き換えてみましょう!
Enable Token Privileges
C++でプログラムを作りました。
#include <iostream>
#include <Windows.h>
BOOL CheckPrivilege(IN HANDLE hProcess, IN LPCSTR lpPrivilegeName, OUT HANDLE hToken) {
PTOKEN_PRIVILEGES pTokenPrivs = {};
DWORD dwLength = NULL;
if (!OpenProcessToken(hProcess, TOKEN_QUERY, &hToken)) {
return FALSE;
}
GetTokenInformation(hToken, TokenPrivileges, NULL, 0, &dwLength);
pTokenPrivs = (PTOKEN_PRIVILEGES)LocalAlloc(LPTR, dwLength);
GetTokenInformation(hToken, TokenPrivileges, pTokenPrivs, dwLength, &dwLength);
for (DWORD i = 0; i < pTokenPrivs->PrivilegeCount; i++) {
char szPrivilegeName[256];
LookupPrivilegeNameA(NULL, &pTokenPrivs->Privileges[i].Luid, szPrivilegeName, &dwLength);
if (strcmp(szPrivilegeName, lpPrivilegeName) == 0) {
printf("[+] %s %d \n", szPrivilegeName, pTokenPrivs->Privileges[i].Attributes & SE_PRIVILEGE_ENABLED);
}
}
}
BOOL ChangePrivilege(IN HANDLE hProcess, IN LPCSTR lpPrivilegeName, IN BOOL bEnablePrivilege, OUT HANDLE hToken) {
TOKEN_PRIVILEGES tp;
LUID luid;
OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken);
if (!LookupPrivilegeValueA(NULL, lpPrivilegeName, &luid)) {
printf("[!] LookupPrivilegeValueA failed with error : %d \n", GetLastError());
return FALSE;
}
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
if (bEnablePrivilege) {
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
}
else {
tp.Privileges[0].Attributes = SE_PRIVILEGE_REMOVED;
}
if (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), (PTOKEN_PRIVILEGES)NULL, (PDWORD)NULL)) {
printf("[!] AdjustTokenPrivileges failed with error : %d \n", GetLastError());
return FALSE;
}
return TRUE;
}
int main()
{
HANDLE hProcess = NULL;
HANDLE hToken = NULL;
LPCSTR lpPrivilegeName = "SeIncreaseQuotaPrivilege";
hProcess = GetCurrentProcess();
CheckPrivilege(hProcess, lpPrivilegeName, hToken);
ChangePrivilege(hProcess, lpPrivilegeName, true, hToken);
CheckPrivilege(hProcess, lpPrivilegeName, hToken);
}
実行すると、1回目と2回目でちゃんとPrivilegeが更新されていることがわかります。
>.\TokenTest.exe
[+] SeIncreaseQuotaPrivilege 0
[+] SeIncreaseQuotaPrivilege 2
こうして、必要な特権を有効化することで、別の攻撃につなげることができます…
EOF