Skip to content

NAT Slipstreaming v1 原理浅析

Published: at 16:34

大家好,好久不见,这里是某昨。这是一篇从 2021 年春节一直咕到现在的文章,因此文中的「今天」等指代时间的词语均代表当时的时间,请各位在阅读时自行转换(笑)

ToC

开始

今天无意在 OSChina 的公众号看到一篇讲解 Chrome 将一些端口加入黑名单以防止 NAT Slipstreaming 攻击的新闻。原文是这样描述的:

这个新型 NAT Slipstreaming 漏洞使网站可以托管恶意脚本,这些恶意脚本发送经过特殊设计的响应,从而绕过网站访问者的 NAT 防火墙并能够访问用户内部网络上的任何 TCP/UDP 端口。

https://mp.weixin.qq.com/s/Z5tuhhlt4uZGDVKCuOGCOQ

这个漏洞的结果令我产生了强烈的好奇:这个洞到底是怎么打出来的?!这篇文章就是在明白了其原理之后诞生的。

值得注意的是,这篇文章中描述的是 NAT Slipstreamingv1 版本。上述新闻中描述的是 v2v1 能做到的是能连通内网的 5060 端口,而 v2 则可以支持任意的端口。v2v1 的主要区别在于选取的协议不同,但很多原理都是共通的。因此这里只介绍 v1 的原理。

NAT

在之前的一篇文章,我详细介绍了 NAT 的几种类型。但无论是哪种 NAT,都无法解决这样的问题:协议选择使用多条连接时,外部连接无法穿过 NAT

FTP 协议为例,当使用主动模式时,FTP 客户端主动选择了端口 nFTP 服务器建立连接,并打开端口 n+1 接收 FTP 服务器传来的数据。此时,端口 n 由于内网机器主动穿过 NAT,建立了 NAT 映射;但对于端口 n+1,由于传输层并没有任何迹象表明这个端口会被使用,因此 FTP 服务器对这个端口的访问就会被 block,由此导致 FTP 主动模式无法使用。

尽管 FTP 提供了被动模式,但被动模式会受到服务端端口数量的限制,从而限制了同时使用的用户数量。并且,如果配置了防火墙策略,服务端还需要放行一部分被动模式使用的端口。

FTP 只是许多这样协议中的一种。它工作在应用层,其预期行为由于 NAT 的存在而无法正常进行。由此,应用层网关应运而生。

应用层网关(ALG

应用层网关,顾名思义,就是工作在应用层的网关。我们来看一看 ALG 是如何解决上述问题的。

还是以 FTP 协议为例。我们知道,当 FTP 客户端建立主动连接时,其自身选择了一个端口 n。对于 ALG,其可以通过各种方式判断当前连接的协议为 FTP。当主动连接时,ALG 透明地增加一条与目标机器端口的映射。这样,FTP 协议就可以正常使用了。

简单总结一下,就是 ALG 通过识别某些特殊的协议报文,自动判断并建立需要建立的端口映射,从而使得应用层协议能够正常运行。

问题所在

乍一看这样的流程好像没什么问题,那究竟是什么导致了危险呢?

我们知道,数据在传输的过程中,IP 数据报由于 MTU 的限制,必须进行分片;TCP 数据包由于 MSS 的限制,必须进行分段。而网关作为需要处理大量数据报的设备,其效率永远是第一位的。这也就意味着 ALG 的对报文的识别通常是无状态的。当 ALG 接收到报文,通过协议特征判断出其对应的应用层协议,下一步就是建立 NAT 映射。

于是利用方式就出现了。当我们知道了网络的 MTUMSSIP 头长度、TCP 头长度,我们就可以通过巧妙构造 HTTP 请求,通过 POSTbody 产生 TCP 报文分段。如果分段后的报文恰好是合法的 FTP 主动模式连接建立报文,那么 ALG 就会被欺骗并创建端口 n+1 与被攻击者之间的 NAT 映射。

因此问题就恰巧出现在了上图的第二步:识别 FTP 协议。当 ALG 识别到了这样的协议,就会自动放行对应的流量;而当流量得到放行,攻击者就可以访问对应内网机器的其他端口了。

SIP 协议

上文中为了方便理解,我们一直举了 FTP 协议作为例子。而在实际的攻击行为中,SIP 协议才是被选取的受害者。

简单来说,SIP 协议的 INVITEREGISTER 需要构造类似 FTP 协议中 n+1 端口的开放才能正常工作,因此只要能够构造数据包,带有 SIP 的注册信息,就可以对内网的任意主机5060 端口进行打洞了。

TURN 协议

有的 ALG 实现 SIP 协议实现只允许 TCPTCP 的,UDPUDP 的,因此我们需要一个突破 UDP 的手段。TURN 就是被选中的受害者了。TURN 协议中有认证的环节,其中的 username 是以明文传输的,并且没有任何限制,这就是利用点了。

我们知道,UDP 协议是没有 MSS 的,其分片只会受 MTU 的影响。而当 IP 包被分片时,第二片报文中就不存在 UDP 报头了。也就是说,除了这个报文是 UDP 协议的报文之外,其他的一切 ALG 都一无所知。由此,我们就可以构造任意的 UDP 报文内容了,自然也包括 SIP 协议。

内网主机探测

现在我们有了能够打通 NAT 的能力,那被打的人在哪儿呢?原文给出了两种手段。

一种是通过 ICE 协议,还是 WebRTC 那一套探测内网;而另一种则是通过诸如 <img>onsuccessonerrortimeout 实现,当成功探测到 Web 服务器时是 success,其他 TCP 服务发送 RST 则为 onerrorIP 不存在则会产生一秒以上的耗时,可以通过计时器判断。

结语

有了打洞方式、探测手段和受害者,NAT Slipstreaming v1 的使命就完成了。利用 ALG 的合理行为,IP 协议的合理行为,TURN 协议的合理行为,以及 ICE 协议和 <img> 的合理行为,挡在我们面前的 NAT 被层层剥开,暴露出了其中一无所知的被害主机。

这也就是 NAT Slipstreaming 的暴露出来的核心问题:当所有协议都以其正确的方式运行时,却产生了足以致命的安全问题。而这,也对后续的协议设计有着巨大的启示意义。

参考

  1. https://samy.pl/slipstream/

Previous Post
绕过「9-nine-」的 CDKEY 验证——KrkrPlugin 正(?)向实录
Next Post
Go 学习笔记 02 - 找准 io 之道