导语:在本文,我们向你展示了如何使用不同的可用工具和在线资源在Windows RPC服务器中发现潜在的安全风险。
2018年8月底,一名自称“沙盒逃脱者”(SandboxEscaper)的女性研究人员发布了一个Windows本地权限升级0 day漏洞。另外,还附上一个概念性验证攻击程序,允许黑客读取系统中未经授权的区域,不过目前她的GitHub帐号已被封了。这是因为从该漏洞被公开发布到攻击者使用这一漏洞进行攻击,不到两周的时间,这让网络安全机构根本来不及应对。
安全研究人员相信,了解这种漏洞攻击的运行原理将极大的帮助他们找到类似SandboxEscaper在Windows任务计划程序(Windows Task Scheduler)中发现的漏洞。在这篇文章中,我们将讨论通过SandboxEscaper通过滥用RPC服务器上的符号链接来发现权限升级漏洞的方法。
继今年8月及10月之后, SandboxEscaper在12月又第三次公开披露了Windows的0 day漏洞了,尽管前两次都招致批评,且本月她还收到Google的警告通知,指出她已被FBI盯上,但SandboxEscaper似乎不为所动,依然不理会安全社群的“责任披露”原则,持续直接对外公开披露安全漏洞。
原来,Windows任务计划程序在其通过RPC服务器公开的远程过程调用(RPC)应用程序编程接口(API)中存在漏洞。事实上,大多数RPC服务器由运行本地系统权限的系统进程托管,并且允许具有较低权限的RPC客户端与它们交互。与其他软件一样,这些RPC服务器可能容易受到拒绝服务、内存损坏和逻辑漏洞等软件漏洞的影响。换句话说,攻击者可以利用RPC服务器中可能存在的任何漏洞发起攻击。
0 day漏洞如此迅速流行的原因之一是潜在的漏洞非常容易被利用,它是由程序逻辑漏洞引起的,只要使用正确的工具和技术,程序逻辑漏洞就很容易被发现。这种特殊类型的权限升级漏洞通常使用伪符号链接来升级文件或文件夹,进而导致普通用户的权限升级。对于感兴趣的人,网上有有大量关于符号链接攻击的资源。
如何在动态条件和静态条件下发现RPC服务器的漏洞
对于研究人员来说,在进行一个新的研究主题时,都会查看一下是否有可用的开源工具。幸运的是,Microsoft RPC是一个众所周知的协议,在过去的几十年中,研究人员对它进行了很好的逆向工程。比如,研究人员已经开源了一个名为RpcView的工具,它是识别运行在Windows操作系统上的RPC服务的一个非常方便的工具。这绝对是我最喜欢的RPC工具之一,具有许多高效实用的功能,例如搜索RPC接口通用惟一标识符(UUID)、RPC接口名称等。
但是,我们本文的目的不是将所有RPC信息反编译并导出到文本文件中。幸运的是,在阅读源代码时,我们发现其中已经包含了我们需要的功能,但是默认情况下它不会被启用,只能在调试模式下使用特定的命令行参数被触发。由于此限制,我们在启用该功能时,会将现有的DecompileAllInterfaces函数调整为RpcView GUI。如果你对使用这个功能感兴趣,可以在Github存储库中使用我们自定义的RpcView工具。我们现在可以在下一节中讨论“反编译所有接口” 功能的好处时,详细谈到。
RpcView会反编译所有接口
在分析RPC服务器的行为时,我们总是通过RPC接口调用API。通过RPC客户端向服务器发送RPC请求,然后使用SysInternals中的Process Monitor工具观察其行为,进而实现与感兴趣的RPC服务器的这种交互。在我看来,最方便的方法是通过脚本而不是重新编写需要程序编译的C / C ++ RPC客户端,编写很费时间。
本文,我们将使用的是PythonForWindows工具。它以Python化的方式提供了一些Windows功能的抽象,这在很大程度上依赖于Python的ctypes 模块。它还包含一个RPC库,该库提供了一些方便的包装函数,节省了我们编写RPC客户端时的时间。例如,典型的RPC客户端二进制文件需要定义接口定义语言,你需要手动实现绑定操作,这通常涉及一些c++代码,具体的请参见下面的代码段1和代码段2,它们演示了如何使用最少的漏洞处理代码编写RPC客户端脚本和编程之间的差异。
import sys import ctypes import windows.rpc import windows.generated_def as gdef from windows.rpc import ndr StorSvc_UUID = r"BE7F785E-0E3A-4AB7-91DE-7E46E443BE29" class SvcSetStorageSettingsParameters(ndr.NdrParameters): MEMBERS = [ndr.NdrShort, ndr.NdrLong, ndr.NdrShort, ndr.NdrLong] def SvcSetStorageSettings(): print "[+] Connecting...." client = windows.rpc.find_alpc_endpoint_and_connect(StorSvc_UUID, (0,0)) print "[+] Binding...." iid = client.bind(StorSvc_UUID, (0,0)) params = SvcSetStorageSettingsParameters.pack([0, 1, 2, 0x77]) print "[+] Calling SvcSetStorageSettings" result = client.call(iid, 0xb, params) if len(str(result)) > 0: print " [*] Call executed successfully!" stream = ndr.NdrStream(result) res = ndr.NdrLong.unpack(stream) if res == 0: print " [*] Success" else: print " [*] Failed" if __name__ == "__main__": SvcSetStorageSettings()
代码段1:使用PythonForWindows RPC客户端的SvcSetStorageSettings
RPC_STATUS CreateBindingHandle(RPC_BINDING_HANDLE *binding_handle) { RPC_STATUS status; RPC_BINDING_HANDLE v5; RPC_SECURITY_QOS SecurityQOS = {}; RPC_WSTR StringBinding = nullptr; RPC_BINDING_HANDLE Binding; StringBinding = 0; Binding = 0; status = RpcStringBindingComposeW(L"BE7F785E-0E3A-4AB7-91DE-7E46E443BE29", L"ncalrpc", nullptr, nullptr, nullptr, &StringBinding); if (status == RPC_S_OK) { status = RpcBindingFromStringBindingW(StringBinding, &Binding); RpcStringFreeW(&StringBinding); if (!status) { SecurityQOS.Version = 1; SecurityQOS.ImpersonationType = RPC_C_IMP_LEVEL_IMPERSONATE; SecurityQOS.Capabilities = RPC_C_QOS_CAPABILITIES_DEFAULT; SecurityQOS.IdentityTracking = RPC_C_QOS_IDENTITY_STATIC; status = RpcBindingSetAuthInfoExW(Binding, 0, 6u, 0xAu, 0, 0, (RPC_SECURITY_QOS*)&SecurityQOS); if (!status) { v5 = Binding; Binding = 0; *binding_handle = v5; } } } if (Binding) RpcBindingFree(&Binding); return status; } VOID RpcSetStorageSettings() { RPC_BINDING_HANDLE handle; RPC_STATUS status = CreateBindingHandle(&handle); if (status != RPC_S_OK) { _tprintf(TEXT("[-] Error creating handle %d\n"), status); return; } RpcTryExcept { if (!SUCCEEDED(SvcSetStorageSettings(0, 1, 2, 0x77)) { _tprintf(TEXT("[-] Error calling RPC API\n")); return; } } RpcExcept(1) { RpcStringFree(&instanceid); } RpcEndExcept }
代码段2:使用c++ RPC客户端的SvcSetStorageSettings
RPC客户端成功地执行了相应的RPC API之后,我们使用Process Monitor来监控其活动。流程监控器在动态分析中非常有用,因为它提供了基于事件的API运行时信息。Process Monitor是一款拥有功能强大的监控和过滤的高级WindowsProcess Monitor 工具,可实时显示文件系统、注册表、进程或线程的活动。它结合了两个 Sysinternals 的旧版工具 Filemon 和 Regmon 的功能,并添加了一个包含丰富的和非破坏性的广泛增强过滤功能列表,全面的事件属性(例如会话 ID 和用户名称),可靠的进程信息,每个操作的完整线程、堆栈与集成符号支持,同时记录到一个文件中,以及更多。如图2所示,它使你能够跟踪事件的API调用。
Process Monitor API调用堆栈
例如,在通过IDA Pro这样的反汇编程序进行静态分析时,我们可以使用地址和路径信息精确地指出对应的模块和函数例程。这很有用,因为有时你可能无法仅使用Process Monitor的输出信息来发现潜在的符号链接攻击模式。这就是为什么通过反汇编程序进行静态分析,以帮助我们发现竞态条件漏洞,这些漏洞将在本系列博客的第二部分中详细讨论。
微软通用遥测客户端(Universal Telemetry Client,UTC)案例研究
你听说过微软正在Windows 10及以上版本上收集客户信息、数据和文件启动信息吗?你有没有想过其中的运行原理?如果你感兴趣,可以在这篇关于UTC 的优秀文章中详细了解到。
在开始分析之前,我们首先将所有RPC接口从RpcView GUI导出到文本文件。生成的文本文件包含可从RPC服务器调用的所有RPC API。然后,我们从输出文本文件中查找接受宽字符串作为输入的RPC API,直到发现来自diagtrack.dll的一个更有趣的RPC接口。稍后,我们会确认此DLL组件负责UTC的功能是否实现,这可以通过Microsoft Windows Diagnostic Tracking的名称判断,以下是RpcView GUI中具体的描述信息。
RpcView显示了UTC的DLL组件,其中一个RPC接口接受宽字符串作为输入
由于我们的目标是找到可能接受最终导致权限升级的输入文件路径的API,正如Windows任务计划程序漏洞所示的那样。但是仅这个漏洞就提供了16个可能的API,如图3所示。显然,我们需要过滤掉那些我们不感兴趣的API。因此,我们必须使用IDA Pro并从静态分析开始,找出应该深入研究的API。
我通常会首先找到RPC函数RpcServerRegisterIf,它通常用于在RPC服务器上注册接口规范。接口规范包含由特定RPC服务器托管的RPC接口的定义。根据MSDN的说明,接口规范位于函数的第一个参数中,该参数由RPC_SERVER_INTERFACE数据结构表示,其定义如下所示:
struct _RPC_SERVER_INTERFACE { unsigned int Length; RPC_SYNTAX_IDENTIFIER InterfaceId; RPC_SYNTAX_IDENTIFIER TransferSyntax; PRPC_DISPATCH_TABLE DispatchTable; unsigned int RpcProtseqEndpointCount; PRPC_PROTSEQ_ENDPOINT RpcProtseqEndpoint; void *DefaultManagerEpv; const void *InterpreterInfo; unsigned int Flags; };
接口规范的InterpreterInfo是指向MIDL_SERVER_INFO数据结构的指针,该数据结构由DispatchTable指针组成,该指针保存特定RPC接口支持的接口API的信息,这些信息正是我们正在查找的内容。
typedef struct _MIDL_SERVER_INFO_ { PMIDL_STUB_DESC pStubDesc; const SERVER_ROUTINE* DispatchTable; PFORMAT_STRING ProcString; const unsigned short* FmtStringOffset; const STUB_THUNK* ThunkTable; PRPC_SYNTAX_IDENTIFIER pTransferSyntax; ULONG_PTR nCount; PMIDL_SYNTAX_INFO pSyntaxInfo; } MIDL_SERVER_INFO, *PMIDL_SERVER_INFO;
下图是一个动图,说明了我们如何遍历导入地址表以确定IDA Pro中的DispatchTable。
通过在IDA Pro中遍历IAT来确定RPC公开的API
在我们使用UtcAPI前缀确定UTC的接口API之后,如上图所示,我们会尝试确定这些接口API是否会导致访问控制列表(ACL) API,例如SetNamedSecurityInfo和SetSecurityInfo。之所以我们对这些ACL API感兴趣,是因为它们可以用于更改对象(无论是文件、目录还是注册表对象)的自主访问控制(DACL)安全描述符。IDA Pro中另一个可能未得到充分利用的有用功能是它的邻近视图(proximity view),它会显示一个函数例程的调用图,该函数例程将以图形的形式显示。我们可以使用邻近视图来查找前面提到的ACL API引用或调用的函数例程。
IDA的邻近视图,它显示了SetSecurityInfo和diag .dll中的函数例程之间的相关性
然而,当我们试图查找SetSecurityInfo和UtcAPI之间的相关性时,IDA Pro里并没有什么有价值的线索。进一步深入研究后,我们发现UtcAPI将客户端的RPC请求放置到将由异步线程处理的运行项队列中。如上图所示,当Microsoft::Diagnostic::EscalationWorkItem::Execute被触发时,SetSecurityInfo将会被执行。基本上,这是一个回调函数,负责执行RPC客户端提交的运行项中保存的升级请求。
此时,我们需要弄清楚如何提交升级请求。在试过各种应用程序之后,我们遇到了Microsoft Feedback Hub, Feedback Hub是微软在Windows 10系统上收集建议和反馈的官方应用,该应用除了用户表达关注、报告漏洞等,还充当了调试报告诊断信息的重要工具,在Windows 10上是默认安装的,是一个通用Windows平台(UWP)应用程序。有时候,你可能会发现调试UWP应用程序很有用。遗憾的是,你无法直接在WinDbg下打开或添加UWP应用程序,并期望它能神奇地运行。但是,你可以通过Windows 10 SDK中包含的窗口调试器(Window Debugger)附带的PLMDebug工具来启用UWP应用程序调试。我们可以先通过Powershell内置的cmdlet确定Feedback Hub的完整包系列名称:
PS C:\Users\researcher> Get-AppxPackage | Select-String -pattern "Feedback" Microsoft.WindowsFeedbackHub_1.1809.2971.0_x86__8wekyb3d8bbwe PS C:\Users\researcher> cd "c:\Program Files\Windows Kits\10\Debuggers\x86" PS C:\Program Files\Windows Kits\10\Debuggers\x86> PS C:\Program Files\Windows Kits\10\Debuggers\x86> .\plmdebug.exe /query Microsoft.WindowsFeedbackHub_1.1809.2971.0_x86__8wekyb3d8bbwe Package full name is Microsoft.WindowsFeedbackHub_1.1809.2971.0_x86__8wekyb3d8bbwe. Package state: Unknown SUCCEEDED PS C:\Program Files\Windows Kits\10\Debuggers\x86>
获得完整的包名称后,我们再次使用PLMDebug为Feedback Hub启用UWP调试。
c:\Program Files\Windows Kits\10\Debuggers\x86>plmdebug.exe /enabledebug Microsoft.WindowsFeedbackHub_1.1809.2971.0_x86__8wekyb3d8bbwe "c:\program files\windows kits\10\Debuggers\x86\windbg.exe" Package full name is Microsoft.WindowsFeedbackHub_1.1809.2971.0_x86__8wekyb3d8bbwe. Enable debug mode SUCCEEDED
这样在下次启动Feedback Hub时,应用程序将自动执行并添加到WinDbg。
确定来自Process Monitor事件属性的API调用的偏移量
启动Feedback Hub后,我们将按照应用程序的屏幕说明进行操作,并开始在Process Monitor中查看活动。这是一个好兆头,因为它意味着我们正在走上正轨。当我们查看突出显示的SetSecurityFile事件的调用堆栈时,就可以在偏移量0x15A091处找到ACL API SetSecurityInfo的返回地址(diagtrack.dll的基地址可以在Event Properties的Process选项卡中找到)。如你所见,这个偏移位于Microsoft::Diagnostics::Utils::FileSystem::SetTokenAclOnFile例程中,该例程不但出现在上图中的反汇编程序,并且也出现在图5中所示的邻近视图中。这证明了我们可以使用Feedback Hub来找到我们想要的代码路径。
除此之外,我们通过查看Process Monitor的输出内容还会发现,这个事件会试图设置文件对象的DACL,但是通过执行代码静态分析来确定文件对象是如何生成的可能会非常耗时。幸运的是,我们可以将本地调试器添加到具有管理权限的UTC服务的svchost.exe程序,因为该进程不受Protected Process Light(PPL)机制的保护,我们就可以灵活地动态调试UTC服务,以了解如何检索文件路径。
在后台,所有的反馈回来的详细信息和附件将通过Feedback Hub提交后保存在格式为%DOCUMENTS%\ FeedbackHub \ <guid> \ diagtracktempdir <random_decimals>的临时文件夹中。添加到diagtracktempdir的随机十进制数是通过BCryptGenRandom API生成的,这意味着生成的十进制数是不可预测的。但是,进行符号链接攻击最重要的条件之一是能够预测文件或文件夹的名称,因此,随机diagtracktempdir名称增加了利用符号链接漏洞的难度。所以,我们再想其他办法去查找其他潜在的漏洞。
在我们试图弄清楚如何设置diagtracktempdir安全描述符时,却发现该文件夹使用的是显式安全描述符字符串O:BAD:P(A;OICI;GA;; BA)(A;OICI;GA;; SY)创建的,这意味着对象的DACL将仅授予管理员和本地系统用户访问权限。但是,如果相应地设置了以下注册表项,则将忽略显式安全描述符:
HKEY_LOCAL_MACHINE\Software\Microsoft\Diagnostics\DiagTaskTestHooks\Volatile “NoForceCopyOutputDirAcl” = 1
简而言之,当上面的注册表项不存在时,diagtracktempdir将被强制使用显式的安全描述符,否则默认的DACL将应用于可能引发某些安全问题的文件夹,因为在文件夹创建过程中没有使用模拟令牌。不过,如果存在任意注册表写入漏洞,则可以将显式安全描述符绕过此文件夹。但这并不是我们的目的,所以我们最好的选择是再次调查Process Monitor。
设置DACL并重命名文件夹diagtracktempdir
基本上,我们可以将上图中标志的操作过程总结如下:
1.在本地系统权限下,授予对diagtracktempdir上当前登录用户的访问权限;
2.将diagtracktempdir重命名为模拟环境下的GUI样式的文件夹;
3.在模拟环境下撤消对diagtracktempdir上登录的当前用户的访问权限;
下面的代码段对应于上图所示的操作:
bQueryTokenSuccessful = UMgrQueryUserToken(hContext, v81, &hToken); if ( hToken && hToken != -1 ) { // This will GRANT access of the current logged in user to the directory in the specified handle bResultCopyDir = Microsoft::Diagnostics::Utils::FileSystem::SetTokenAclOnFile(&hToken, hDir, Sid, GRANT_ACCESS) if ( !ImpersonateLoggedOnUser(hToken) ) { bResultCopyDir = 0x80070542; } } // Rename diagtracktempdir to GUID-styled folder name bResultCopyDir = Microsoft::Diagnostics::Utils::FileSystem::MoveFileByHandle(SecurityDescriptor, v65, Length); if ( bResultCopyDir >= 0 ) { boolRenamedSuccessful = 1; // This will REVOKE access of the current logged in user to the directory in the specified handle bSetAclSucessful = Microsoft::Diagnostics::Utils::FileSystem::SetTokenAclOnFile(&hToken, hDir, Sid, REVOKE_ACCESS) if (bSetAclSucessful) { // Cleanup and RevertToSelf return; } } else { lambda_efc665df8d0c0615e3786b44aaeabc48_::operator_RevertToSelf(&hTokenUser); // Delete diagtracktempdir folder and its contents lambda_8963aeee26028500c2a1af61363095b9_::operator_RecursiveDelete(&v83); }
代码段3:先授予diagtracktempdir访问权限,然后撤销该访问权限
从代码段3中,我们可以判断文件重命名操作何时失败。如果bResultCopyDir的值小于0,它将继续调用RecursiveDelete函数。值得注意的是,在调用RecursiveDelete函数之前调用RevertToSelf函数来终止模拟,这意味着可以在本地系统权限下删除目标目录及其内容,如果我们设法使用一个符号链接将diagtracktempdir重定向到任意文件夹中,就能够实现任意文件删除。幸运的是,微软已经缓解了潜在的重解析点(reparse points)删除漏洞。此RecursiveDelete函数已显式跳过任何设置了FILE_ATTRIBUTE_REPARSE_POINT标志的目录或文件夹,该标志通常是为一个连接文件夹设置的,所以我们可以确认这个递归删除例程不会带来任何安全风险。
由于我们无法在此演示任意文件删除的过程,所以我们决定演示如何将任意文件写入diagtracktempdir目录。在查看代码时,我们意识到在递归删除例程完成后,UTC服务不会删除当前登录用户的diagtracktempdir的安全描述符。这是有意为之的,因为你不需要将新的DACL强加到将要删除的文件夹中,这是冗余的运行。但是,这也为攻击者提供了一个潜在的竞态条件机会,可以通过在同一个目录中创建具有独占文件句柄的文件来防止删除升级的diagtracktempdir。尝试使用独占文件句柄打开和删除文件时,RecursiveDelete函数遇到共享冲突,然后正常退出操作。毕竟,攻击者可以在受限制的目录中删除并执行升级的diagtracktetempdir中的文件,例如C:\WINDOWS\System32。
紧接着,我们会问文件重命名操作如何会失败?深入研究Microsoft::Diagnostics::Utils::FileSystem: MoveFileByHandle的底层实现,我们发现它本质上是一个调用SetFileInformationByHandle API的包装器函数。从这个API生成的底层内核函数似乎总是能够获得具有写入访问权限的父目录的文件句柄。例如,如果该句柄当前被引用到c:\blah\abc,它将尝试以c: blah的写入访问权限获取文件句柄。但是,如果我们删除一个当前登录用户的具有写入访问权限的目录,那么Microsoft::Diagnostics::Utils::FileSystem::MoveFileByHandle可能无法正确执行。以下文件路径就是一个很好的选择,因为它们是不允许为普通用户帐户创建文件夹的受限文件夹:
C:\WINDOWS\System32 C:\WINDOWS\tasks
由于某些升级请求会将一堆日志文件写入我们的受控diagtracktempdir并且它们将需要一些时间来删除,因此这个竞态条件不会有任何可以被利用的漏洞。因此,如果我们在目标目录中成功创建了一个独占文件句柄,那么在具有多个内核的现代系统中,竞态条件下的漏洞是不会发生的。
接下来,我们需要找到使用UtcAPI所需的正确参数以编程方式触发代码路径的方法。能够调试并设置RPC函数上的断点,Feedback Hub中的NdrClientCall确实使我们的运行更轻松。调试器会显示方案ID以及我们应该发送到UtcApi的升级路径。在本文的示例中,我们将使用方案ID {1881A45E-01FD-4452-ACE4-4A23666E66E3},因为它似乎总是在UtcAPI_EscalateScenarioAsync例程被触发时显示,并且它也会产生RPC服务器上所需的代码路径。请注意,升级路径还允许我们控制将创建diagtracktempdir的位置。
Breakpoint 0 hit eax=0c2fe7b8 ebx=032ae620 ecx=0e8be030 edx=00000277 esi=0c2fe780 edi=0c2fe744 eip=66887154 esp=0c2fe728 ebp=0c2fe768 iopl=0 nv up ei pl nz na po nc cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202 Helper+0x37154: 66887154 ff15a8f08866 call dword ptr [Helper!DllGetActivationFactory+0x6d31 (6688f0a8)] ds:0023:6688f0a8={RPCRT4!NdrClientCall4 (76a74940)} 0:027> dds esp l9 0c2fe728 66892398 Helper!DllGetActivationFactory+0xa021 0c2fe72c 66891dca Helper!DllGetActivationFactory+0x9a53 0c2fe730 0e8be030 0c2fe734 1881a45e // Scenario ID 0c2fe738 445201fd 0c2fe73c 234ae4ac 0c2fe740 e3666e66 0c2fe744 00000000 0c2fe748 032ae620 // Escalation path 0:027> du 032ae620 032ae620 "E:\researcher\Documents\Feedback" 032ae660 "Hub\{e04b7a09-02bd-42e8-a5a8-666" 032ae6a0 "b5102f5de}\{e04b7a09-02bd-42e8-a" 032ae6e0 "5a8-666b5102f5de}" 因此,utcAPI_escalatescenoasync的原型如下所示: long UtcApi_EscalateScenarioAsync ( [in] GUID SecnarioID, [in] int16 unknown, [in] wchar_t* wszEscalationPath [in] long unknown2, [in] long unknown3, [in] long num_of_keyval_pairs, [in] wchar_t **keys, [in] wchar_t **values)
综上所述,我们的概念证明(PoC)是这样的:
1.创建一个监控目标目录的无限线程,例如:C:\WINDOWS\ SYSTEM32, 以便捕获diagtracktempdir的文件夹名称;
2.创建另一个无限线程,它将在C:\WINDOWS\SYSTEM32\diagtracktempdir{random_decimal}\z中创建一个独占文件句柄;
3.调用UtcAPI_EscalateScenarioAsync(1881A45E-01FD-4452-ACE4-4A23666E66E3)来触发Microsoft::Diagnostic::EscalationWorkItem::Execute;
4.成功地创建C:\WINDOWS\SYSTEM32\ diagtracktempdir { random_decimal } \ z;
5.之后,攻击者可以将任意文件写入并在升级文件夹C:\WINDOWS\SYSTEM32\ diagtracktempdir { random_decimal }执行,以绕过一直认为%SYSTEM32%目录仅包含合法操作系统文件的合法程序;
PoC的结果演示了利用UTC服务在受限目录下的静态文件夹中创建任意文件和文件夹的可能方法。
PoC允许在diagtracktempdir中创建任意文件
重申一下,如果没有能够控制或重命名文件夹diagtracktempdir,这个PoC不会对Windows操作系统造成安全风险。然而,恶意软件的开发者会经常使用不同的技术(如用户帐户控制(UAC)绕过)来将文件写入Windows系统文件夹,以便绕过精巧的启发式扫描技术检测器。实际上,在探索PoC中使用的潜在文件路径时,我们发现C:\WINDOWS\SYSTEM32\Tasks包含普通用户账户的写入和执行权限。但是维度没有读取权限,这就是为什么这个文件夹也是恶意软件开发者用来存储恶意文件的一个目标路径。
总结
在本文,我们向你展示了如何使用不同的可用工具和在线资源在Windows RPC服务器中发现潜在的安全风险。我们还演示了对RPC服务器进行反向汇编所需的一些基本知识。我们坚信RPC服务器中还有其他潜在的安全漏洞。在下一篇文章中,我们将继续研究并改进强化Windows RPC服务器的方法,以便发现其他RPC服务器漏洞。