【权限与会话】降权

分类: 英国365bet体育在线 📅 2025-09-19 10:22:15 👤 admin 👁️ 3755 ❤️ 279
【权限与会话】降权

阅读这篇文章你可以了解:

降权操作,Windows服务进程中以低权限创建进程

[toc]

【权限与会话】 Service降权启动进程

【权限与会话】提权工具

【权限与会话】提权

背景说明

在服务程序中调用了某一个程序的安装程序,由于权限的问题,这个安装程序也继承了服务的 SYSTEM 权限,导致安装程序与预期不符合。

解决方案

最终实现的目标就是在服务中以普通用户的权限去启动安装程序,要以普通用户去启动,就涉及到降权的问题,需要获取用户的信息。在任务管理器详细信息中可以看到,资源管理器是以普通用户的身份启动的,因此可以在服务中以 Explore.exe 的权限去调用安装程序。

实现逻辑

此逻辑也可以用于解决 UAC 弹窗的问题。

获取token

通过token获取用户的会话ID

通过token和ID启动进程

代码

接口

最终调用的接口为: CreateProcessAsUser

12345678910111213141516int ExecutePackage(LPCSTR pszPath, LPCSTR pszParams){ if (nullptr == pszPath) return -1; wstring szPath = stringToWstring(pszPath); wstring szParams; if (pszParams) { szParams = stringToWstring(pszParams); } CreateProcessWithAdmin(szPath.c_str(), szParams.c_str()); return 0;}

实现

