RDG(Remote Desktop Gateway)之前叫做Terminal Services Gateway(终端服务网关)是为远程桌面RDP提供录用的Windows服务器组件。用户并不是直接连接到RDP服务器,而是连接到网关与网关进行认证。成功认证后,网关会转发RDP流量到用户指定的地址——作为代理。只有网关需要连接到互联网,使得所有的RDP服务器都安全地位于防火墙之后。由于RDP是一个很大的供给面,因此使用RDP的设置可以明显减少该组织的攻击面。
1月的微软安全更新中,修复了RDG中的2个安全漏洞,分别是CVE-2020-0609和CVE-2020-0610,这两个漏洞都是预认证远程代码执行漏洞。
漏洞分析
研究人员首先查看受影响的DLL和修复后的版本来分析漏洞:
RDG可执行文件补丁安装前后BinDiff分析
很明显只有一个函数被修改了。RDG支持3种不同的协议:HTTP, HTTPS 和 UDP。更新的函数负责处理UDP。由于该函数的代码量很大,而且有许多的变化。因此,研究人员在文中用函数的伪代码表示,并且去除了一些无关代码。
URP处理函数伪代码
RDG UDP协议允许大量的消息分割成不同的分割的UDP包。由于UDP是无连接的,因此包到达时是无需的。该函数的作用的重新聚合函数,确保每个包处于正确的位置。每个包中都含有以下域的header:
· fragment_id: 表示序列中包的位置
· num_fragments: 表示序列中包的数量
· fragment_length: 表示包中数据的长度
消息处理函数用packet header来确保重新聚合的消息的顺序是正确的,和没有消息丢失。函数的实现过程中还会引入一些可以利用的漏洞。
CVE-2020-0609
包handler的边界检查
memcpy_s 会复制每个fragment到重新组合buffer中的offset,buffer是在堆中分配的。每个fragment的offset是由fragment id乘以1000计算出来的。边界检查并不会考虑offset。假设buffer_size是1000,研究人员发送了含有2个fragment的消息。
· 第一个fragment (fragment_id=0) 的长度是1。 this->bytes_written 是0,所以边界检查通过了。
· 会有1个字节写入offset为0的buffer,bytes_written会增加1。第二个fragment (fragment_id=1) 的长度是998, this->bytes_written 是1,1+998仍然小于1000,所以检测检查仍然是通过的。
· 998字节会写入offset 为1000(fragment_id*1000)的buffer中,这会让998字节传递到buffer的末尾。
需要说明的是包并不是有序发送的。所以,如果发送的第一个包fragment_id=65535,那么offset就等于65535*1000,65534000字节超过了buffer的尾部。通过修改fragment_id,就可以在缓存的尾部的1到65534000之间写入999字节。该漏洞要比典型的线性堆溢出漏洞更加灵活。不仅可以控制写入数据的大小,还可以控制写入的offset。有了精准控制后,就可以实现准确地写,避免不必要的数据破坏。
CVE-2020-0610
收到的fragment的包处理的追踪
Object类有一个32位无符号整数数组(每个fragment一个对应的无符号数)。接收到fragment后,对应的数组记录就会被设置为0或1。一旦元素被设为1,就表明消息重新组合完成了,并且消息可以被处理。数组的空间最多有64条记录,但fragment ID的范围为0到65535。只验证了fragment_id 小于 num_fragments (也可以被设置为65535)。因此,将fragment_id设置为65到65535可以在数组边界外写入1 (TRUE)。虽然看起来设置为1并不会引发RCE,但实际上一个小的修改都会堆程度行为带来巨大的影响。
缓解措施
如果无法安装补丁,仍然有一些预防漏洞被利用的方法。RDG支持HTTP、HTTPS和UDP协议,但该漏洞只存在于处理UDP的代码中。禁用UDP传输或将禁用UDP端口(3391)都可以预防漏洞利用。
RDG设置
还没有评论,来说两句吧...