Bypassing Web Filters Part 1 SNI Spoofing
这是一系列关于绕过网络过滤器技术的博客文章的第一部分,每一部分都会探讨越来越高级的技术。
早在 2019 年(是的,已经过去很长时间了),我看到一条推文 1,讲述了如何使用 SNI 欺骗来绕过网络过滤器:
好吧,SNI 欺骗比我想象的更酷。它可以轻松绕过这些深度数据包检测设备和下一代防火墙过滤器。
想访问一个"恶意"网站?被阻止了?只需将 SNI 值更改为 Windows 更新地址即可。
PAUL SEEKAMP @NULLENC0DE (推文)
我之前从未听说过 SNI 欺骗,所以我很好奇它是什么,它如何工作,以及如何用它来绕过那些讨厌的网络过滤器。因此,我做了一些研究和实验。如果你想知道这些问题的答案,请继续阅读。
绕过网络过滤器博客文章系列:
-
绕过网络过滤器第一部分:SNI 欺骗 -
绕过网络过滤器第二部分:Host 头欺骗 -
绕过网络过滤器第三部分:域名前置 -
绕过网络过滤器第四部分:Host 头欺骗和域名前置检测绕过
网络过滤器/代理简介
在我们开始探索各种绕过网络过滤器/代理的技术之前,我想简要介绍一下什么是网络过滤器以及它们可能有的不同配置。
网络过滤器是一个检查互联网流量(特别是 HTTP 和 HTTPS 请求)的系统,用于确定请求是否合法或应该被阻止。这些过滤器通常被称为 HTTP 代理。在许多情况下,网络过滤器被集成到防火墙中(也称为应用层防火墙、企业网关、下一代防火墙等),除了标准的 TCP/IP 防火墙功能外,还具有入侵检测等附加功能。网络过滤器也可以在专用代理上运行,该代理仅负责检查和过滤网络流量。
网络过滤器/代理模式
HTTP 代理可以在两种模式下运行:"正常"模式(也称为"显式"或"非透明"模式)和"透明"或"不可见"模式。
正常/显式/非透明代理
在正常模式下,代理服务器充当客户端和目标网站之间的中介。当客户端请求访问网站时,首先建立到代理的新连接。客户端通过 HTTP CONNECT
方法告诉代理它想要建立连接的目标网站。在向客户端确认连接已建立后,代理将请求转发到目标系统,并将响应发回客户端。
有趣的是,客户端不执行任何 DNS 查询,它只是将主机名发送给代理。然后代理将为提供的主机名执行 DNS 查询。
下图显示了一个示例,其中 Alice 通过代理使用 HTTP 连接到 example.net。这个代理在客户端上配置。通过 HTTP CONNECT
方法建立到代理的连接。然后代理连接到目标网站。进一步的请求和响应在客户端和网站之间转发:
这在 Wireshark 中也可以看到。客户端首先通过 HTTP CONNECT
方法建立到代理的连接,并告诉代理目标服务器的主机名①。连接建立后,客户端向代理发送 HTTP 请求②。然后这个请求和相应的响应在客户端和服务器之间转发③:
当使用 HTTPS / TLS 时也是如此。在通过 CONNECT
方法建立到代理的连接后,所有 TLS 消息都被转发到目标服务器。由于 TLS 隧道是在服务器和客户端之间建立的,代理无法读取加密数据。
透明/不可见代理
在透明模式下,代理服务器拦截用户的请求,而无需在客户端进行任何配置。客户端甚至可能不知道流量正在通过代理发送。代理服务器仍然处理请求和响应,但不会更改原始请求头。这种模式通常用于管理员希望在不需要用户干预的情况下执行策略的环境中。
下图显示了一个示例,其中 Alice 通过透明代理服务器使用 HTTP 连接到 example.net。这个代理服务器没有在客户端上配置。不需要建立到代理的额外连接。网络流量只是通过代理路由,数据包在那里被转发:
在这种情况下,DNS 查询必须在客户端执行,因为这是唯一主动建立的连接。
TLS 检查
代理可以简单地检查和转发请求,如上所示,或执行 TLS 检查。TLS 检查意味着 TLS 流量被解密,以便进行更彻底的分析。为了正确工作,客户端必须安装代理的根证书。否则,客户端将拒绝连接并收到 TLS "未知 CA"错误。
当通过执行 TLS 检查的"正常"模式代理建立 HTTPS 连接时,代理将 TLS 握手转发到目标服务器①并完成 TLS 握手②。然后代理与客户端完成 TLS 握手③,但使用由代理的 CA 签名的新生成的证书。由于 TLS 隧道在客户端和代理之间建立,另一个在代理和服务器之间建立,代理可以读取所有传输的数据。
注意:有些代理首先通过直接发送 ServerHello 来完全完成与客户端的 TLS 握手,只有在成功建立此 TLS 连接后才建立与目标服务器的连接。具体实现方式取决于所使用的代理。
透明代理也能检查 TLS 流量。代理还将与客户端和服务器建立单独的 TLS 连接,但只是通过替换必要的数据包。这再次允许代理检查 TLS 流量:
什么是 SNI
服务器名称指示(Server Name Indication,SNI)是 TLS 协议的一个扩展,定义在 RFC 60662 中。这个扩展允许客户端在 TLS 握手开始时的 ClientHello
中告诉服务器它试图连接的主机名。这对于在同一 IP 地址上托管多个网站的服务器特别有用,因为它允许服务器在 ServerHello
消息中向客户端提供正确的证书。
例如,如果你在浏览器中访问 https://www.compass-security.com
,浏览器会在 TLS 握手期间的 ClientHello
中使用 SNI 扩展告诉网络服务器连接到主机 www.compass-security.com
:
注意:在大多数 TLS 版本中,包括 TLS 1.3,ClientHello
在 TLS 握手中是不加密的,除非使用特定的扩展,如加密 ClientHello
(ECH)3。因此,每个能够访问网络流量的系统都能看到客户端连接到哪个主机,即使使用了 TLS。
然后网络服务器知道应该使用 www.compass-security.com
的证书在 TLS 握手期间的 ServerHello
中继续:
证书是否以明文发送取决于所使用的 TLS 版本。在上面的截图中,使用的是 TLS 1.2,其中证书总是以明文形式发送给客户端 4。
在 TLS 1.3 中,证书不以明文形式包含在 ServerHello
中,而是在加密消息中发送给客户端 5:
基于 SNI 的网络过滤器
现在我们知道了 SNI 是什么以及它如何工作,让我们看看这与网络过滤器有什么关系。由于 TLS 握手中 SNI 字段中的主机名是以明文传输的,它为防火墙或代理提供了一种简单的方法来基于这个主机名识别和阻止流量。
例如,这可以用来阻止用户访问恶意网站或恶意软件与其 C2 服务器通信。
使用 SNI 欺骗绕过简单网络过滤器
想象你有以下情况,Alice 能够访问网站 legit.example.net
,但访问 evil.example.com
被防火墙因为 SNI evil.example.com
而阻止:
Alice(或她电脑上的恶意软件)现在可以通过连接到 evil.example.com
的 IP 地址(198.51.100.23
)但使用 SNI legit.example.net
来绕过网络过滤器:
这种攻击需要控制 TLS 请求,这可以通过在系统上运行的恶意软件或试图绕过网络过滤器的攻击者或具有系统访问权限的用户来实现。
最终的 IP、TLS 和 HTTP 数据包结构如下所示:
这种技术只有在恶意主机能够处理具有合法主机名 SNI 的 TLS 握手时才有效。如果恶意主机在攻击者的控制之下,这可以轻松完成,一些网络服务器会自动接受任意 SNI。然而,如果恶意主机无法控制,这个系统可能无法为任意 SNI 提供正确的内容。
使用 OpenSSL 的示例
可以使用例如 openssl
6 建立如上所示的 TLS 连接:
openssl s_client -connect 198.51.100.23:443 -servername legit.example.net
-
openssl
的s_client
子命令可用于建立 TLS 连接。 -
-connect
选项用于建立到evil.example.com
的 IP 地址的 TLS 连接。 -
-servername
选项用于将 SNI 设置为legit.example.net
。
因此,此命令建立了一个到 evil.example.com
的 IP 地址(198.51.100.23
)的 TLS 连接,SNI 为 legit.example.net
。这也可以在网络流量中看到:
当使用 TLS 1.2 时(可以在 openssl
命令中使用 -tls_1_2
选项强制执行),响应中的证书显示 TLS 连接已建立到具有 evil.example.com
证书的服务器:
使用 curl 的示例
使 url`7 也可以实现相同的效果:
curl -k --connect-to legit.example.net::198.51.100.23: -H "Host: evil.example.com" https://legit.example.net
-
-k
选项告诉 curl 忽略证书警告。由于主机名与证书的主题/主题备用名不匹配,证书将不被信任。 -
--connect-to
选项告诉 curl 在使用主机名legit.example.net
时连接到提供的evil.example.com
的 IP 地址(198.51.100.23
)。 -
-H
选项告诉 curl 将 HTTP Host 请求头设置为evil.example.com
,以便 Web 服务器知道客户端想要访问哪个虚拟主机。根据 Web 服务器的配置,也可以省略此选项以使用合法主机名。
这建立了一个到 evil.example.com
(198.51.100.23
)IP 地址的 TLS 连接,SNI 服务器名称为 legit.example.net
。curl 自动在 SNI 中使用目标 URL 中的合法主机名:
注意:Wireshark 中的 TLS 流量被解密仅用于显示 HTTP Host 头。不执行 TLS 检查的普通防火墙/Web 过滤器将无法看到此信息。
在执行 TLS 检查的显式代理上绕过 SNI
在上面的 curl 命令中,没有配置显式代理,这通常是透明代理设置中的情况。起初,我认为 SNI 欺骗只能在透明代理设置中进行,因为在使用显式代理的设置中,目标主机名的 DNS 解析是在代理上而不是在客户端上完成的。当 DNS 解析在代理上执行时,客户端如何告诉代理建立到另一个 IP 地址的连接?
经过一些实验,结果发现我的假设是错误的,这可以很容易地完成,即使是使用 TLS 检查代理。客户端可以在 CONNECT
方法中告诉代理建立到 IP 地址的连接。然后客户端可以与代理执行包含伪造 SNI 的 TLS 握手。代理随后将建立到提供的 IP 地址的连接并使用伪造的 SNI。curl 的 --proxy
选项可用于指定代理:
curl --proxy http://10.5.23.42:8080 -k --connect-to legit.example.net::198.51.100.23: -H "Host: evil.example.com" https://legit.example.net
客户端首先会通过代理使用 HTTP CONNECT
方法建立到目标 IP 地址的连接①。然后代理会建立到提供的 IP 地址的连接②,并从客户端发送伪造的 SNI③。之后,代理将在客户端和服务器之间转发数据包:
然而,有些代理不遵守来自 CONNECT
请求的 IP 地址①,而是直接解析 SNI 中的主机名②并连接到该 IP 地址③:
这表明并非所有代理产品的工作方式都相同,绕过方法高度依赖于所使用的软件或代理配置。
SNI 欺骗防护和限制
应该清楚的是,仅通过查看 SNI 来阻止/允许 TLS 连接既不是一种非常先进,也不是一种可靠的 Web 过滤技术。我在多个客户的渗透测试和客户端加固/基础设施审查中尝试了这种绕过方法,但遗憾的是从未成功。如果实施了 Web 过滤,会应用更强大的技术,如检查 TLS 流量。
例如,Fortinet 的 FortiGate 的 Web 过滤模块有对 SNI 执行额外检查的选项:
当 Server certificate SNI check
选项设置为 Enable
时,FortiGate 将使用证书中的服务器名称 (主题或 SAN) 来检查是否允许或阻止连接。此外,如果设置为 Strict
[8],如果 SNI 和主题/SAN 不匹配,连接将直接终止。
这意味着要绕过这样的 Web 过滤器,你还需要控制相关证书的主题,使其与你指定的 SNI 正确对齐。因此,连接到任意被阻止的网站将不可能,因为它们的证书与伪造的 SNI 不匹配。然而,如果你也控制了服务器,例如运行你的 C2 服务器时,这可以通过安装颁发给允许主机名的自签名证书来完成。为防止此类攻击,Web 过滤器应始终正确验证证书链,并终止不受信任证书的连接。
总结
总之,SNI 欺骗可用于绕过一些基本的 Web 过滤器,但当配置正确时,它不是一种可以对抗更复杂过滤机制的技术。
在本系列的第 2 部分中,我们将研究通过 Host
头欺骗来绕过 Web 过滤器。
参考文献
-
@nullenc0de 关于绕过 SNI 过滤器的推文:https://twitter.com/nullenc0de/status/1159805999332638720↩︎ -
RFC 6066, TLS 扩展定义,第 3 章,服务器名称指示:https://datatracker.ietf.org/doc/html/rfc6066#section-3↩︎ -
Internet 草案,TLS 加密客户端 Hello: https://www.ietf.org/archive/id/draft-ietf-tls-esni-22.html↩︎ -
RFC 5246, TLS 1.2, 握手中的证书:https://datatracker.ietf.org/doc/html/rfc5246#section-7.4.2↩︎ -
RFC 8446, TLS 1.3, 握手中的加密证书 (第 11 页图): https://datatracker.ietf.org/doc/html/rfc8446#section-2↩︎ -
OpenSSL s_client
手册页:https://docs.openssl.org/master/man1/openssl-s_client/↩︎ -
curl(1)
手册页:https://curl.se/docs/manpage.html↩︎ -
FortiGate 管理指南,配置 SSL/SSH 检查配置文件:https://docs.fortinet.com/document/fortigate/7.6.0/administration-guide/709167/configuring-an-ssl-ssh-inspection-profile↩︎↩︎
原文始发于微信公众号(securitainment):绕过网络过滤器第一部分:SNI 欺骗
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论