首页 > 其他分享 >WIN32 动态 UAC 提权

WIN32 动态 UAC 提权

时间:2024-01-20 14:45:38浏览次数:32  
标签:pNetFwRule 对话框 WIN32 提权 put UAC include

UAC(User Account Control) 是 Windows 平台的用户权限控制。它可以让程序使用管理员权限执行某些操作。

静态 UAC 提权

静态 UAC 提权让程序一直运行在管理员权限下,只要在项目设置里把 "UAC Execution Level" 设置为 "requireAdministrator"。这样生成的 exe 文件图标会自动加上一个小盾牌的角标 Overlay。执行 exe 文件会自动弹出 UAC 对话框。

image-20240120115154732

静态 UAC 提权对程序员来说是一种偷懒的办法,只需要修改一个配置就行。但对用户来说非常麻烦,每次打开程序都需要确认 UAC 对话框。比如“小黑盒加速器”,每次打开它都会弹 UAC 对话框。更奇葩的是“小黑盒加速器” 可以设置开机自启,每次开机都会弹一个 UAC 对话框要你确认。

动态 UAC 提权

动态 UAC 提权让程序一直运行在普通用户权限下,并且只有需要管理员权限操作时才会弹出 UAC 对话框。这种做法比静态 UAC 提权更加细致。一个普通的应用程序 99% 的功能都不需要管理员权限,只在极少数情况下才需要。比如“QQ音乐”,它只是一个音乐播放软件。用户大部分的时间都仅使用音乐播放功能。而需要管理员权限的“将QQ音乐设为默认应用”功能很少会被使用。所以动态 UAC 提权很有必要。

按照微软官方文档 Developing Applications that Require Administrator Privilege,有四种方法可以实现动态 UAC 提权:

可以根据具体需要实现的功能选择合适的方法。比如:“添加防火墙规则”这个功能需要使用 INetFwPolicy2。这是一个 COM 接口,可以直接用第 4 种方法“Administrator COM Object Model”实现。使用这种方法有个前提,就是这个 COM 接口必须在注册表里是配置为可以提权的。比如 INetFwPolicy2 接口,先找到 NetFwPolicy2 的 GUID 为 E2B3C97F-6AE1-41AC-817A-F6F92166D7DD,再打开 regedit,输入 HKLM\Software\Classes\CLSID\{E2B3C97F-6AE1-41AC-817A-F6F92166D7DD}\ElevationEnabled 值为 1 就可以用。对于这种方法,The COM Elevation Moniker 介绍得比较详细,所以直接贴出完整代码:

#include <Windows.h>
#include <netfw.h>
#include <comdef.h>

#include <spdlog/spdlog.h>
#include <memory>
#include <filesystem>
#include <wil/resource.h>
#include <wil/com.h>
#include <iostream>

int add_firewall_rule();

int main()
{
    add_firewall_rule();
}

