欢迎来到 嗅灵易学

零基础也能上手的脚本技术课,一对一答疑带你入门

[翻译]RPC Bug挖掘实例研究 - 第一部分

[翻译]RPC Bug挖掘实例研究 - 第一部分

原文:https://www.fortinet.com/blog/threat-research/the-case-studies-of-microsoft-windows-remote-procedure-call-serv.html

翻译:玉林小学生                   校对:Nxe


        2018年8月,一个网名为SandboxEscaper的研究者公开了一个Windows本地提权0-day。在0-day被公开在网上的几周内,该漏洞的利用工具就被恶意软件作者大量使用。如ESET所说,这件事在InfoSec社区引起了一些混乱。这件事也引起了FortiGuard实验室的注意。

        FortiGuard实验室相信理解这个攻击的原理有助于其它研究者找到与SandboxEscaper发现的Windows Task Scheduler中类似的漏洞。本文我们将介绍找到滥用RPC服务的一个符号链接进行提权的漏洞的方法。

        该漏洞表明Windows Task Scheduler在一个RPC(Remote Procedure Calls) 服务提供的RPC API中有缺陷。事实上,大多数RPC服务由system权限的系统进程提供,准许低权限的RPC客户端与其进行交互。和其它软件一样,这些RPC服务易被拒绝服务、内存破坏和逻辑错误一类的问题影响。也就是说攻击者能够利用RPC服务中存在的脆弱性。

        这个0-day被如此迅速如此大范围利用的一个原因是其基于的攻击点很容易被利用。它由一个程序的逻辑错误引起,使用正确的工具和技术很容易地发现这个问题。这类特殊的提权脆弱性只需一个链接到特权文件或目录的符号链接就可以进行利用,将最终导致一个普通用户进行特权提升。如果感兴趣,Google Project Zero的James Forshaw分享了许多关于符号链接攻击的资源。

RPC服务运行时和静态分析预备知识

        当开始一个新研究时,在动手自己写工具前通常先从scratch找找看是否有可以利用的开源工具。幸运的是,微软RPC是一个著名的协议,研究者在过去许多年间对其进行了大量的逆向研究。研究者开源了一款叫RpcView的工具,这是一个识别Windows操作系统上运行的RPC服务的很好的工具。这是我最爱的RPC工具之一,有许多有用的功能,如:搜索RPC接口全局统一标识符(UUID)、搜索RPC接口名。

        然而,在一个文章中反编译并介绍所有RPC信息与我们的目标无关。幸运的是,通过阅读源代码,我们发现作者已经在工具中包含了我们需要的功能,但默认没有开启且只能通过一个特殊的命令行参数在调试模式下触发。由于这个限制,我们在RpcView GUI开启并修改原来的DecompileAllInterfaces函数。如果你对使用这个功能感兴趣,可以在我们的Github中找到我们订制的RpcView工具。我们现在可以在下一节介绍Decompile All Interfaces (反编译所有接口)功能的好处了。


图一:使用RpcView反编译所有接口功能

        分析一个RPC服务器的行为时,我们通常调用RPC接口导出的API。我们感兴趣的那些与RPC服务器的交互,可以通过利用RPC客户端向服务器发送RPC请求来实现,然后使用SysInternals里的Process Monitor工具来观察行为。我认为,使用脚本比使用C/C++写一个需要编译的RPC客户端更方便,后者很消耗时间。

        我们选择使用PythonForWindows。它以python方式对一些Windows功能提供了抽象,这个功能依赖于python的ctypes。它里面也包含一个RPC库,提供了一些很方便的函数节约了写RPC客户端的时间。例如,一个传统的RPC客户端需要定义接口定义语言,并且需要人工实现绑定操作,这些通常涉及C++代码。看下面的代码列表一和代码列表二,里面列出了使用脚本和以最小的错误处理代码编程实现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()

注意:上传附件及图片大小不得大于30M。

⚠️ 版权声明:
本博客所有内容(含教程、源码、工具)仅供个人技术学习与研究交流使用,严禁商用、倒卖、二次分发及非法用途
未经作者书面授权,任何组织或个人不得转载、复制或用于其他平台,违者将追究相关责任。

0 0 0 举报
复制成功