(360 A-TEAM 长期招收高级安全研究人员,APT 攻防人员,请联系 wufangdong@360.net)
这是十几年前就出来的技术。但是,最近依然有一些关于 Relay 的文章出来,其中或多或少都有一些错误。
本篇文章,360 A-TEAM 将介绍一些与 NTLM-Relay 有关的,其他文章很少提及到的知识。当然,与之前 A-TEAM 的所有文章一样,这篇文章不会覆盖到所有的细节知识。想深入了解的同学,可以仔细阅读文中我推荐的技术文档。
需要知道的背景知识简述
挑战认证的基本概念
SSPI - Security Service Provider Interface 或 Security Support Provider Interface。这是 Windows 定义的一套接口,此接口定义了与安全有关的功能函数,包含但不限于:
身份验证机制
为其他协议提供的 Session security 机制。Session Security 指的是会话安全,即为通讯提供数据完整性校验以及数据的加、解密功能。
...
SSP - Security Service Provider。SSPI 的实现者,微软自己实现了如下的 SSP,用于提供安全功能:
NTLM SSP
Kerberos
Cred SSP
Digest SSP
Negotiate SSP
...
我们当然也可以实现自己的 SSP,然后注册到操作系统中。
因为 SSPI 中定义了与 session security 有关的 API。所以,基本上层应用利用任何 SSP 与远程的服务进行了身份验证后,此 SSP 都会为本次连接生成一个随机 key。这个 key 往往被称为 session key。上层应用在经过身份验证后,可以选择性地使用这个 key 来对之后发往服务端或接收自服务端的数据进行签名或加密。
不同的 SSP,实现的身份验证机制是不一样的。比如 NTLM SSP 实现的就是一种 challenge based 身份验证机制。而 Kerberos 实现的就是基于 ticket 的身份验证机制。我们可以编写自己的 SSP,然后注册到操作系统中,让操作系统支持更多的自定义的身份验证方法。
因为主题是 NTLM-Relay,所以本篇文章当然只讲 NTLM SSP。
NTLM SSP 实现了 NTLM 身份验证协议(以下就直接简称 NTLM)。
想深入了解的看:http://davenport.sourceforge.net/ntlm.html
NTLM 验证流程简述(非域环境或非域账号验证)
这里假设客户端以账号 admin 密码 123,连接服务端,身份验证方式为 NTLM SSP。
共 4 步:
客户端利用 NTLM SSP 生成 NTLM_NEGOTIATE 消息 (被称为 TYPE 1 消息),并将 TYPE 1 消息发送给服务端。
服务端接收到客户端发送过来的 TYPE 1 消息,传入 NTLM SSP,得到 NTLM_CHALLENGE 消息(被称为 TYPE 2 消息),并将此消息发回客户端。此消息中包含了一个由服务端生成的随机值,此随机值被称为 challenge。
客户端收到服务端返回的 TYPE 2 消息,并取出其中的随机值 challenge。客户端将密码 (123) 转换为 LM HASH 与 NT HASH,同时利用计算出来的 LM HASH 与/或 NT HASH 对 challenge 进行一些计算。算出来的那段数据,根据具体的情况,有可能是(为了简洁,这里的描述并不十分准确):
Net LM-Hash(在有的文章里也被称为 LM Response)
Net NTLM-Hash(在有的文章里也被称为 NTLM Response)
Net NTLM2-Hash(在有的文章里也被称为 NTLM2 Response/NTLM2 Session Response)
Net NTLMv2-Hash(在有的文章里也被称为 NTLMv2 Response)
Net LMv2-Hash(在有的文章里也被称为 LMv2 Response)
总而言之,计算出来的这段 hash 数据,将会封装到 NTLM_AUTH 消息中(被称为 TYPE 3 消息),发往服务端
服务端收到 TYPE 3 消息后,将会重复第 3 步客户端的操作,也计算出来一个 hash。然后将自己计算出来的 hash 与客户端发送过来的 TYPE 3 消息中的 hash 进行对比,如果一样,则客户端验证成功。不一样,则客户端验证失败 。
LmCompatibilityLevel
前面说到,客户端发送的 TYPE 3 消息中的那段 hash(也许严格意义上来说不能被称为 hash?),有可能是多种类型中的一种。
那到底什么时候用什么类型的 hash 呢?是由 LmCompatibilityLevel 来决定的。
https://technet.microsoft.com/en-us/library/cc960646.aspx
在组策略中,它叫作 “网络安全: LAN 管理器身份验证级别”。
这里就引出了另一个问题:客户端与服务端 LmCompatibilityLevel 的兼容性的问题。
你有没有碰到过这样的情况:当服务器上有一个账号 admin 密码 123 的账户,但是你 net use \\server "123" /user:admin 却提示账号密码错误?
如果有,那么你可能就遇到了两边 LmCompatibilityLevel 不兼容的情况。
即,客户端发送的 hash 的类型与服务端所期待的类型不一样,服务端计算出来了与客户端不一样的 hash,导致用户名密码错误。
在 LmCompatibilityLevel 不兼容的情况下,你正常去连接的结果是验证失败,自然用 NTLM-Relay 的结果肯定也是验证失败。
LmCompatibilityLevel 的默认值,不同的操作系统,甚至不同的补丁版本,是不一样的。在多数情况下应该是兼容的。
NTLM 是一个嵌入式协议
什么意思?前面说过了 NTLM SSP 的 TYPE 1/2/3 三条消息。这三条消息本质上就是一组字节。在前面的描述中,说到“客户端在生成 TYPE 1 消息后,会将此消息发送到服务端”。那么客户端通过什么样的方式将此消息发送给服务端呢? NTLM 本身并没有定义应该用什么方式来发送,它只负责生成 TYPE 1/2/3 这 3 条消息。
意思就是:NTLM 并没有定义它所依赖的传输层协议。NTLM 消息的传输完全依赖于使用 NTLM 的上层协议来决定。所以说 NTLM 是一个嵌入式协议。
如果你自己写一个利用 NTLM SSP 的程序,那么在拿到 NTLM 消息后,你可以以任何你喜欢的方式将这些消息发送至服务端。比如通过 HTTP,TCP,或者任何其他类型的 7 层协议,或者你自己定义的协议。
SMB-Relay Vs NTLM-Relay?
SMB-Relay 与 NTLM-Relay,这两种说法大家都见过,那么哪种才是正确的?
在理解了前面所说的 “NTLM 是嵌入式协议”的说法后,大家应该能够明白:
SMB-Relay 指的是 NTLM 上层协议是 SMB 的情况。如果上层协议是 HTTP,也许你可以管它叫做 HTTP-Relay。无论上层协议是什么,都可以统称为 NTLM-Relay。
NTLM-Relay 的具体流程?
前面说过,本文主要只介绍那些其他地方没有提到过的知识。已经有很多文章里写过 NTLM-Relay 的流程,所以这里略过。
跨协议的 NTLM-Relay
前面说过,NTLM 的上层协议基本可以是任何协议(如果上层是基于UDP 的协议的话,可能会不一样),所以这引出了跨协议的 NTLM-Relay 技巧。无论 NTLM 的上层协议是什么,其携带的 NTLM 的三条消息都是
由 NTLM SSP 生成的,所以上层协议在 relay 的过程中,是可以被替换掉的。
比如从 http relay 至 smb,从 smb relay 至 ldap/mssql 等等。我们只需要将一个协议中的 NTLM 消息取出来,然后原样不动的地放入另一个协议,就完成了上层协议转换的过程。
NTLM-Relay 与 Pass the hash?
某些部分有点相似,但完全不同的两个东西。
NTLM Relay 的一般防御方案
一般人们在讨论 SMB-Relay 的防御方案的时候,都会说开启 SMB 签名。那么开启 SMB 签名为什么可以防止 relay?这涉及到本文最开始提到的 session security 与 session key 。
SSP 往往会为上层协议提供 session security 功能,NTLM SSP 也不例外。session security 功能往往都是基于 session key 来实现的。这个 session key 往往是由 SSP 自己生成的。(Kerberos 场景下,session key 是由 KDC 在生成相应票据的时候一起生成的,并发回给客户端或服务端的)
在开启了 SMB Signing 的情况下,在 SMB 协议利用 NTLM SSP 进行了身份验证后,后续的所有数据包,都会利用 NTLM SSP 生成的这个 session key 进行签名。SMB 服务端收到后续的数据包后,也会检查数据包的签名,如果签名不对,则拒收。
NTLM SSP 在生成 session key 的时候,会需要用到账号密码的原始 LM HASH 或 NT HASH。而 relay 型的攻击,都是站在一个中间人的位置,我们是不可能知道原始的 LM HASH 或 NT HASH 的(如果知道了也就不需要 Relay 这种攻击手法了)。所以,我们是无法计算出来这个 session key 的,自然也就无法对数据包进行签名。(有一个例外,见后面的 NETLOGON 协议的 CVE 2015-0005)
所以在你用 SMB-Relay 打一台服务器的时候,如果出现了账号验证成功,但是后续无法进行任何其他操作的时候,或者提示你 Access denied 的时候,这就是目标服务器开启了 SMB 签名校验。
NTLM SSP 的缺陷
通过开启 SMB Signing 功能,才能防止 SMB-Relay。这实际上是 NTLM SSP 的一个缺陷。即,NTLM SSP 不能够进行 mutual authentication。仔细观察前面所讲到的 NTLM 验证流程你就会发现,NTLM SSP 可以让服务端来验证客户端的身份,但是却无法让客户端来验证服务端的身份。即,使用 NTLM SSP 的客户端,本质上是不知道自己连上的服务器到底是哪一台的。Kerberos 是支持双向认证的。(支持双向验证的 SSP ,一般都是在验证阶段就引入了 session key 或其他类似的 key,来确保进行验证的双方都知道所谓的 "previously-shared secret"。在 NTLM SSP 中,这个 previously-shared secret 指的就是 LM HASH 或 NT HASH)
所以,要想解决 NTLM-Relay 的问题,只能是使用 NTLM SSP 的上层协议,强行使用类似 SMB-Signing(如 LDAP Signing) 的手法,来间接验证服务端的身份。
NETLOGON 与 Pass through authentication
这一节的内容并不是本文的重点,所以简述。
Pass through authentication
域环境下默认的验证协议是 Kerberos。(本质上是 Negotiate,它会优先选择 Kerberos)但是当 Kerberos 因为某些原因不可用的时候,会降级到 NTLM。
大家想一下这个场景:
用域账号 USER 去登陆名为 MACHINE的机器,但是 Kerberos 又因为一些原因不能用,此时会降级到 NTLM。那么此时 NTLM 的验证流程会有一些变化。
回想一下 NTLM 验证流程的第 4 步:服务端需要根据被验证账号的密码的 LM HASH/NT HASH 来计算出来一段 hash,来与 TYPE 3 中的那段 hash 进行对比,来决定验证是否成功。
那么 USER 账号的 LM HASH/NT HASH 是存储在域控上的,MACHINE 当然是无法完成第 4 步操作的,因为它没有 USER 账号的 LM HASH/NT HASH。
此时,它会以 NETLOGON 协议联系域控,NETLOGON 所建立的安全通道经过了双向验证,并且数据加密传输,确保了 MACHINE 机器连接上的是真的域控。
联系上域控后,服务器会将 TYPE 1/2/3 消息全部都发送到域控上,让域控来进行身份验证。当身份验证通过后,域控会将 session key 返回给服务器。 session key 是基于账号的 LM HASH/NT HASH 计算出来的,服务器上没有这些信息,自然是算不出来 session key 的,所以自然是由域控来计算 session key 并返回给服务端。
服务端从域控那里得知验证结果与 session key 后,就可以继续自己后面的逻辑了。
CVE-2015-0005
先前只是在研究别的东西的时候,粗略地看过 NETLOGON 协议。后来是在 impacket 库的 ntlmrelayx.py 里面看到了此 CVE(由 impakcet 库的作者发现的)。
CVE 讲的主要就是 NETLOGON 协议的 pass through authentication 功能会泄露 session key,导致 SMB Signing 功能也无法防止 SMB-Relay。
360 A-TEAM 是隶属于 360 企业安全集团旗下的纯技术研究团队。团队主要致力于 Web 渗透,APT 攻防、对抗,前瞻性攻防工具预研。从底层原理、协议层面进行严肃、有深度的技术研究,深入还原攻与防的技术本质。
欢迎有意者加入!