原文地址:https://blog.christophetd.fr/bypassing-cloudflare-using-internet-wide-scan-data/

翻译水平有限,有不通顺的语句,请见谅。

原作者:Christophe Tafani-Dereeper
写于 18 January 2018

Cloudflare 是一个在网站和网站用户之间的中间人服务, 保护网站免受各种攻击. 不幸的是, 这些网站常常配置不当, 让攻击者可以完全绕过 Cloudflare ,并发起 DDoS 攻击,或者利用基于 web 的漏洞发送本应被阻止的恶意漏洞利用代码. 本文将展示这个漏洞,并介绍自动检测工具 CloudFlair.

cloud
cloud

太阳被一片云遮住了视线. 照片来自 Pixabay.

Cloudflare 可以保护网站防御各种攻击. 他还可以作为 Web 应用防火墙 (WAF) 来阻止一些基于web的漏洞利用,比如 XSS 和 SQL 注入. It gained even more traction recently by announcing unmetered mitigation of DDoS attacks: Cloudflare 基本上表示他们会保护他们的客户免受任何规模的 DDoS 攻击,而不收取任何额外费用, 无论客户是在任何价位的套餐 (包含免费套餐).

在过去的几周, 我发现有几个使用了 Cloudflare 网站的配置有错误,可以让攻击者轻易绕过所有 Cloudflare 的保护. 这几家公司的网站上都有超过百万的用户在使用,是其市场的顶级领域公司之一.

cf2.png
cf2.png
cf1.png
cf1.png
cf.png
cf.png

一些有漏洞的网站会有公开的漏洞悬赏计划

需要明确的是, 这篇文章讨论的并不是 Cloudflare 服务本身的漏洞, 而是使用了Cloudflare的网站的管理员通常的错误配置.

注意: 就在发布这篇文章前的几分钟, 有个人提醒我注意一篇相似的文章 写于几个月前. 虽然如此,我还是会发布这篇文章,因为我相信他能提高我对这个主题的认识(并且我花了太多的时间写这篇文章).

背景: 使用 Cloudflare 保护网站

以下是不受Cloudflare保护时网站的通常请求流程。

  1. 用户向网站托管提供商的DNS服务器建立连接, 询问 example.com 网站IP地址
  2. DNS 服务器回应example.com的服务器的IP地址 (比如, 93.184.216.34)
  3. 用户向web服务器发起 HTTP 请求
  4. web 服务器回应web网页数据

Without-CloudFlare-1.png
不受Cloudflare保护时网站的通常请求流程

由于任何人都可以直接访问托管example.com的Web服务器,因此攻击者可能会通过对其进行DDoS攻击来破坏网站。 如果example.com背后的基础设施不够强大,无法处理或阻止流量,那么该网站就可以完全被打到下线。

当公司 (或者个人) 决定使用 Cloudflare 来保护他们的网站

  1. 到他们的域名注册商, 将 DNS 服务器地址设置为 Cloudflare 的 (比如, kim.ns.cloudflare.com) ;
  2. 设置 Cloudflare 账号来管理域名 (比如, mycompany.com).

现在, 当用户访问 mycompany.com, 会发生以下的情况.

  1. 用户向 DNS 服务器 kim.ns.cloudflare.com建立连接, 询问 mycompany.com网站的IP地址
  2. DNS 服务器返回Cloudflare中介服务器 IP 地址 (e.g., 104.16.109.208)
  3. 用户向这台服务器发送 HTTP 请求
  4. Cloudflare 检查请求的合法性 (是否存在恶意请求内容,请求源IP地址,以及其他因素), 并决定放行或者阻断请求
  5. 如果 Cloudflare 选择让请求通过, 请求会被转发到负责 mycompany.com网站的真实服务器 (比如, 188.226.197.73). 这台服务器通常被称为 源站服务器(origin server).
With-CloudFlare.png
With-CloudFlare.png

受Cloudflare保护时网站的通常请求流程

理论上, 攻击者无法直接访问源站服务器, 特别是不知道源站服务器的IP地址。然而, 这个保护依赖于源站服务器只能通过Cloudflare访问.

为了让这层保护生效, 攻击者必须无法直接连接源站服务器. 否则, 他只需要和源站服务器连接,而不需要通过 Cloudflare, 并且绕过所有的保护.

暴露的源站服务器

在Cloudflare后的源站服务器应该采取的正确行为是,只接受来自Cloudflare 的 IP 范围 的流量. 但是, 很多源站服务器接受了所有地址的流入流量. 我相信这是因为Cloudflare 的文档中没有强调这个问题. 我在文档中找到最相关的内容,是一个名为为Cloudflare所有用户推荐的第一步页面 :

Step 1:将 Cloudflare的 IP 地址放入白名单

