因此,我试图通过复制来自提升进程的令牌来查看是否可以为当前进程获得提升特权。
1。在进程1中,我用admin调用进程2,并传递了进程1的PID:
RunAsAdmin(L"test.exe /admin pid"); // Calls ShellExecute with runas and waits to finish
2。在提升的过程中,我正在复制提升的令牌(已删除错误检查):
HANDLE h3 = 0;
OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &h3);
// Verification if token is elevated, yes it is
TOKEN_ELEVATION te;
TOKEN_ELEVATION_TYPE tet;
DWORD l;
GetTokenInformation(h3, TOKEN_INFORMATION_CLASS::TokenElevation, &te, sizeof(te), &l);
GetTokenInformation(h3, TOKEN_INFORMATION_CLASS::TokenElevationType, &tet, sizeof(tet), &l);
// Duplicate the token to the process which we have the PID from cmdline:
auto hProcess = OpenProcess(PROCESS_ALL_ACCESS, false, pid);
HANDLE nh = 0;
DuplicateHandle(GetCurrentProcess(), h3, hProcess, &nh, 0, 0,DUPLICATE_SAME_ACCESS);
// Verification if new handle is elevated, yes it is
// Pass token to process
PassNewTokenToProcess(nh); // Currently I'm using clipboard, later I will use file mapping.
3。在过程1中,我正在获取令牌:
HANDLE hTok = GetTokenFromClipboard();
// Verify it's elevated, yes it is.
// Duplicate it to myself
HANDLE hTok2;
DuplicateTokenEx(hTok, TOKEN_ALL_ACCESS, 0, SecurityImpersonation, TokenPrimary, &hTok2);
// Verify it's elevated, yes it is.
// Impersonate
ImpersonateLoggedOnUser(hTok2); // Returns true
RegCreateKeyEx(HKEY_LOCAL_MACHINE, L"SOFTWARE\\TestXXX", 0, 0, 0, KEY_ALL_ACCESS, ...);
// Fails error 5 access denied
最后一次通话失败。我知道我做错了什么,但是令牌随着GetTokenInformation
的返回而升高。
我可以在某个地方验证新令牌确实无法真正提升当前流程吗?
非常感谢。
答案 0 :(得分:0)
通话中的问题
// Impersonate
ImpersonateLoggedOnUser(hTok2); // Returns true
尽管ImpersonateLoggedOnUser
返回true,但实际上函数不能等待您的等待。
所有模拟功能(包括 ImpersonateLoggedOnUser )均允许 如果满足以下条件之一,则请求模拟:
- 请求的令牌模拟级别小于 SecurityImpersonation ,例如 SecurityIdentification 或 SecurityAnonymous 。
- 呼叫者具有 SeImpersonatePrivilege 特权。
...
因此,即使对于有效的 hToken api也会失败,但不是以通常的方式-而不是返回false并设置错误代码-api仍然返回true,但是将线程令牌的模拟级别默默地重置为{{ 1}}。在所有这些调用之后,进行安全检查的调用将以SecurityIdentification
或ERROR_BAD_IMPERSONATION_LEVEL
失败。
通常,未提升权限的进程没有ERROR_ACCESS_DENIED
特权,因此,当我们尝试使用提升权限的令牌模拟时,正式呼叫 不会失败,而是获得了SeImpersonatePrivilege
的模拟级别SecurityIdentification
。即使提升权限(或 LocalSystem ,甚至内核模式)也尝试将提升令牌设置为没有SecurityImpersonation
特权的进程中的线程-此尝试仅设置SeImpersonatePrivilege
级别。>
我们可以通过SecurityIdentification
调用来方便地检查并查询OpenThreadToken
。
完整的测试代码:
TokenImpersonationLevel
所以这是设计使然-通过从进程令牌中删除inline ULONG BOOL_TO_ERROR(BOOL f)
{
return f ? NOERROR : GetLastError();
}
void WINAPI entry(void*)
{
HANDLE hToken, hThread, hDupToken;
ULONG dwError;
// for attach debugger
MessageBoxW(0, 0, GetCommandLineW(), 0);
if (PWSTR c = wcschr(GetCommandLineW(), '*'))
{
ULONG dwThreadId = wcstoul(c + 1, &c, 16);
dwError = ERROR_INVALID_PARAMETER;
if (!*c && dwThreadId)
{
dwError = BOOL_TO_ERROR(OpenProcessToken(GetCurrentProcess(), TOKEN_DUPLICATE|TOKEN_IMPERSONATE, &hToken));
if (dwError == NOERROR)
{
dwError = BOOL_TO_ERROR(DuplicateToken(hToken, ::SecurityImpersonation, &hDupToken));
CloseHandle(hToken);
if (dwError == NOERROR)
{
if (hThread = OpenThread(THREAD_SET_THREAD_TOKEN, FALSE, dwThreadId))
{
dwError = RtlNtStatusToDosError(
ZwSetInformationThread(hThread, ThreadImpersonationToken, &hDupToken, sizeof(hDupToken))
);
CloseHandle(hThread);
}
else
{
dwError = GetLastError();
}
CloseHandle(hDupToken);
}
}
}
ExitProcess(dwError);
}
WCHAR file[MAX_PATH], params[32];
if (GetModuleFileNameW(0, file, RTL_NUMBER_OF(file)))
{
SHELLEXECUTEINFOW sei = {
sizeof(sei), SEE_MASK_NOCLOSEPROCESS, 0, L"runas", file, params
};
swprintf(params, L"*%x", GetCurrentThreadId());
dwError = BOOL_TO_ERROR(ShellExecuteExW(&sei));
if (dwError == NOERROR)
{
switch (WaitForSingleObject(sei.hProcess, INFINITE))
{
case WAIT_OBJECT_0:
if (GetExitCodeProcess(sei.hProcess, &dwError))
{
break;
}
case WAIT_FAILED:
dwError = GetLastError();
break;
default:
__debugbreak();
dwError = ERROR_GEN_FAILURE;
}
CloseHandle(sei.hProcess);
if (dwError == NOERROR)
{
if (OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE, &hToken))
{
ULONG cb;
SECURITY_IMPERSONATION_LEVEL sil;
if (GetTokenInformation(hToken, ::TokenImpersonationLevel, &sil, sizeof(sil), &cb))
{
DbgPrint("ImpersonationLevel = %x\n", sil);
}
CloseHandle(hThread);
}
union {
HANDLE hFile;
HKEY hKey;
};
hFile = CreateFileW(file, 0, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
if (hFile == INVALID_HANDLE_VALUE)
{
DbgPrint("CreateFile=%u\n", GetLastError());
}
else
{
CloseHandle(hFile);
}
dwError = RegOpenKeyExW(HKEY_CURRENT_USER, 0, 0, KEY_READ, &hKey);
if (dwError)
{
DbgPrint("OpenKey=%u\n", dwError);
}
else
{
RegCloseKey(hKey);
}
}
}
}
ExitProcess(dwError);
}
来禁用未提升的进程(小于“ <高>完整性级别”的进程)来模拟提升的令牌。在设置较高或更高的完整性级别时,所有冒充他人的尝试都是有效的。