int add_firewall_rule()
{
    auto couninitialize_call = wil::CoInitializeEx();

    auto pNetFwPolicy2 = wil::CoCreateInstance<INetFwPolicy2>(__uuidof(NetFwPolicy2));

    wil::unique_cotaskmem_string clsid;
    RETURN_IF_FAILED(StringFromCLSID(__uuidof(NetFwPolicy2), &clsid));

    // https://learn.microsoft.com/en-us/windows/win32/secauthz/developing-applications-that-require-administrator-privilege
    // https://learn.microsoft.com/en-us/windows/win32/com/the-com-elevation-moniker
    BIND_OPTS3 bo{};
    bo.cbStruct = sizeof(bo);
    bo.hwnd = GetConsoleWindow();
    bo.dwClassContext = CLSCTX_LOCAL_SERVER;
    auto moniker = fmt::format(L"Elevation:Administrator!new:{}", clsid.get());
    spdlog::info(L"moniker: {}", moniker);
    auto hr = (CoGetObject(moniker.c_str(), &bo, IID_PPV_ARGS(&pNetFwPolicy2)));

    wil::com_ptr<INetFwRules> pNetFwRules;
    RETURN_IF_FAILED(pNetFwPolicy2->get_Rules(&pNetFwRules));

    long count{};
    RETURN_IF_FAILED(pNetFwRules->get_Count(&count));

    spdlog::info("rule count: {}", count);

    wil::com_ptr<IUnknown> pEnumerator;
    pNetFwRules->get__NewEnum(&pEnumerator);

    auto pVariant = pEnumerator.query<IEnumVARIANT>();

    std::vector<wchar_t> buf(1024);
    GetModuleFileNameW(nullptr, buf.data(), (DWORD)buf.size());
    std::filesystem::path exe_path(buf.data());

    // https://learn.microsoft.com/en-us/previous-versions/windows/desktop/ics/c-enumerating-firewall-rules
    while (true) {
        wil::unique_variant var;
        ULONG cFecthed = 0;
        if (pVariant->Next(1, &var, &cFecthed) != S_OK) {
            break;
        }

        wil::com_ptr<INetFwRule> pNetFwRule;
        var.pdispVal->QueryInterface(__uuidof(INetFwRule), (void**)&pNetFwRule);

        _bstr_t app_name;
        pNetFwRule->get_ApplicationName(app_name.GetAddress());
        std::error_code ec{};
        if (!app_name || !std::filesystem::equivalent(exe_path, (wchar_t*)app_name, ec)) {
            continue;
        }

        pNetFwRule->put_Name(app_name);
        pNetFwRules->Remove(app_name);
        spdlog::info(L"remove firewall rule: {}", (wchar_t*)app_name);
    }

    auto pNetFwRule = wil::CoCreateInstance<INetFwRule3>(__uuidof(NetFwRule));
    pNetFwRule->put_Enabled(VARIANT_TRUE);
    pNetFwRule->put_Action(NET_FW_ACTION_ALLOW);
    pNetFwRule->put_ApplicationName(_bstr_t(exe_path.c_str()));
    pNetFwRule->put_Profiles(NET_FW_PROFILE2_ALL);

    pNetFwRule->put_Name(_bstr_t(L"firewall-test.exe(TCP-In)"));
    pNetFwRule->put_Protocol(NET_FW_IP_PROTOCOL_TCP);
    RETURN_IF_FAILED(pNetFwRules->Add(pNetFwRule.get()));

    pNetFwRule->put_Name(_bstr_t(L"firewall-test.exe(UDP-In)"));
    pNetFwRule->put_Protocol(NET_FW_IP_PROTOCOL_UDP);
    RETURN_IF_FAILED(pNetFwRules->Add(pNetFwRule.get()));

    spdlog::info("success");
    return S_OK;
}

关于动态 UAC 提权的代码只有第 30-36 行。需要注意的点有:

  • 第 32 行的 bo.hwnd 设置 UAC 对话框的 owner。如果代码是控制台程序,应该设置为 GetConsoleWindow(),如果是 GUI 程序可以直接填 nullptr
  • 第 33 行的 bo.dwClassContext 应填 CLSCTX_LOCAL_SERVER,而不是 CLSCTX_INPROC_SERVER。否则提权失败,CoGetObject 仍然返回 S_OK
  • UAC 对话框出现在 CoGetObject 调用时,而不是执行需要管理员权限的操作(如pNetFwRules->Add)时。
  • 每次执行 add_firewall_rule() 都会弹出 UAC 对话框。

很多动态 UAC 提权的程序都会在需要管理员权限的操作按钮上显示一个小盾牌图标sheild,表示点击它会请求管理员权限,比如:

image-20240120141602183

可以直接调用 SHGetStockIconInfo 方法直接得到它的 HICON 句柄。

SHSTOCKICONINFO sii{};
sii.cbSize = sizeof(sii);
HRESULT hr = SHGetStockIconInfo(SIID_SHIELD, SHGSI_ICON | SHGSI_SMALLICON, &sii);
m_buttonRepairFirewall.SetIcon(sii.hIcon);
DestroyIcon(sii.hIcon);