一旦你 修改域名服务器到 Cloudflare, web 流量会被路由到 Cloudflare 的网络. 欧耶! 这就意味着你的网络服务器将收到Cloudflare的大量的经过代理后的流量 , 并且为了允许所有的流量访问它, 你将需要确保 Cloudflare 的 IP 们是在白名单中的,并且没有限制速率 . 这个页面包含了所有的 Cloudflare IP.

(我的强调部分)

你可以看到, 这里只告诉系统管理员,将Cloudflare 的 IP 地址白名单,但是没有明确指引需要阻止其他来源的传入流量. Cloudflare的博客中, 预防DDoS: 保护源站服务器 在我看来更加糟糕, 文中暗示,只需要让源站服务器的IP足够”秘密”即可.

Cloudflare 不能阻止知道你源站IP地址的攻击者直接向你发送流量. 只是因为你的源站服务器的IP地址不需要通过DNS,就已经连接到互联网. 如果你的IP地址不保密, 攻击者就能绕过 Cloudflare 的网络,直接攻击你的服务器.

(我的强调部分)

总而言之 – 只要没人能找到源站服务器的IP地址,那么它就是安全的.

Censys的互联网扫描数据

不幸的是, 在 2018 年, 依靠别人无法找到你的IP地址来保证安全,还能说有点乐观. 像 Shodan 或者 Censys 这样的项目会不停的扫描互联网中的主机,任何人都可以免费访问到这些数据.

举个随便的栗子, 他们只需要一秒钟就能检索出互联网上所有的 标题中包含Nicolas Cage 或者Rick Astley HTTP 服务器 .

censys-768x374.png
censys-768x374.png

搜索的一个例子 (点击来放大)

Censys 非常适合查找暴露的源站服务器. 以下部分描述了使用Censys检测特定域名的公开源服务器的方法。

使用Censys查找某个域名的暴露的源站服务器

查找可公开访问的源站服务器的有效方法是,利用他们的 SSL 证书. 通过 Censys 证书搜索功能(Certificate search feature), 我们能搜索一个指定域名的有效 SSL 证书. Censys 从多个途径收集这些证书 (直接探测 443 端口, 以及证书透明项目(Certificate Transparency project)的日志信息).

举个例子, 查询请求 parsed.names: reddit.com and tags.raw: trusted 能用于查询颁发给reddit.com的有效证书,或者是颁发给它的子域名. 这个 链接 会使用上述请求,直接跳转到 Censys 搜索.

reddit-768x381.png
reddit-768x381.png

查找颁发给reddit.com的 SSL 证书,和它的子域名 (点击即可放大)

你可以看到,Censys 找到了 7 个单独的证书. 如果你单击某一个, 则可以选择查找在端口443上探测时,发现此证书的所有IPv4主机。

Untitled-drawing-4.png
Untitled-drawing-4.png
reddit2-768x381.png
reddit2-768x381.png

Finding IPv4 hosts using a specific SSL certificate (点击即可放大)

在这个 视图中,我们能看到,所有的 IPv4 主机使用的 SSL 证书的 SHA256 指纹信息是 36f7[…]815a0a.

这种简单的方式,来查找颁发了SSL证书到指定域名的 IPv4 主机,可以用于寻找源站服务器.

  • 查找颁发给 mytarget.tld 域名的SSL 证书
  • 找到所有使用了这些证书的 IPv4 主机
  • 检查这些主机是否有可能是 mytarget.tld 的源站服务器

检查一个主机是否是(可能性)源站服务器

一旦我们有了一个潜在的源站服务器列表, 接下来的问题是: 我们如何评估那个主机就是特定Cloudflare保护域名后的源站服务器? 这里没有灵丹妙药(silver bullet),因为只有那家公司的系统管理员才会明确知道, 但是有一些启发式的方法可以提供帮助.

首先, 目标主机的IP地址不会在 Cloudflare IP 地址范围中, 否则, 我们找到的就是 Cloudflare 在源站和用户之间的中间人服务器. 然后, 目标主机的 HTML 回应应该类似于我们使用他的标准域名访问得到的回应 (比如, mytarget.tld). 我之所以说类似,因为精确的相等在这里非常严谨, 当你在访问同一网页时,网页的每个部分都在发生变化 – CSRF tokens(令牌), 会话标识, 等等.

一旦我们找到一组符合这些标准的主机, 我们就可以基本相信我们找到了一组公开的源站服务器. 当然, 这些主机可能和 mytarget.tld相似,但是实际上是开发环境或者是阶段性实例. 我们无法 100 % 信任, 但是可以直接浏览来帮助筛选, 并查看它是否能像访问mytarget.tld的正式环境那样的行为: 能否注册账号? 能否登录你在mytarget.tld创建的账号 , 反之亦然(vice versa)? 如果确定可以, 你就应该非常自信的确认你找到了一组不应公开的源站服务器.

请记住,通过在浏览器的地址栏中直接输入IP地址,来访问源站服务器,有时候不起作用, 因为运行的 web 服务器可能会验证一个 HTTP Host 请求头. 在这种情况下,你可以在Hosts文件中添加一个静态映射,或者使用 curlPostman 这样的工具,在工具内可以设置指定的 Host 请求头.

