Skip to content

6、绕过 Web 应用程序保护

在理想情况下,目标端不会部署任何保护措施,因此不会阻止自动利用。否则,在针对此类目标运行任何类型的自动化工具时,我们可能会遇到问题。尽管如此,SQLMap 中加入了很多机制,可以帮助我们成功绕过这种保护。

Anti-CSRF 令牌绕过

防止使用自动化工具的第一道防线之一是将 Anti-CSRF(即跨站点请求伪造)令牌合并到所有 HTTP 请求中,尤其是那些因 Web 表单填写而生成的请求。

用最基本的术语来说,这种情况下的每个 HTTP 请求都应该有一个(有效的)令牌值,只有当用户实际访问和使用该页面时才可用。虽然最初的想法是防止出现带有恶意链接的情况,在这种情况下,仅打开这些链接会对不知情的登录用户产生不良后果(例如,打开管理员页面并添加具有预定义凭据的新用户),但此安全功能也无意中强化了针对(不需要的)自动化的应用程序。

然而,SQLMap 有一些选项可以帮助绕过反 CSRF 保护。即,最重要的选项是 --csrf-token。通过指定令牌参数名称(它应该已经在提供的请求数据中可用),SQLMap 将自动尝试解析目标响应内容并搜索新的令牌值,以便它可以在下一个请求中使用它们。

此外,即使在用户未通过 --csrf-token 明确指定令牌名称的情况下,如果提供的参数之一包含任何常见的中缀(即 csrfxsrftoken),系统也会提示用户是否在进一步的请求中更新它:

$ sqlmap -u "http://www.example.com/" --data="id=1&csrf-token=WfF1szMUHhiokx9AHFply5L2xAOfjRkE" --csrf-token="csrf-token"

        ___
       __H__
 ___ ___[,]_____ ___ ___  {1.4.9}
|_ -| . [']     | .'| . |
|___|_  [)]_|_|_|__,|  _|
      |_|V...       |_|   http://sqlmap.org

[*] starting @ 22:18:01 /2020-09-18/

POST parameter 'csrf-token' appears to hold anti-CSRF token. Do you want sqlmap to automatically update it in further requests? [y/N] y

Unique(唯一) Value Bypass

在某些情况下,Web 应用程序可能只需要在预定义参数内提供唯一值。这种机制类似于上面描述的Anti-CSRF 技术,只是不需要解析网页内容。因此,通过简单地确保每个请求都有一个预定义参数的唯一值,Web 应用程序可以轻松防止 CSRF 尝试,同时避免一些自动化工具。为此,应使用选项 --randomize,指向包含在发送前应随机化的值的参数名称:

$ sqlmap -u "http://www.example.com/?id=1&rp=29125" --randomize=rp --batch -v 5 | grep URI

URI: http://www.example.com:80/?id=1&rp=99954
URI: http://www.example.com:80/?id=1&rp=87216
URI: http://www.example.com:80/?id=9030&rp=36456
URI: http://www.example.com:80/?id=1.%2C%29%29%27.%28%28%2C%22&rp=16689
URI: http://www.example.com:80/?id=1%27xaFUVK%3C%27%22%3EHKtQrg&rp=40049
URI: http://www.example.com:80/?id=1%29%20AND%209368%3D6381%20AND%20%287422%3D7422&rp=95185

计算参数 Bypass

另一种类似的机制是 Web 应用程序期望根据某些其他参数值计算出适当的参数值。大多数情况下,一个参数值必须包含另一个参数的消息摘要(例如 h=MD5(id))。要绕过这个,应该使用选项 --eval,在将请求发送到目标之前评估有效的 Python 代码:

$ sqlmap -u "http://www.example.com/?id=1&h=c4ca4238a0b923820dcc509a6f75849b" --eval="import hashlib; h=hashlib.md5(id).hexdigest()" --batch -v 5 | grep URI

URI: http://www.example.com:80/?id=1&h=c4ca4238a0b923820dcc509a6f75849b
URI: http://www.example.com:80/?id=1&h=c4ca4238a0b923820dcc509a6f75849b
URI: http://www.example.com:80/?id=9061&h=4d7e0d72898ae7ea3593eb5ebf20c744
URI: http://www.example.com:80/?id=1%2C.%2C%27%22.%2C%28.%29&h=620460a56536e2d32fb2f4842ad5a08d
URI: http://www.example.com:80/?id=1%27MyipGP%3C%27%22%3EibjjSu&h=db7c815825b14d67aaa32da09b8b2d42
URI: http://www.example.com:80/?id=1%29%20AND%209978%socks4://177.39.187.70:33283ssocks4://177.39.187.70:332833D1232%20AND%20%284955%3D4955&h=02312acd4ebe69e2528382dfff7fc5cc

IP地址隐藏

如果我们想隐藏我们的 IP 地址,或者如果某个 Web 应用程序具有将我们当前 IP 地址列入黑名单的保护机制,我们可以尝试使用代理或匿名网络 Tor。可以使用选项 --proxy 设置代理(例如 --proxy="socks4://177.39.187.70:33283"),我们应该在其中添加一个工作代理。

除此之外,如果我们有一个代理列表,我们可以使用选项 --proxy-file 将它们提供给 SQLMap。这样,SQLMap 将按顺序遍历列表,如果出现任何问题(例如,将 IP 地址列入黑名单),它只会从列表中的当前跳到下一个。另一种选择是使用 Tor 网络提供易于使用的匿名化,我们的 IP 可以出现在大量 Tor 出口节点列表中的任何地方。当在本地机器上正确安装时,本地端口 9050 或 9150 应该有一个 SOCKS4 代理服务。通过使用开关 --tor,SQLMap 将自动尝试找到本地端口并适当地使用它。

