研究人员: Eyal Itkin
概述
远程桌面协议(RDP)由全球数以千计的IT专业人员和安全研究人员使用,通常被认为是连接到远程计算机的安全可靠的应用程序。无论是用于帮助远程工作人员还是在安全的VM环境中工作,RDP客户端都是非常宝贵的工具。
但是,Check Point Research最近在常用的远程桌面协议(RDP)中发现了多个关键漏洞,这些漏洞将允许恶意行为者扭转通常的通信方向并感染IT专业人员或安全研究人员的计算机。这种感染可能会导致整个IT网络的入侵。
总共发现了16个主要漏洞和25个安全漏洞。完整列表可在附录A和B中找到。
简介
远程桌面协议(RDP),在Microsoft内置RDP客户端之后也称为“mstsc”,技术用户和IT人员通常使用它来连接/工作在远程计算机上。RDP是Microsoft开发的专有协议,通常在用户想要连接到远程Windows机器时使用。还有一些流行的RDP协议开源客户端主要由Linux和Mac用户使用。
RDP提供许多复杂功能,例如:压缩视频流,剪贴板共享和多个加密层。因此,我们决定寻找协议及其流行实现中的漏洞。
在正常情况下,您使用RDP客户端,并连接到远程计算机上安装的远程RDP服务器。成功连接后,您现在可以根据用户的权限访问和控制远程计算机。但如果情景可以反过来?我们想调查RDP服务器是否可以攻击并控制连接的RDP客户端的计算机。
图1: RDP协议的攻击情形
有几种常见的情况,攻击者可以通过部署此类攻击获得提升的网络权限,从而推进他在组织内部的横向移动:
- 攻击连接到公司网络内受感染工作站的IT成员,从而获得更高的权限级别和更大的网络系统访问权限。
- 攻击连接到包含经过测试的恶意软件的远程沙盒虚拟机的恶意软件研究人员。这允许恶意软件逃离沙箱并渗透到企业网络中。
现在我们确定了攻击向量,现在是时候介绍我们的目标,最常用的RDP客户端:
- mstsc.exe - 微软内置的RDP客户端。
- FreeRDP - Github上最受欢迎和最成熟的开源RDP客户端。
- rdesktop - 较旧的开源RDP客户端,默认出现在Kali-linux发行版中。
有趣的事实:由于“rdesktop的”是内置在卡利的Linux客户端,由红队为渗透测试使用的Linux发行版,我们想到了一个3 次(虽然可能不是实际的)攻击的场景:蓝队可以安装组织蜜罐攻击试图通过RDP协议连接到它们的红队。
开源RDP客户端
通常情况下,我们决定开始寻找开源客户端中的漏洞。在我们对协议有一个充分的了解之后,似乎只有开始对微软的客户进行逆向工程才有意义。此外,如果我们在两个开源客户端中发现常见漏洞,我们可以检查它们是否也适用于Microsoft的客户端。在重新检查中,它看起来像“rdesktop”小于“FreeRDP”(代码行数较少),因此我们选择它作为我们的第一个目标。
注意:我们决定执行老式的手动代码审核,而不是使用任何模糊测试技术。这个决定的主要原因是为复杂的RDP协议编写专用的模糊器的开销,以及将AFL用于具有多个压缩和加密层的协议的事实看起来不是一个好主意。
rdesktop
测试版本: v1.8.3
在短暂的一段时间后,看起来决定手动搜索漏掉的漏洞。我们很快发现了代码中的几个易受攻击的模式,使得“感觉”代码更容易,并查明可能的漏洞的位置。
我们发现11个漏洞具有重大安全隐患,并且库中总共有19个漏洞。有关“rdesktop”的完整CVE列表,请参阅附录A.
注意:另一个侦测显示xrdp开源RDP服务器基于“rdesktop”代码。根据我们的调查结果,似乎在“xrdp”中也可以找到类似的漏洞。
我们将重点关注我们发现的两种常见的易受攻击的代码模式,而不是对所有CVE进行技术分析。
远程执行代码 - CVE 2018-20179 - 2018-20181
在整个客户端代码中,假设服务器向客户端发送了足够的字节来进行处理。可以在图2中的以下代码片段中找到此假设的一个示例:
图2: 在没有首先检查其大小的情况下从流“s”解析2个字段
正如我们所看到的,字段“length”和“flags”是从流“s”中解析出来的,而不检查“s”确实包含了这个解析操作所需的8个字节。虽然这通常只会导致Out-Of-Bounds读取,但我们可以将此漏洞与多个内部通道中的其他漏洞相结合,并实现更严重的影响。
有三个逻辑通道共享一个共同的漏洞:
- lspci的
- rdpsnddbg - 是的,此调试通道始终处于活动状态
- 无缝
漏洞本身可以在图3中看到:
图3:计算剩余“pkglen”时的整数下溢
通过从流中读取太多数据,即将斩波数据包发送到客户端,“s-> p <= s-> end”的不变量会中断。这会在计算“pkglen”时导致整数下溢,并在为缓冲区分配“xmalloc(pkglen + 1)”字节时导致额外的整数溢出,如上面对“xmalloc”调用的注释中所示。
与图4中所示的“STRNCPY”的专有实现一起,当将数据复制到微小的分配堆缓冲区时,我们可以触发大量的基于堆的缓冲区溢出。
图4: “strncpy”函数的专有实现
通过将这两个漏洞链接在三个不同的逻辑通道中,我们现在有三个 远程执行代码漏洞。
CVE 2018-8795 - 远程执行代码
另一个经典漏洞是处理收到的位图(屏幕内容)更新时的Integer-Overflow,如图5所示:
图5: 处理位图更新时的整数溢出
虽然“宽度”和“高度”每个只有16位,但通过将它们与“Bpp”(每像素位数)相乘,我们可以触发整数溢出。稍后,位图解压缩将处理我们的输入并中断任何解压缩错误,从而为我们提供可控制的基于堆的缓冲区溢出。
注意:这个棘手的计算可以在“rdesktop”代码的几个地方找到,因此我们将其标记为在“FreeRDP”中检查的潜在漏洞。
FreeRDP
测试版本: 2.0.0-rc3
在“rdesktop”中发现多个漏洞之后,我们对“FreeRDP”提出了一些恐惧; 或许只有“rdesktop”在实施RDP时存在漏洞?我们仍然无法确定协议的每个实施都会容易受到攻击。
事实上,乍一看,代码似乎要好得多:在从接收到的数据包中解析数据之前进行最小规模的检查,并且代码“感觉”更加成熟。这将是一个挑战。然而,经过深入研究后,我们开始发现代码中存在问题,最终我们发现了该客户端的关键漏洞。
我们发现5个漏洞具有重大安全隐患,并且库中总共有6个漏洞。有关“FreeRDP”的完整CVE列表,请参阅附录B.
注意:另一个侦察显示RDP客户端NeutrinoRDP是旧版本(1.0.1)的“FreeRDP”的分支,因此可能遭受相同的漏洞。
在我们的研究结束时,我们为CVE 2018-8786开发了一个PoC漏洞,如本视频所示:
CVE 2018-8787 - 相同的整数溢出
正如我们之前在“rdesktop”中看到的那样,计算接收到的位图更新的尺寸容易受到整数溢出的影响。事实上,“FreeRDP”也有同样的漏洞:
图6: 处理位图更新时的相同整数溢出
远程执行代码 - CVE 2018-8786
图7: 处理位图更新时的Integer-Truncation
从图7中可以看出,在尝试计算位图更新数组所需的容量时会出现Integer-Truncation。稍后,矩形结构将从我们的数据包解析到太小的分配缓冲区的内存中。
当解析矩形并将其存储到阵列时,此特定漏洞后面是堆分配的受控量(“bitmapUpdate-> number”)(具有受控大小),从而为攻击者提供了一个很好的堆整形原语。这个漏洞的缺点是大多数矩形字段只有16位宽,并且被上传到32位以存储在数组中。尽管如此,我们还是设法在我们的PoC中利用了这个CVE。即使这种部分受控的基于堆的缓冲区溢出也足以进行远程代码执行。
Mstsc.exe - 微软的RDP客户端
测试版本: Build 18252.rs_prerelease.180928-1410
在我们完成对开源实现的检查之后,我们觉得我们对协议有了很好的理解,现在可以开始对Microsoft的RDP客户端进行逆向工程。但首先,我们需要找到哪些二进制文件包含我们想要检查的逻辑。我们选择关注的* .dll文件和* .exe文件:
- rdpbase.dll - RDP客户端的协议层。
- rdpserverbase.dll - RDP服务器的协议层。
- rdpcore.dll / rdpcorets.dll - RDP引擎的核心逻辑。
- rdpclip.exe - 我们发现的一个.exe,我们稍后会介绍。
- mstscax.dll - mstsc.exe使用的RDP逻辑大致相同。
测试先前的漏洞
我们首先测试我们的PoC是否存在开源客户端中的漏洞。不幸的是,所有这些都导致客户端干净利落地关闭,没有任何崩溃。没有更多的借口,我们开了IDA并开始跟踪消息的流动。很快,我们意识到微软的实现比我们之前测试的实现要好得多。实际上,似乎微软的代码要好几个数量级,因为它包含:
- 几个优化层,用于接收视频的高效网络流传输。
- 强大的输入检查。
- 强大的解压缩检查,以确保不会通过目标缓冲区写入任何字节。
- 其他支持的剪贴板功能
- ...
不用说,在处理位图更新时会检查Integer-Overflows。
等一下,他们共用一张剪贴板?
当我们检查“rdesktop”和“FreeRDP”时,我们发现剪贴板共享通道中存在多个漏洞(每个逻辑数据层称为一个通道)。但是,当时我们并不太关注它,因为它们只共享两种格式:原始文本和Unicode文本。这次微软似乎支持多种共享数据格式,因为我们看到的交换表比以前大得多。
在阅读了有关MSDN中不同格式的更多信息后,一种格式立即引起了我们的注意:“CF_HDROP”。这种格式似乎负责“拖放”(因此名称为H DROP),在我们的例子中,“复制和粘贴”功能。可以简单地从第一台计算机复制一组文件,然后将它们粘贴到第二台计算机中。例如,恶意软件研究人员可能希望将其脚本的输出日志从远程VM复制到其桌面。
这大概是在这一点上,当我试图找出的数据流,奥马尔(@GullOmer)问我是哪里PathCanonicalizeA 叫。如果客户端无法正确规范化并清理它接收的文件路径,则可能容易受到路径遍历攻击,允许服务器在客户端计算机上的任意路径中删除任意文件,这是一种非常强大的攻击原语。在未能找到规范化函数的导入之后,我们深入挖掘,试图找出该数据流的整体架构。
图8总结了我们的发现:
图8: Microsoft RDP中共享剪贴板的体系结构
这是rdpclip.exe发挥作用的地方。事实证明,服务器通过代理访问剪贴板,那就是rdpclip.exe。实际上,rdpclip.exe只是一个正常的过程(我们可以自己杀死/生成它),它使用专用的虚拟通道API与RDP服务对话。
在这个阶段,我们安装了ClipSpy,并开始动态调试在rdpclip.exe中完成的剪贴板数据处理。
这些是关于普通“复制和粘贴”操作中数据流的结论,其中文件从服务器复制到客户端:
- 在服务器上,“复制”操作创建格式为“CF_HDROP”的剪贴板数据。
- 当在客户端的计算机中执行“粘贴”时,会触发一系列事件。
- 要求服务器上的rdpclip.exe进程提供剪贴板的内容,并将其转换为FileGroupDescriptor(Fgd)剪贴板格式。
- 使用HdropToFgdConverter :: AddItemToFgd()函数将文件的元数据一次添加到描述符中。
- 完成后,将Fgd blob发送到服务器上的RDP服务。
- 服务器只需将其包装并发送给客户端。
- 客户端将其解包并将其存储在自己的剪贴板中。
- “粘贴”事件将发送到焦点窗口的进程(例如,explorer.exe)。
- 此过程处理事件并从剪贴板读取数据。
- 通过RDP连接本身接收文件的内容。
路径遍历共享RDP剪贴板
如果我们回顾对收到的剪贴板数据执行的步骤,我们会注意到客户端没有验证从RDP服务器收到的收到的Fgd blob。事实上,如果我们修改服务器以包含以下形式的路径遍历路径:.. \ canary1.txt,ClipSpy会向我们展示(参见图9)它在客户端的剪贴板上“按原样”存储:
图9: 带有路径遍历的Fgd存储在客户端的剪贴板上
在图10中,我们可以看到explorer.exe如何处理.. \ filename.txt的路径遍历:
图10: 当explorer.exe处理它时带有路径遍历的Fgd
只是为了确保在“内部”文件夹中的“粘贴”之后,文件存储到“Base”而不是:
图11: 成功路径遍历攻击后的文件夹
实际上就是这样。
如果客户端通过RDP连接使用“复制和粘贴”功能,则恶意RDP服务器可以透明地将任意文件丢弃到客户端计算机上的任意文件位置,仅受客户端权限的限制。例如,我们可以将恶意脚本丢弃到客户端的“Startup”文件夹中,重启后,它们将在他的计算机上执行,从而完全控制我们。
注意:在我们的漏洞利用中,我们简单地杀死了rdpclip.exe,并通过向每个“复制和粘贴”操作添加额外的恶意文件来生成我们自己的进程以执行路径遍历攻击。攻击是使用“用户”权限执行的,并不要求攻击者拥有“系统”或任何其他提升权限。
这是我们PoC漏洞的视频:
更进一步
每次在RDP连接的任一侧更新剪贴板时,都会向另一端发送CLIPRDR_FORMAT_LIST消息,以通知它现在可用的新剪贴板格式。我们可以将其视为双方剪贴板之间的完全同步(除了RDP连接本身区别对待的一小部分格式之外)。这意味着只要客户端将某些内容复制到他的“本地”剪贴板,就会通知我们的恶意服务器,现在它可以查询这些值并读取它们。此外,服务器可以向客户端通知剪贴板“更新”,而无需 在RDP窗口内进行“复制”操作,从而完全控制客户端的剪贴板而不会被注意到。
场景#1:
恶意RDP服务器可以窃听客户端的剪贴板 - 这是一个功能,而不是错误。例如,客户端本地复制管理员密码,现在服务器也有。
场景#2:
恶意RDP服务器可以修改客户端使用的任何剪贴板内容,即使客户端未在RDP窗口内发出“复制”操作。如果在打开RDP连接时单击“粘贴”,则您很容易受到此类攻击。例如,如果您在计算机上复制文件,服务器可以修改您的(可执行文件?)文件/捎带您的副本,以使用之前显示的PoC添加其他文件/路径遍历文件。
我们能够使用NCC的.NET反序列化 PoC 成功测试这种攻击情形:
- 服务器执行其PoC,并在剪贴板中放置将弹出计算器的.NET内容(使用“System.String”格式)。
- 当客户端在PowerShell程序中单击“粘贴”时,将发生反序列化并弹出计算结果。
注意:同步剪贴板的内容受延迟渲染的影响。这意味着只有在程序主动询问后才能通过RDP连接发送剪贴板的内容,通常是单击“粘贴”。在此之前,剪贴板仅保留可用格式列表,而不保留内容本身。
披露时间表
- 2018年10月16日 - 向Microsoft披露了漏洞。
- 2018年10月22日 - 向FreeRDP披露了漏洞。
- 2018年10月22日 - FreeRDP回复并开始研究补丁。
- 2018年10月28日 - 向rdesktop披露了漏洞。
- 2018年11月5日 - FreeRDP向我们发送补丁并要求我们验证它们。
- 2018年11月18日 - 我们验证了FreeRDP的补丁,并给了他们一个“绿灯”继续。
- 2018年11月20日 - FreeRDP将补丁作为2.0.0-rc4的一部分提交给他们的Github。
- 2018年12月17日 - 微软承认了我们的调查结果。有关更多信息,请参阅Microsoft的响应。
- 2018年12月19日 - rdesktop向我们发送补丁并要求我们验证它们。
- 2018年12月19日 - 我们验证了rdesktop的补丁,并给他们一个“绿灯”继续。
- 2019年1月16日 - 作为v1.8.4的一部分,rdesktop将补丁发送给他们的Github。
微软的回应
在负责任的披露过程中,我们将mstsc.exe中的路径遍历的详细信息发送给了Microsoft。
这是微软的官方回应:
“感谢您提交。我们确定您的发现是有效的,但不符合我们的服务标准。有关详细信息,请参阅Windows的Microsoft安全服务标准(https://aka.ms/windowscriteria)。“
因此,此路径遍历没有CVE-ID,并且没有补丁来解决它。
结论
在我们的研究中,我们在测试的RDP客户端中发现了许多关键漏洞。虽然不同客户端的代码质量各不相同,但我们发现的漏洞分布可以看出,我们认为远程桌面协议很复杂,容易出现漏洞。正如我们在我们的PoC中为Microsoft的客户端和一个开源客户端演示的那样,恶意RDP服务器可以利用RDP客户端中的漏洞来实现客户端计算机上的远程代码执行。
由于IT人员和技术人员经常使用RDP连接到远程计算机,我们强烈建议每个人都修补他们的RDP客户端。此外,由于我们在Microsoft的RDP客户端中显示的剪贴板结果的性质,我们建议用户在连接到远程计算机时禁用剪贴板共享通道(默认情况下已启用)。
保护建议
Check Point建议采取以下步骤以防止此类攻击:
- Check Point Research与FreeRDP,rdesktop和Microsoft密切合作,以缓解这些漏洞。
如果您使用的是rdesktop或FreeRDP,请更新到包含相关修补程序的最新版本。 - 使用Microsoft RDP客户端(MSTSC)时,我们强烈建议禁用RDP上的双向剪贴板共享。
- 将安全措施应用于RDP通信中涉及的客户端和服务器。
Check Point提供可用于保护的各种安全层,例如IPS,SandBlast Agent,威胁仿真和ANTEX。 - 用户应避免使用RDP连接到未实施足够安全措施的远程服务器。
- Check Point的IPS刀片提供针对这些威胁的保护:
- “FreeRDP远程执行代码(CVE-2018-8786)”
附录A - 在rdesktop中找到的CVE:
- CVE 2018-8791:rdesktop版本(包括v1.8.3)包含函数rdpdr_process()中的Out-Of-Bounds,导致信息泄漏。
- CVE 2018-8792:rdesktop版本直到并包括v1.8.3包含函数cssp_read_tsrequest()中的Out-Of-Bounds Read,导致拒绝服务(segfault)。
- CVE 2018-8793:rdesktop版本(包括v1.8.3)在函数cssp_read_tsrequest()中包含基于堆的缓冲区溢出,导致内存损坏,甚至可能导致远程代码执行。
- CVE 2018-8794:rdesktop版本(包括v1.8.3)包含一个整数溢出,导致函数process_bitmap_updates()中的Out-Of-Bounds写入并导致内存损坏甚至可能导致远程代码执行。
- CVE 2018-8795:rdesktop版本(包括v1.8.3)包含整数溢出,导致函数process_bitmap_updates()中的基于堆的缓冲区溢出,并导致内存损坏甚至可能导致远程代码执行。
- CVE 2018-8796:rdesktop版本直到并包括v1.8.3包含函数process_bitmap_updates()中的Out-Of-Bounds,导致拒绝服务(segfault)。
- CVE 2018-8797:rdesktop版本(包括v1.8.3)在函数process_plane()中包含基于堆的缓冲区溢出,导致内存损坏甚至可能导致远程代码执行。
- CVE 2018-8798:rdesktop版本(包括v1.8.3)包含函数rdpsnd_process_ping()中的Out-Of-Bounds,导致信息泄漏。
- CVE 2018-8799:rdesktop版本(包括v1.8.3)包含函数process_secondary_order()中的Out-Of-Bounds,导致拒绝服务(segfault)。
- CVE 2018-8800:rdesktop版本(包括v1.8.3)在函数ui_clip_handle_data()中包含基于堆的缓冲区溢出,导致内存损坏甚至可能导致远程代码执行。
- CVE 2018-20174:直到并包括v1.8.3的rdesktop版本包含函数ui_clip_handle_data()中的Out-Of-Bounds,导致信息泄漏。
- CVE 2018-20175:rdesktop版本(包括v1.8.3)包含几个Integer Signedness错误,这些错误导致文件mcs.c中的Out-Of-Bounds读取并导致拒绝服务(segfault)。
- CVE 2018-20176:rdesktop版本(包括v1.8.3)包含文件secure.c中的几个Out-Of-Bounds,导致拒绝服务(segfault)。
- CVE 2018-20177:rdesktop版本(包括v1.8.3)包含整数溢出,导致函数rdp_in_unistr()中的基于堆的缓冲区溢出,并导致内存损坏甚至可能导致远程代码执行。
- CVE 2018-20178:rdesktop版本(包括v1.8.3)包含函数process_demand_active()中的Out-Of-Bounds,导致拒绝服务(segfault)。
- CVE 2018-20179:rdesktop版本(包括v1.8.3)包含一个整数下溢,导致函数lspci_process()中的基于堆的缓冲区溢出,导致内存损坏,甚至可能导致远程代码执行。
- CVE 2018-20180:rdesktop版本(包括v1.8.3)包含一个整数下溢,导致函数rdpsnddbg_process()中的基于堆的缓冲区溢出,导致内存损坏甚至可能导致远程代码执行。
- CVE 2018-20181:rdesktop版本(包括v1.8.3)包含整数下溢,导致函数seamless_process()中的基于堆的缓冲区溢出,并导致内存损坏甚至可能导致远程代码执行。
- CVE 2018-20182:rdesktop版本(包括v1.8.3)在函数seamless_process_line()中包含全局变量的缓冲区溢出,导致内存损坏,甚至可能导致远程代码执行。
附录B - FreeRDP中的CVE:
- CVE 2018-8784:版本2.0.0-rc4之前的FreeRDP在函数zgfx_decompress_segment()中包含基于堆的缓冲区溢出,导致内存损坏甚至可能导致远程代码执行。
- CVE 2018-8785:版本2.0.0-rc4之前的FreeRDP在函数zgfx_decompress()中包含基于堆的缓冲区溢出,导致内存损坏甚至可能导致远程代码执行。
- CVE 2018-8786:版本2.0.0-rc4之前的FreeRDP包含一个整数截断,导致函数update_read_bitmap_update()中的基于堆的缓冲区溢出,并导致内存损坏甚至可能导致远程代码执行。
- CVE 2018-8787:版本2.0.0-rc4之前的FreeRDP包含整数溢出,导致函数gdi_Bitmap_Decompress()中的基于堆的缓冲区溢出,并导致内存损坏甚至可能导致远程代码执行。
- CVE 2018-8788:版本2.0.0-rc4之前的FreeRDP包含函数nsc_rle_decode()中最多4个字节的Out-Of-Bounds写入,这会导致内存损坏甚至可能导致远程代码执行。
- CVE 2018-8789:版本2.0.0-rc4之前的FreeRDP在NTLM身份验证模块中包含几个Out-Of-Bounds Read,导致拒绝服务(segfault)。
本文作者为Mr.Bai,转载请注明。