使用 CloudFlair 自动处理

手动完成这个过程可能比较麻烦; 所以我写了个叫CloudFlair的工具来自动化完成 . 它会调用 Censys API 来搜索 SSL 证书和关联的 IPv4 主机. 一旦它使用之前描述的方式得到了潜在的源站主机列表, 它会挨个访问 ,并计算响应和原来域名返回响应的相似性. 它使用了一个结构相似的函数,这个函数被设计用于比较web网页 ( 这里描述的), 因为标准的字符串相似函数,比如 Levenshtein 距离对于计算常规web页面大小的运行太慢.

以下是一个示例的输出.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
$ python cloudflair.py myvulnerable.site

[*] The target appears to be behind CloudFlare.

[*] Looking for certificates matching "myvulnerable.site" using Censys
[*] 75 certificates matching "myvulnerable.site" found.

[*] Looking for IPv4 hosts presenting these certificates...
[*] 10 IPv4 hosts presenting a certificate issued to "myvulnerable.site" were found.
- 51.194.77.1
- 223.172.21.75
- 18.136.111.24
- 127.200.220.231
- 177.67.208.72
- 137.67.239.174
- 182.102.141.194
- 8.154.231.164
- 37.184.84.44
- 78.25.205.83

[*] Retrieving target homepage at https://myvulnerable.site

[*] Testing candidate origin servers
- 51.194.77.1
- 223.172.21.75
- 18.136.111.24
responded with an unexpected HTTP status code 404
- 127.200.220.231
timed out after 3 seconds
- 177.67.208.72
- 137.67.239.174
- 182.102.141.194
- 8.154.231.164
- 37.184.84.44
- 78.25.205.83

[*] Found 2 likely origin servers of myvulnerable.site!
- 177.67.208.72 (HTML content identical to myvulnerable.site)
- 182.102.141.194 (HTML 98 % structurally identical to myvulnerable.site)

view raw

获得了可能是源站服务器的IP地址列表后,你仍旧需要手工检查来确认这些结果.

修复措施

更新: 在 Cloudflare的CTO 在Twitter指出这个问题后, 未来最好的缓解措施可能是使用 Cloudflare Warp. 这个功能目前还在测试阶段, 但是可能成为扭转这个问题的重要功能. 我没有深入研究细节, 但是实质上,它允许你从专用网络(不可公开路由)打开一个通往 Cloudflare 的隧道, 确保只有 Cloudflare 能连接到你的源站服务器 (因为你的源站服务器没有暴露在公网中).

如果你的网站对于本文讨论的弱点有缺陷, 那么很可能没有简单的方法来解决. 一旦源站服务器的IP地址泄露了,游戏结束. Censys 使用的数据已经加上了版本管理, 并且任何人都可以在此下载 数据在任何时间的快照.而且, 现在服务器上的传入流量是不足以保护免受 DDoS 攻击的. 使用软件层面的iptables来丢弃流量,是不能保护攻击者发送的大流量数据包到服务器,这会消耗掉所有可用的带宽,让其不能被合法访问的用户访问.

以下两步措施是我推荐要做的.

  • 第一步,应该是防止你的源站IP地址再次出现在 Censys 的扫描中, 并确保Cloudflare的应用层的安全功能无法被绕过 (比如 WAF 或者 HTTP 终点的速率限制).
  • 第二步,应该是 (并且是唯一的方法) 防止攻击者对你发动 DDoS 攻击.

Step 1: 在传入流量启用防火墙或者开启 Authenticated Origin Pulls 功能

在你的源站服务器上配置,使之仅接受来自Cloudflare 的 IP 范围传入流量. 参考如下:

注意: 在应用这些步骤之前, 请确保你了解 这将阻止你从SSH, RDP, FTP访问你的服务器, or 任何 基于非HTTP 的协议. 根据你的需要,这可能没问题. 但是, 如果你仍需要通过这些协议中的一种接入你的源站服务器, 那么你需要开启对应的端口.

另一种限制传入流量到 Cloudflare 的服务器的方法是,在账户上开启Authenticated Origin Pulls功能, 并对应的配置你的 web 服务器. 在与源站服务器通信的时候,这个功能可以让 Cloudflare 使用一个 TLS 客户端证书进行身份校验.

Step 2: 更换你的源站服务器IP地址

综上所述,一旦源站IP被泄露,游戏结束。最好的解决方案,如果可以的话,DDoS攻击也对你构成可信威胁的情况下,更换IP地址. 这要取决于你的服务器提供商, 可能很容易实现,也可能很难实现.

致谢

我想向下面的人们致以诚挚的谢意,感谢他们的多重建议和校对这篇文章!

感谢你的阅读! 欢迎在下面评论或者给我发推 @christophetd 进行讨论和评论。