如果我们想确保 Tor 被正确使用,以防止不必要的行为,我们可以使用开关 --check-tor。在这种情况下,SQLMap 将连接到 https://check.torproject.org/ 并检查预期结果的响应(即,Congratulations 出现在里面)。

WAF Bypass

每当我们运行 SQLMap 时,作为初始测试的一部分,SQLMap 会使用不存在的参数名称(例如?pfov=...)发送一个预定义的恶意负载,以测试是否存在 WAF(Web 应用程序防火墙)。在用户和目标之间有任何保护的情况下,与原始响应相比会有实质性的变化。例如,如果实施了最流行的 WAF 解决方案之一 (ModSecurity),则在此类请求之后应该有 406 - Not Acceptable 响应。

在检测到阳性的情况下,为了识别实际的保护机制,SQLMap 使用第三方库 identYwaf,其中包含 80 种不同的 WAF 解决方案的签名。如果我们想完全跳过这个启发式测试(即产生更少的噪音),我们可以使用开关 --skip-waf

用户代理黑名单绕过

如果在运行 SQLMap 时出现直接问题(例如,从一开始就出现 HTTP 错误代码 5XX),我们首先应该想到的事情之一是 SQLMap 使用的默认用户代理(例如 User-agent: sqlmap/ 1.4.9(http://sqlmap.org))。

使用开关 --random-agent 绕过这一点很简单,它使用从浏览器使用的大量值中随机选择的值更改默认用户代理。

注意:如果在运行期间检测到某种形式的保护,我们可以预料目标会出现问题,甚至其他安全机制也会出现问题。主要原因是此类防护措施的不断发展和新改进,留给攻击者的机动空间越来越小。

Tamper Scripts

最后,在 SQLMap 中实现的绕过 WAF/IPS 解决方案的最流行机制之一是所谓的“Tamper”脚本。Tamper 脚本是一种特殊的 (Python) 脚本,用于在发送到目标之前修改请求,在大多数情况下绕过某些保护。

例如,最流行的 Tamper 脚本之一是将所有出现的大于运算符 (>) 替换为 NOT BETWEEN AND #,将等于运算符 (=) 替换为 BETWEEN # AND #。这样,许多原始保护机制(主要集中在防止 XSS 攻击)很容易被绕过,至少对于 SQLi 而言是这样。

Tamper 脚本可以在 --tamper 选项(例如 --tamper=between,randomcase)中一个接一个地链接起来,它们根据预定义的优先级运行。预定义优先级以防止任何不需要的行为,因为某些脚本通过修改其 SQL 语法(例如 ifnull2ifisnull)来修改有效负载。相反,一些 Tamper 脚本不关心内部内容(例如 appendnullbyte)。

Tamper 脚本可以修改请求的任何部分,但大多数会更改负载内容。最著名的篡改脚本如下:

Tamper-Script Description
0eunion 用 e0UNION 替换 UNION 的实例
base64encode Base64 编码给定负载中的所有字符
between 将大于运算符 (>) 替换为 NOT BETWEEN AND #,将等于运算符 (=) 替换为 BETWEEN # AND #
commalesslimit LIMIT N OFFSET M 对应物替换 (MySQL) LIMIT M, N 实例
equaltolike 将所有出现的运算符等于 (=) 替换为 LIKE 对应项
halfversionedmorekeywords 在每个关键字前添加 (MySQL) 版本注释
modsecurityversioned 包含带有 (MySQL) 版本注释的完整查询
modsecurityzeroversioned 包含带有 (MySQL) 零版本注释的完整查询
percentage 在每个字符前添加百分号 (%)(例如 SELECT -> %S%E%L%E%C%T)
plus2concat 用 (MsSQL) 函数 CONCAT() 对应项替换加号运算符 (+)
randomcase 用随机大小写值替换每个关键字字符(例如 SELECT -> SEleCt)
space2comment 将空格字符 ( ) 替换为注释 `/
space2dash 将空格字符 ( ) 替换为破折号注释 (--),后跟随机字符串和新行 (\n)
space2hash 将空格字符 ( ) 的 (MySQL) 实例替换为井号字符 (#),后跟随机字符串和换行符 (\n)
space2mssqlblank 用一组有效的备用字符中的随机空白字符替换 (MsSQL) 空格字符 ( ) 的实例
symboliclogical 将 AND 和 OR 逻辑运算符替换为其符号对应项(&&||
versionedkeywords 用 (MySQL) 版本注释将每个非函数关键字括起来
versionedmorekeywords 用 (MySQL) 版本注释括起每个关键字

要获得已实施的篡改脚本的完整列表以及上面的描述,可以使用开关 --list-tampers。我们还可以为任何自定义类型的攻击开发自定义篡改脚本,例如二阶 SQLi。

其他 Bypasses

在其他保护 Bypass 机制中,还有两个值得一提。第一个是 Chunked 传输编码,使用开关 --chunked 打开,它将 POST 请求的主体拆分为所谓的“chunks(块)”。列入黑名单的 SQL 关键字在块之间拆分,这样包含它们的请求可以在不被注意的情况下通过。

其他绕过机制是 HTTP 参数污染 (HPP,HTTP parameter pollution ),其中有效负载以与 --chunked 在不同的相同参数命名值之间的类似方式拆分(例如 ?id=1&id=UNION&id=SELECT&id=username,password&id=FROM&id =users...),如果支持它(例如 ASP),则由目标平台连接。