在3月13号的微软补丁日中,由Preempt团队发现的Windows凭据安全支持提供协议(CredSSP)高危漏洞CVE-2018-0886被修复,该漏洞为逻辑远程代码执行(RCE)漏洞,几乎所有版本Windows操作系统都受其影响,它类似于经典的中继攻击,但其不同之处在于:它与RSA加密和质数相关,比较有意思。
漏洞介绍
CredSSP应用于微软远程桌面RDP和远程管理WinRM(包括Powershell会话)中,用于处理其他应用程序身份验证请求的安全提供程序,该漏洞主要原因在于CredSSP中存在一个设计缺陷,具有完整中间人控制权的攻击者可以利用该漏洞,冒充合法用户在目标服务器上执行任意代码或窃取数据。
Preempt已在域环境的RDP条件下成功复现了该漏洞攻击,如果用户是目标系统中的本地管理员,攻击将会以系统权限执行任意代码,能进一步对目标系统造成安全威胁。攻击在受限管理员模式和正常RDP模式下都能有效实现。
由于RDP会话非常普遍,所以对攻击者来说该漏洞非常极具价值。另外,因为它是一种设计缺陷,所以只要未作修复的Windows版本系统,都仍存在该漏洞(修复措施参考此处)。
本文中,我们来分享一下发现该漏洞的过程,同时在其中会解释这个漏洞的技术和数学细节。在此之前,希望读者能对活动目录(Active Directory)相关的Kerberos、NTLM、MS-RDP和安全支持提供程序接口(SSPI)能有所了解。
我们是如何发现该漏洞的
发现Bug#1
发现这个CredSSP漏洞可以算是歪打正着。此前,我们发现了另外一个漏洞(CVE-2017-8563 ),也就是在在不知道目标服务器私钥的情况下也能够在RDP受限管理模式下执行NTLM中继攻击,这是非常严重的,因为整个过程可实现在传输层安全性(TLS)下完成,并由服务器证书加密。
因为RDP的普通应用,导致这种NTLM中继攻击漏洞会被成功利用,主要步骤如下:
能力协商 (通常基于CredSSP环境下)
建立TLS通道
使用CredSSP的网络层认证
客户端证书验证,错误时会显示验证告警
用户接收结果告警
用户通过CredSSP向远程服务器发送密码
用户登录远程用户界面
在建立了加密的安全会话之后,RDP的下一步是进行网络层认证NLA。服务器会利用通常的认证方法(如Kerberos)验证客户端是否拥有该用户凭据,从而节省了分配登录所需的资源需求。
在第4步中,客户端检查证书。如果证书由受信的证书颁发机构(CA)签署,或是手动受信输入,则验证不会显示告警。 但如果执行的是Kerberos身份验证,则Microsoft会认为服务器已经过验证,验证证书与步骤3中Kerberos身份验证是结合在一起的。以下即为一个标准的MS-RDP告警:
可在证书验证之前看到网络层认证行为发生。因此,在第3步中可以使用任何伪造的证书来执行验证操作。我们将这个潜在的威胁称为Bug#1。
发现Bug#2
在分析Bug#1的过程中,我们发现它的存在也是有原因的,由此在测试CredSSP时我们又发现了Bug#2。
CredSSP是用于在MS-RDP中转发用户凭证的基础协议,其实该协议非常简单:其TSRequest消息会在客户端和服务端之间进行传输,这些消息中携带了用于认证协议在协商阶段的SPNEGO令牌。CredSSP客户端/服务端的相互协商是透明的,其协商过程会在步骤1中建立的安全TLS会话中进行。以下是CredSSP在网络层认证过程中的步骤:
在最终协商消息阶段(accept_complete)中,客户端计算机会完成NLTM / Kerberos的最终令牌传输,也会发送使用SSPI加密和签名的服务器公钥。其公钥结构体则是从RSA的关键参数中派生出来的,重点是,它包含了服务器证书核心的N和e参数。
这是一种称为Channel Binding(信道绑定)技术的常见变化形式,它目的在于将TLS会话与Windows身份验证绑定来阻止证书中继攻击。 因此,这种情况下,服务器身份(证书)与标准的Windows身份验证身份(账户密钥)会结合在一起。尽管如此,这种设计仍然存在致命的设计缺陷,在此可能需要几分钟时间来了解它。
Bug#2
该Bug#2的问题在于客户端信任服务端公钥的过程,它实际上是不先去验证身份,而是对服务端公钥结构进行加密并签名。该Bug下的攻击可看成是一种选择明文攻击(CPA)的特殊案例,这种情况下,它会对SSPI中的应用程序进行加密和签名(经典攻击只是加密)。
这就是CredSSP漏洞的实质,为了对它进行利用,攻击者可以设置一个恶意服务器,使用恶意公钥来冒充应用程序数据和有效的RSA密钥,然后它会将加密和签名过的应用程序数据转发给目标攻击服务端(假设当前测试场景中没有其它服务器端)。下图展示了整个漏洞利用步骤:
这是否可行呢? 毕竟,公钥是具备双重目的,它应该对RSA密钥和尚待确定的Windows协议下的签名应用程序数据有效,这个Windows协议当然也包括SSPI接口协议。
让我们先来关注一下其中是最棘手的问题:也就是我们需要来控制RSA公钥(可将其转换为应用程序数据)。
漏洞利用
破坏RSA加密
这里需要读者掌握一些RSA加密的基本数学原理知识。假设任意给定正整数N,计算在小于等于N的正整数之中,有多少个与N构成互质关系,计算这个值的方法就叫做欧拉函数,以φ(N)表示;a的φ(N)次方被N除的余数为1,ab≡1(modN)。
我们可以看到,如果要实现通常的RSA认证,由于参数N的可控制性较少,我们选择一个质数为p,因为一个数如果是质数,则小于它的所有正整数与它都是互质数,所以有φ(p)=p -1;而且,一个数N可以分解为两个质数p和q的乘积,则有:φ(N)=(p-1)(q-1);另外,根据欧拉定理,如果两个正整数a和N互质,那么一定可以找到整数b,使得ab≡1(mod N)成立。
同时,作为公钥部分来说,还存在一个小于N且与φ(N)互质的数e,能使c =m^e*mod N成立,这也是RSA加密的前提。
根据RSA加密规则,如果m是给定的甲要发送给乙的密文,经过c = m^e mod N之后,就把密文m加密成了c,所以其公钥也就是(N,e);乙收到加密过的密文c之后,要计算出私钥(N,d)来,才能解密经过加密的密文c,这个过程中,我们可以随机选择两个不相等的质数p和q,计算p和q的乘积N=p×q,根据欧拉函数公式,代入φ(N)=(p-1)(q-1)得到φ(N)值,然后在1和φ(N)之间随机一个与φ(n)互质的整数e,根据ed≡1(modφ(N))算出d来即可知晓私钥(N,d),完成解密。
所以,要“破坏”这种RSA加密机制,只需按照RSA本身的加密解密原理结合原生的OpenSSL库来做就行,但另外我们仍然需要删除服务器中的一些优化设置,因为实际这里并没有涉及到两个质数。完成这一步之后,我们就能实现有效加密,并能对N进行控制。但实际控制程度是多少呢?我们可以找到一个初始质数吗?答案是可以的。
寻找质数k
根据质数定理:
当π是小于x的质数计算函数时,如果我们随机在1和N之间选择一个数k时,那么这个数k是质数的概率是:
根据上述公式,当N是靠近600字节或在2的600*8次方附近的数时,我们随机选择的数成为质数的概率会介于1/3328到1/2651之间,对其中适当的范围作精确计算,可以得到一个相似结果。
根据公式:
可知,接近2字节的范围足够找到一个适合的质数,我们需要尝试约1650个数字才能找到合适的素数,在我电脑上,平均需要70秒才能完成一次有效寻找,所以找质数的过程解决了,那么现在就需要一个适合的协议了。
寻找协议
显然,这里需要将公钥的抽象语法标记ASN.1.结构编码成应用数据,其大致结构体如下:
根据上图结构可知,前8个字节数据都不可能受控制。
NTLM or Kerberos
需要考虑的问题是我们是否可以实施NTLM或Kerberos,由于SSPI具有基于NTLM和Kerberos身份验证的标准机制,在这两种情况下,如果在协商阶段同意签名,那么包含校验值和和序列号的头信息将被添加到应用数据中。另外,SPNEGO协商之后,会启用签名和加密,且公钥结构中的序列号将为0。
但是,在NTLM和Kerberos两种机制之间有一个重要的区别,以RPCR的GSSAPI接口应用为例,下图能很好的说明:
公钥结构实际上被编码为“无头协议”,整个结构将会以NTLM格式进行加密和签名,但RPC服务器只希望加密应用程序数据。所以,NTLM为协议增加了另一个限制,这个限制实际上阻断了我们对NTLM的中继攻击,因为我们找不到合适的“无头”协议,如果找到这样的协议可能会产生更厉害漏洞利用,将会允许攻击者选择不同服务器作为NTLM中继攻击目标。
另外一点要注意的是,在Kerberos中,只要帐户匹配,就不会严格限制票据服务名称,而RDP中的帐户是机器帐户,所以,我们可以说Kerberos中可存在轻微的Kerberos中继攻击,只要在给定的CPA(选择明文攻击)条件下,一个应用程序中使用的数据可以在另一个应用程序中使用。
最终,协议要满足如下要求:
支持SPNEGO协商机制
编码要求
应用程序数据为非ASN.1
前8字节前缀我们无法操作控制
包含一定自由度
如果应用于NTLM时则无标题头信息
能够用单个签名的数据包进行破坏
适用于各种机器
除了NTLM机制应用的额外要求外,满足以上条件的协议无非就只有微软的远程过程调用(MSRPC),我们也还暂时未找到其它适合的协议。
漏洞利用
MSRPC的应用数据编码为微软接口定义语言(MIDL),它定义了远程过程传输中的各种参数,是一种结构比较多元而混乱的语言。
由于MSRPC协议第一个参数是字符串(通常可能是指针),它指向了一个称为ReferentId的8字节字段(在64位环境下),目标服务器不同则该字段值也不同,而我们要求开始的8个字节不受控制,所以我们可以选择其它任何函数。
对于自由度字节,不会有太大问题,而且会RPC忽略掉过多字节,因此最简单的方法是将它们全部放在最后。最终,可以把任务调度接口Task Scheduler Interface下的Opnum 1函数作为漏洞利用函数:
Task Scheduler Interface用来管理Windows中的任务调度,它有点像ATSvc接口,但又比ATSvc接口功能更强,它能对创建任务和过程属性执行更多控制。以下为漏洞利用的具体命令代码:
该命令以系统权限用户身份创建了一个任务,漏洞执行程序为攻击者控制共享的文件,该漏洞程序能很好运行,并且,如果该系统用户是管理员身份,则不需要执行系统提权操作。
存在的一些现实障碍
当利用中间人攻击时,可以利用ARP欺骗等方式,很多情况下并不太难实现,但这里存在的问题是Windows防火墙,当目标系统防火墙开启时,那么在通常的操作系统下,默认情况下,对于任何接口,都会阻断RPC入站连接。
尽管如此,基于以下几方面因素来说,该漏洞还是存在非常广泛的现实威胁:
域控制器在默认情况下仍然容易受到此类攻击;
很多时候,某些用户的Windows防火墙处于关闭状态,因此RPC能被有效启用;
如果被成功利用,这种攻击能绕过各种环境下的防御机制,或者还能结合MSRPC之外的其它协议被利用。
该漏洞攻击场景中,漏洞程序被执行之后,目标系统远程桌面会话会弹出一个如下的错误告警:
但在不产生任何系统安全告警的情况下,攻击者构造的恶意攻击载荷(Payload)会被悄无声息地隐蔽植入目标系统内,实现对目标系统的进一步提权入侵,
总结
在这篇文章中,我们详细介绍了以任务计划程序接口(Task Scheduler Interface)为目标的MS-RDP攻击。在启用了RPC的服务器上,假设攻击者具备中间人攻击(MITM)能力,则这种攻击的成功率为100%。在本月的BlackHat Asia过后,我们会发布该攻击的具体漏洞利用工具,敬请期待。(点此查看该漏洞详细技术分析报告, 点此观看漏洞分析视频)
*参考来源:preempt,FreeBuf小编clouds编译,转载请注明来自FreeBuf.COM
领取专属 10元无门槛券
私享最新 技术干货