8000 Windows 降权 · Issue #101 · holdyounger/ScopeBlog · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content
Windows 降权 #101
Open
Open
@holdyounger

Description

@holdyounger

Windows 降权

[toc]

背景说明

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

解决方案

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

实现逻辑

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

  1. 获取token
  2. 通过token获取用户的会话ID
  3. 通过token和ID启动进程

代码

接口

最终调用的接口为: CreateProcessAsUser

int 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;
}

实现

实现如下所示:

/*
* @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是否被提升:

BOOL 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

HANDLE 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;
}

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

/*
* @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;
}

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

bool 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;
}

调用接口创建进程:

typedef 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;
}

blog link Windows 降权

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      0