正确的 性能对网络安保是如此关键 WAF
有钻研人员在安保测试时,绕过了 Cloudflare WAF 的 SQLi 过滤器,这象征着Cloudflare 装置没有正确性能,但Cloudflare目前还不以为这是个破绽。虽如此,安保人员在为其运行程序部署安保包全时须要留意无关疑问。关于试图绕过 WAF 的人来说,发现的些许破绽也或者会派上用场。攻打者可以应用一种或多种技术(详细取决于最终运行程序)绕过某些 WAF 并经过滥用 SQLi 破绽窃取数据。
测试时经常使用的Web运行程序详细信息
测试时经常使用的Web 运行程序的目的关于实践测试来说并不关键。除了在主机上地下的 /graphql 端点和运转查问的 PostgreSQL 服务之外,写入查问的堆栈也并不关键。 GraphQL 是一种查问言语,它处置查问,在测试中,在后端运转适当的 SQL 查问并前往恳求的数据。之前由于测试人员从未经常使用或浏览过无关 GraphQL 的信息,因此遵照的是官网教程,假设感兴味你也可以了解一下。
查问的构成相似于 JSON 对象。运行程序向 /graphql 端点发送 POST 恳求。恳求注释蕴含 GraphQL 查问,如下所示:
X-MARK 中未过滤的参数从 GraphQL 传递,并在 PostgreSQL 存储环节中被交流,从而准许咱们注入在后端主机上口头的 SQL 查问。
这简直是咱们目前必定了解的关于运行程序的内容。在接上去的局部中,我将引见我在测试 SQL 注入运行程序时观察的一些现象,这些观察使我成功地利用了SQL注入,包括绕过Cloudflare SQLi过滤器。
观察 1
第一个关键的观察结果是主机对有效的电子邮件输入(即当 SQL 查问前往数据时)的照应与对有效的电子邮件输入的照应不同。前往的 HTTP 代码一直为 200,但照应注释不同:
这将前往“OK”:
这将前往"NOT OK":
后来这或者看起来不太像,但它实践上是准许我验证数据库中特定数据能否存在的机制。它让我想到了应用这种机制口头SQL盲注入攻打并经常使用脚本智能化它的想法。该脚本结构一个有效负载,并将其与POST恳求一同发送,POST恳求反上来修正在后端主机上运转的SQL查问。
步骤如下:
观察 2
第二个关键的观察结果是,在口头的SQL查问出现失误时,会显示失误信息,这对我来说容易得多。这个失误信息不准许我口头一个基于失误的SQL注入,而是显示了由PostgreSQL在SQL主机上口头的完整SQL查问。这一点为什么如此关键,咱们很快就会明确。
从失误信息中提取的SQL查问看起来像这样:
作为“email”变量提交的用户输入反映在X-MARK上。这就是为什么领有完整的SQL查问关于开发环节很关键的两个要素:
留意:第 8 行的 $1 符号是 SQL 预备查问的位置参数,并由 HTTP 恳求的“称号”变量参数交流。但它不容易遭到 SQL 注入的影响。
第一次性尝试
我首先尝试查找数据库的称号。在 PostgreSQL 中口头此操作的 SQL 查问是:
有很多事件须要思考,而且从一开局就很疯狂,我必定从一开局就想出绕过 Cloudflare 的方法。
WAF 绕过的第一种方法
首先,我必定首先将 current_database() 的第一个字符与字符“a”启动比拟。PostgreSQL的方法是:
Cloudflare会阻塞'substr'函数,所以窍门是要么经常使用'left',要么经常使用'right'函数。我经常使用'right'函数,由于'left'给了我一些费事,当我试图找出我曾经找到一切的数据库称号的字符。新的查问(将“a”与最后一个资源的字符启动比拟,如下所示:
并且未被 WAF 检测到。
留意:函数 right(current_database(), N) 前往数据库称号最左边的 N 个字符。因此,当找到最后一个字符时,例如X,下一次性调用该函数应该是:
由于咱们曾经知道咱们必定封锁查问中的左括号(来自观察2),POST 恳求的注释如下所示(此处仅显示'email'变量):
然而,记住后端 SQL 查问如何蕴含 JOIN 子句(来自观察2),我还在查问中参与了一些额外的内容,以确保 SQL 衔接在后盾正确口头。 POST 恳求的注释如下所示:
主机上的后续 SQL 查问如下所示:
这很复杂,但想法是一样的:假设“a”是数据库称号的最左边的字符,咱们将从主机取得一个“OK”照应。
无论如何,在向主机提交这个恳求后,我看到了Cloudflare WAF(性能失误)的可怕页面,通知我我的恳求被阻止了。
第二次尝试
在我再次尝试之前,我必定了解 Cloudflare 对我的查问有什么协助。
经过重复测试,我发现疑问出在生成的主机 SQL 查问中的 FROM 子句中的空格。这造成我进入第二个 WAF 绕过。
WAF 绕过的第二种方法
此处经常使用的第二种 WAF 绕过技术消弭了 SQL 查问中的空格,并将 SQL FROM 子句的局部括在括号中。
变成了:
因此 POST 恳求的结果注释变为:
在主机上的后续SQL查问是这样的:
这样,整个环节就可以成功智能化了,以找到数据库称号的整个值。相反的环节还检索了用户名(经过经常使用 user 函数)和数据库版本(经过经常使用 version() 函数)。然而存储在数据库表中的数据呢?检索这些数据的通用查问,以及我在文章中经常使用的绕过方法的查问都不起作用。两者都被阻止:
为什么我的查问被阻止了?疑问是紧跟在 SELECT 子句之后的 FROM 子句。以下查问将很好地经过(失误性能的)Cloudflare WAF SQLi 过滤器:
一旦在查问完结时引入 WHERE 子句,WAF 就会启动并阻止恳求。我的最终指标是从任何表中检索数据。是时刻深化开掘兔子洞了。
第三次尝试
我在这里给出 SQLi 的早期失败尝试,只是由于我宿愿这篇文章向人们展如今浸透测试时期思想环节是如何开展的。
在我尝试使事件复杂化(即脱离一切 JOIN 和 FROM 子句)时,我经常使用了一个便捷的分号和注释技巧 (;--)。方案是首先检索数据库称号,而后在此基础上检索表中的数据:
主机上生成的 SQL 查问如下:
无论如何,这当然行不通,要素有两个:
第四次尝试
我在这里给出了从表中检索数据的另一个早期尝试,它使我更凑近我的指标。在此之前我所知道的是,以下负载将被WAF 阻止:
留意:我参与了 LIMIT 和 OFFSET 关键字,以便从 table1 中仅检索一行。 LIMIT 示意咱们只想要检索一行,OFFSET 示意在开局检索数据之前咱们想要跳过多少行。在这种状况下,OFFSET 0 示意数据库应该跳过 0 行并前往 table1 中的第一行。这关于逐个检索表的一切行很有用。
WAF 绕过的第三种方法
回忆从数据库主机发生的失误中检索到的 SQL 查问,我留意到或者不须要经常使用 FROM 子句。 table1 表在经常使用 AS 关键字的查问中别名为 t1,并且可以基于 t1 援用它的任何列。这样就可以这样查问 table1 的 column1 列:
这可以很好地经过(失误性能的)Cloudflare WAF,因此 POST 恳求注释中的有效负载可以这样转换:
主机上的后续 SQL 查问如下所示:
这可以反常上班,但限度是只能提取 table1(或 table2)中的数据,由于这些是主机 SQL 查问中惟一的别名表,继续启动最后的成功尝试。
最后一次性尝试
好吧,假设我想从数据库中检索任何我想要的数据,我不得不丢弃WAF 绕过的第三种方法。此时,仿佛没有方法防止经常使用FROM子句。而且,在不被Cloudflare的WAF检测到的状况下,仿佛也没有方法成功地将FROM子句暗藏到有效载荷中。仿佛我正在寻觅的答案不在SQL查问中。我不得不前进一步。
进入 GraphQL
咱们曾经看到发送的恳求的注释是一个 GraphQL 查问,而后它被翻译成一个 SQL 查问。所以我的下一个尝试是扭转 GraphQL 查问并设法暗藏其中的 FROM 子句,这将有望转换为在主机上上班的SQL查问。
如上所述,GraphQL 查问的结构相似于 JSON 对象。 JSON 中的数据以称号/值对存储在字典中,它们都是字符串。 GraphQL 查问须要字符串键,但准许经常使用恣意参数。这些规则实用于 GraphQL:
因此一个GraphQL查问参数可以看起来像以下任何一种模式:
这让我想到:假设我将对象的值作为数组而不是字符串传递,后端主机上的 SQL 查问会出现什么。简而言之,我想冲破 SQL 注入查问并将 FROM 子句移动到不同的对象以诈骗 Cloudflare。
进入
该恳求绕过了WAF,我从数据库中获取了一个失误,报错是一个格式不正确的SQL查问,并向我显示了完整的SQL查问结果。在注入点的查问是这样的:
留意 SELECT column1 前面的逗号 (,) 吗?那是我绕过SQLi 过滤的凭证。将 GraphQL 查问参数的值作为数组传递会在后端 SQL 主机中转换为字符串。字符串只是由逗号和空格字符分隔的数组项的串联!此时,SQL查问是失误的,但我可以注释掉逗号,并取得一个有效的、绕过waff的恳求,该恳求从我选用的任何数据库表中检索我想要的任何数据。
这是最终 POST 恳求的注释:
以及在 SQL 主机上生成的有效 SQL 查问:
成功!
为了简化表检索环节,我用Python编写了一个脚原本智能化这个环节。脚本的伪代码如下所示:
这就是我如何应用 GraphQL 制造 SQL 注入,绕过性能失误的 Cloudflare WAF 实例,并能够在后端检索整个数据库。正如我在扫尾提到的,这种绕过技术的组合不实用于正确性能的 Cloudflare WAF。
缓解措施
缓解数据库上 SQL 注入的最安保方法是预备好的语句。