标签:pNetFwRule,对话框,WIN32,提权,put,UAC,include
From: https://www.cnblogs.com/mkckr0/p/17976467

相关文章

  • win32com模块--------------------------------word文档转换PDF文档(格式转换)
    上代码:fromwin32com.clientimportgencachefromwin32com.clientimportconstants,gencache'''win32com库是Python语言与Windows操作系统中的COM(ComponentObjectModel)接口进行交互的工具库。它允许开发者使用Python来操作Windows系统中的各种COM组件,例如Office软件(Word、Exc......
  • BC实战后渗透之Bypass Applocker到提权
    0x01前言 提示:当个反面案例看就好,实际上拿下的方式远没有下文说的那么麻烦,只怪自己太心急… 本来是之前BC项目搞下来的一个推广站,当时只拿到了Shell权限是一个普通用户,想提权进一步收集服务器上的信息时,发现运行各种东西都是权限拒绝,提示组策略阻止了这个程序,当时因为还有的别......
  • vulnhub-devguru(sudo提权)
    环境准备:靶机192.168.0.100攻击机kali192.168.0.128演示使用nmap扫描全端口首先访问80端口 信息收集发现访问/.git/config存在,使用githack获取源码  访问adminer.php,为一个mysql的登录界面。 查找配置文件,找到mysql登录密码。/config/database.php 登录数......
  • vulnhub-toppo(suid提权sudo提权)
    环境准备靶机192.168.116.138攻击机kali192.168.116.130演示直接访问webadmin目录下存在密码本使用ssh连接,账号ted,密码12345ted123使用项目进行探测LinEnumhttps://github.com/rebootuser/LinEnum 存在python可以使用suid提权使用python反弹shell /usr/b......
  • vulnhub-matrix(cve-2022-0847提权)
    环境准备靶机matrix192.168.116.134攻击机kali192.168.116.130演示启动靶机,使用nmap探测网段nmap192.168.116.0/24 扫描192.168.116.134全端口nmap-p1-65535192.168.116.134 访问网站 扫描目录gobusterdir-uhttp://192.168.116.134/-xphp,bak,tx......
  • vulnhub-lampiao(linux脏牛提权)
    环境准备靶机-lampiao攻击机-kali演示使用nmap探测内网网络,我这里使用NAT网络,网段为192.168.116.0/24nmap192.168.116.0/24发现192.168.116.136存活,扫描全端口nmap-p1-65535192.168.116.136 访问1898端口发现为drupal使用msf来进行攻击searchdrupal......
  • 用C/C++(Win32API)写软件修改键位
    title:用C/C++(Win32API)写软件修改键位date:2021-06-25categories:编程tags:-键盘-注册表-C/C++-Windows前言紧接上篇《Windows用注册表修改键盘映射(扫描码)》,用起来会发现处处不协调,除了需要熟悉新键位以外,最重要的是原本的快捷键也被拆散了,如原本都在左下角的Ct......
  • 【Powershell】域用户提权
    适合人群:适合对Powershell和域有一定基础和感兴趣的运维。课程目标:利用Powershell和计划任务让普通用户能用管理员权限执行程序或脚本课程简介:以往都需要借助收费第三方软件来完成的事情,现在可以通过强大的Powershell完成。利用Powershell和计划任务让普通用户能用管理员权限执行......
  • 15.明明是x86的sos为什么会报不是有效的Win32应用程序
    最近在分析一个dump的时候,遇到了%1不是有效的Win32应用程序。这个错误,输出如下:*************Pathvalidationsummary**************ResponseTime(ms)LocationDeferredSRV*C:\mysymbols*http://msdl......
  • Stable Diffusion(SD-Webui)tag快速提权(降权)
    StableDiffusion(SD-Webui)tag的快速提权|降权:很简单:  1.选中tag(只要光标在你分词里面就行)  2.CRTRL+上下方向键(向上默认提0.1,向下默认减.0.1,当权为1时候会帮你自动消掉括号)完事请注意:中文逗号默认会被视为tag一部分!判断中英文逗号最简单的办法是看有没有贴贴,俩遍都......