实现如下所示:

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960/** @fn * @brief CreateProcessWithAdmin* @param[in] * strpath: 程序路径* strParams: 程序执行命令* @param[out] * @return * * @detail */bool CreateProcessWithAdmin(LPCWSTR lpExePath, LPCWSTR lpParam){ HANDLE hExplorerToken = GetExplorerToken(); HANDLE hTokenDup = NULL; LPVOID pEnvironment = nullptr; bool res{ false }; char szErr[256] = { 0 }; int iErrCode = 0; do { if (hExplorerToken == NULL) { iErrCode = GetLastError(); break; } // 复制令牌,把调用方有效的所有访问权限给复制后的令牌. DWORD dwReturnBytes = 0; DWORD dwReturnLen = 0; DWORD dwTokenSessionId = 0; // 通过token获取sessionId if (::GetTokenInformation(hExplorerToken, TokenSessionId, &dwTokenSessionId, sizeof(DWORD), &dwReturnLen) == FALSE) { break; } // 通过 SessionId 和 Token运行程序- res = _CreateProcessAsSystemBySession(lpExePath, lpParam, NULL, dwTokenSessionId, hExplorerToken); // 改动如下所示 // 改动 // 判断当前特权token是否已提升,如果已经提升,则直接通过当前的token启动,如果未提升,则通过提升后的token启动+ HANDLE hNewToken = NULL;+ if (GetElevatedToken(hExplorerToken, &hNewToken) && hNewToken)+ {+ res = CreateProcessByToken(hNewToken, hExplorerToken, lpExePath, lpParam, NULL, FALSE);+ CloseHandle(hNewToken);+ }+ else+ {+ res = CreateProcessAsSystemBySession(lpExePath, lpParam, NULL, dwTokenSessionId, hExplorerToken);+ }+ CloseHandle(hExplorerToken); } while (false); return res;}

判断token是否被提升:

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152BOOL IsElevatedToken(HANDLE hToken, PBOOL pbElevated){ DWORD dwReturnBytes = 0; DWORD dwElevateionType = 0; BOOL bElevated = FALSE; if (hToken && pbElevated) { if (GetTokenInformation(hToken, TokenElevationType, &dwElevateionType, sizeof(dwElevateionType), &dwReturnBytes)) { if (dwElevateionType == TokenElevationTypeFull) bElevated = TRUE; else if (dwElevateionType == TokenElevationTypeDefault) { TOKEN_ELEVATION te; ZeroMemory(&te, sizeof(te)); if (GetTokenInformation(hToken, TokenElevation, &te, sizeof(te), &dwReturnBytes)) { if (te.TokenIsElevated) bElevated = TRUE; } } } if (pbElevated) *pbElevated = bElevated; return TRUE; } return FALSE;}BOOL GetElevatedToken(HANDLE hToken, PHANDLE phNewToken){ BOOL bElevated = FALSE; IsElevatedToken(hToken, &bElevated); if (bElevated) { return DuplicateTokenEx(hToken, TOKEN_ALL_ACCESS, NULL, SecurityImpersonation, TokenPrimary, phNewToken); } else { DWORD dwReturnBytes = 0; return GetTokenInformation(hToken, TokenLinkedToken, phNewToken, sizeof(HANDLE), &dwReturnBytes); } return FALSE;}

获取资源管理器的 token

1234567891011121314151617181920212223242526272829303132333435363738HANDLE GetExplorerToken(){ PromotePrivilege(); HANDLE hSnapshot = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (hSnapshot == INVALID_HANDLE_VALUE) { return NULL; } HANDLE hExplorerToken = NULL; PROCESSENTRY32 pe = { 0 }; pe.dwSize = sizeof(pe); BOOL bMore = ::Process32First(hSnapshot, &pe); while (bMore) { if (StrCmpI(L"explorer.exe", pe.szExeFile) == 0) { HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pe.th32ProcessID); if (hProcess == NULL) { continue; } if (OpenProcessToken(hProcess, TOKEN_QUERY, &hExplorerToken)) { CloseHandle(hProcess); break; } } bMore = ::Process32Next(hSnapshot, &pe); } CloseHandle(hSnapshot); return hExplorerToken;}

给本进程特权,以便访问系统进程

123456789101112131415161718192021222324252627282930313233343536373839404142/** @fn PromotePrivilege* @brief 调整进程权限 * * @detail 将进程权限提升成具有调试权限的进程,这个权限应该是进程所能具有的最大权限* 前提启动这个进程的账户必须是一个管理员,否则没法提升*/BOOL PromotePrivilege(){ // 附给本进程特权,以便访问系统进程 HANDLE hToken; // 打开一个进程的访问令牌 if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) { // 取得特权名称为"SetDebugPrivilege"的LUID LUID uID; if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &uID)) { CloseHandle(hToken); return FALSE; } // 调整特权级别 TOKEN_PRIVILEGES tp; tp.PrivilegeCount = 1; // 只启动调试权限,所以权限的个数是一个 tp.Privileges[0].Luid = uID; //当Attributes = SE_PRIVILEGE_ENABLE时,激活权限 //当Attributes = 0时,关闭权限 tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; // AdjustTokenPrivileges函数激活或者关闭tp中给定的权限 if (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(tp), NULL, NULL)) { CloseHandle(hToken); return FALSE; } // 关闭访问令牌句柄 CloseHandle(hToken); return TRUE; } return FALSE;}

设置当前进程的会话信息:

1234567891011121314151617181920212223242526272829bool CreateProcessAsSystemBySession(LPCTSTR pszAppName, LPCTSTR pszCmd, LPCTSTR pszCwd, DWORD dwSession, HANDLE hEnvToken){ if (pszCmd == NULL) return false; bool bRet = false; HANDLE hTokenThis = NULL; bRet = OpenProcessToken(GetCurrentProcess(), TOKEN_DUPLICATE | TOKEN_QUERY, &hTokenThis); if (!bRet || hTokenThis == NULL) return false; HANDLE hTokenDup = NULL; bRet = DuplicateTokenEx(hTokenThis, MAXIMUM_ALLOWED, NULL, SecurityIdentification, TokenPrimary, &hTokenDup); CloseHandle(hTokenThis); if (!bRet || hTokenDup == NULL) return false; if (!SetTokenInformation(hTokenDup, TokenSessionId, &dwSession, sizeof(DWORD))) { CloseHandle(hTokenDup); return false; } bRet = CreateProcessByToken(hTokenDup, hEnvToken, pszAppName, pszCmd, pszCwd, TRUE); CloseHandle(hTokenDup); return bRet;}

调用接口创建进程:

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566typedef BOOL(STDMETHODCALLTYPE FAR* LPFNCREATEENVIRONMENTBLOCK) (LPVOID* lpEnvironment, HANDLE hToken, BOOL bInherit);typedef BOOL(STDMETHODCALLTYPE FAR* LPFNDESTROYENVIRONMENTBLOCK) (LPVOID lpEnvironment);bool CreateProcessByToken(HANDLE hToken, HANDLE hEnvToken, LPCTSTR pszAppName, LPCTSTR pszCmd, LPCTSTR pszCwd, BOOL bWndHide/* = FALSE*/){ STARTUPINFO si = { sizeof(si) }; PROCESS_INFORMATION pi = { 0 }; si.lpDesktop = (LPWSTR)L"Winsta0\\Default"; if (bWndHide) { si.dwFlags = STARTF_USESHOWWINDOW; si.wShowWindow = SW_HIDE; } DWORD dwCreationFlag = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE; LPVOID pEnvironment = NULL; LPFNCREATEENVIRONMENTBLOCK lpfnCreateEnvironmentBlock = NULL; LPFNDESTROYENVIRONMENTBLOCK lpfnDestroyEnvironmentBlock = NULL; HMODULE hUserEnvLib = NULL; hUserEnvLib = LoadLibrary(L"userenv.dll"); if (NULL != hUserEnvLib) { lpfnCreateEnvironmentBlock = (LPFNCREATEENVIRONMENTBLOCK)GetProcAddress(hUserEnvLib, "CreateEnvironmentBlock"); lpfnDestroyEnvironmentBlock = (LPFNDESTROYENVIRONMENTBLOCK)GetProcAddress(hUserEnvLib, "DestroyEnvironmentBlock"); } if (NULL != lpfnCreateEnvironmentBlock) { if (lpfnCreateEnvironmentBlock(&pEnvironment, hEnvToken, FALSE)) { dwCreationFlag |= CREATE_UNICODE_ENVIRONMENT; // must specify } else pEnvironment = NULL; } bool bRet = false; BOOL bDisableRedirect = FALSE; if (CreateProcessAsUser(hToken, pszAppName, (LPTSTR)pszCmd, NULL, NULL, FALSE, dwCreationFlag, pEnvironment, pszCwd, &si, &pi)) { CloseHandle(pi.hThread); DWORD dwRet = WaitForSingleObject(pi.hProcess, 2 * 60 * 60 * 1000); if (WAIT_TIMEOUT == dwRet) { } else if (WAIT_OBJECT_0 == dwRet) { bRet = true; } CloseHandle(pi.hProcess); } if (NULL != lpfnDestroyEnvironmentBlock) lpfnDestroyEnvironmentBlock(pEnvironment); if (NULL != hUserEnvLib) FreeLibrary(hUserEnvLib); return bRet;}

相关文章