由SNI代理错误配置引起的SSRF漏洞-网络攻防学习社区-安全圈子-FancyPig's blog

由SNI代理错误配置引起的SSRF漏洞

简介

SNI代理是使用SNI扩展字段来选择后端系统的负载平衡器。当配置错误时,SNI代理可能会受到SSRF攻击,提供对网络应用后端的访问。

正文

复杂 Web 应用程序中的一个典型任务是将请求路由到不同的后端服务器以执行负载平衡。大多数情况下,反向代理用于此。此类反向代理在应用程序级别(通过 HTTP)工作,并且请求根据Host标头的值(:authority对于 HTTP/2)或部分路径进行路由。

一种典型的错误配置是反向代理直接使用此信息作为后端地址。这可能导致服务器端请求伪造 (SSRF)漏洞,允许攻击者访问反向代理后面的服务器,例如,从 AWS 元数据中窃取信息。我决定调查对在其他级别/协议上运行的代理设置的类似攻击——特别是 SNI 代理。

什么是 TLS SNI?

服务器名称指示 (SNI) 是 TLS 协议的扩展,它提供了 HTTPS 的基础。当浏览器想要与服务器建立安全连接时,它会通过发送ClientHello消息来启动 TLS 握手。此消息可能包含一个包含服务器域名的 SNI 扩展字段。在其ServerHello消息中,服务器随后可以返回适合指定服务器名称的证书。典型的用例是当一个 IP 地址后面有多个虚拟主机时。

什么是 SNI 代理?

当反向代理(更准确地说,负载均衡器)使用 SNI 字段中的值来选择特定的后端服务器时,我们就有了一个 SNI 代理。特别是随着 TLS 和 HTTPS 的广泛使用,这种方法变得越来越流行。(请注意,SNI 代理的另一个含义是指使用此类代理来绕过某些国家/地区的审查。)

运行 SNI 代理有两个主要选项:有或没有 SSL 终止。在这两种情况下,SNI 代理都使用 SNI 字段值来选择合适的后端。使用 SSL 终止运行时,会与 SNI 代理建立 TLS 连接,然后代理将解密后的流量转发到后端。在第二种情况下,SNI 代理转发整个数据流,实际上更像 TCP 代理。

典型的 SNI 代理配置

许多反向代理/负载均衡器支持 SNI 代理配置,包括 Nginx、Haproxy、Envoy、ATS 等。看来您甚至可以在 Kubernetes 中使用 SNI 代理

以 Nginx 为例,最简单的配置如下所示(请注意,这需要 Nginx 模块ngx_stream_core_module才能ngx_stream_ssl_preread_module工作):

stream {
    map $ssl_preread_server_name $targetBackend {
        test1.example.com backend1:443;
        test2.example.com backend2:9999;
    }

    server {
        listen 443; 
        resolver 127.0.0.11;
        proxy_pass $targetBackend:443;       
        ssl_preread on;
    }
}

在这里,我们配置一个名为的服务器(TCP 代理)stream并使用 启用 SNI 访问ssl_preread on。根据 SNI 字段值(在 中$ssl_preread_server_name),Nginx 会将整个 TLS 连接路由到backend1backend2

SNI 代理错误配置导致 SSRF

允许您连接到任意后端的最简单的错误配置如下所示:

stream {
    server {
        listen 443; 
        resolver 127.0.0.11;
        proxy_pass $ssl_preread_server_name:443;       
        ssl_preread on;
    }
}

这里直接使用SNI字段值作为后端的地址。

通过这种不安全的配置,我们可以通过在 SNI 字段中指定所需的 IP 或域名来利用 SSRF 漏洞。例如,以下命令将强制 Nginx 连接到internal.host.com

openssl s_client -connect target.com:443 -servername "internal.host.com" -crlf

一般来说,根据RFC 6066,IP 地址应该用在 SNI 值中,但在实践中,我们仍然可以使用它们。更重要的是,我们甚至可以在这个字段中发送任意符号,包括空字节,这对漏洞利用很有用。如下所示,服务器名称可以更改为任意字符串。虽然对于这个特定的 Nginx 配置,不幸的是,我没有找到改变后端端口的方法:

6dc8701f56103604

另一类易受攻击的配置类似于典型的 HTTP 反向代理配置错误,涉及正则表达式 (regex) 中的错误。在此示例中,如果通过 SNI 提供的名称与正则表达式匹配,则流量将转发到后端:

stream {
    map $ssl_preread_server_name $targetBackend {
        ~^www.example\.com    $ssl_preread_server_name;
    }  

    server {
        listen 443; 
        resolver 127.0.0.11;
        proxy_pass $targetBackend:443;       
        ssl_preread on;
    }
}

此正则表达式不正确,因为第一个句点字符www.example.com未转义,并且表达式$末尾缺少终止符。生成的正则表达式不仅匹配www.example.com,还匹配www.example.com.attacker.comwwwAexample.com等 URL 。因此,我们可以执行 SSRF 并连接到任意后端。虽然我们不能在这里直接使用 IP 地址,但我们可以简单地通过告诉我们的 DNS 服务器www.example.com.attacker.com应该解析为 127.0.0.1 来绕过这个限制。

SNI 代理研究和滥用的潜在方向

在 2016 年一篇关于扫描 IPv4 以寻找开放 SNI 代理的文章中,研究人员设法找到了大约 2500 台服务器,并采用了相当基本的测试方法。虽然这个数字可能看起来很低,但 SNI 代理配置自 2016 年以来变得越来越流行并得到广泛支持,甚至可以通过快速搜索 GitHub 来证明这一点。 

作为进一步研究的方向,对于没有 TLS 终止的配置,我可以提出一些需要考虑的事项。SNI 代理仅检查第一条ClientHello消息,然后代理所有后续流量,即使它不是正确的 TLS 消息。此外,虽然 RFC 指定你只能有一个 SNI 字段,但实际上,我们可以发送多个不同的名称(TLS-Attacker是一个方便的工具)。ClientHello因为 Nginx 只检查第一个值,如果后端接受这样的消息但随后使用第二个 SNI 值,那么(理论上)可能有一条途径获得一些额外的访问权限。

避免 SNI 代理漏洞

每当您配置反向代理时,您都应该意识到任何错误配置都可能导致 SSRF 漏洞,从而使后端系统受到攻击。这同样适用于 SNI 代理,尤其是当它们在大型生产系统中越来越受欢迎时。一般来说,为了避免在配置反向代理时出现漏洞,您应该了解攻击者可以控制哪些数据,并避免以不安全的方式直接使用它。

 

原文选自《SSRF vulnerabilities caused by SNI proxy misconfigurations》

请登录后发表评论

    没有回复内容