SQLmap
SQLmap 是一款功能强大的工具,它可以自动化地探测和利用 SQL 注入漏洞。与手动测试相比,它极大地节省了时间和精力。它支持多种数据库和注入技术,使其在各种场景下都非常通用且有效。 此外,SQLmap 还可以提取数据、操作数据库,甚至执行系统命令,为渗透测试人员和安全分析师提供了一套强大的功能。 “重复造轮子”并非明智之举,因为 SQLmap 已经过专家的严格开发、测试和改进。使用这种可靠且有社区支持的工具,意味着您可以从成熟的最佳实践中受益,并避免漏掉漏洞或在自定义代码中引入错误的风险。 但是,您应始终了解 SQLmap 的工作原理,并能在必要时进行手动复现。
摘要 (Summary)
- SQLmap 基础参数 (#basic-arguments-for-sqlmap)
- 加载请求文件 (#load-a-request-file)
- 自定义注入点 (#custom-injection-point)
- 二阶注入 (#second-order-injection)
- 获取 Shell (#getting-a-shell)
- 爬虫与自动利用 (#crawl-and-auto-exploit)
- SQLmap 代理配置 (#proxy-configuration-for-sqlmap)
- 注入混淆 (Injection Tampering)
- 减少请求数量 (#reduce-requests-number)
- 不依赖 SQL 注入使用 SQLmap (#sqlmap-without-sql-injection)
- 参考资料 (#references)
SQLmap 基础参数 (Basic Arguments For SQLmap)
sqlmap --url="<url>" -p username --user-agent=SQLMAP --random-agent --threads=10 --risk=3 --level=5 --eta --dbms=MySQL --os=Linux --banner --is-dba --users --passwords --current-user --dbs
加载请求文件 (Load A Request File)
SQLmap 中的请求文件是保存好的 HTTP 请求,SQLmap 会读取并使用它来进行 SQL 注入测试。通过该文件,您可以提供完整且自定义的 HTTP 请求,从而使 SQLmap 能够针对更复杂的应用程序进行测试。
自定义注入点 (Custom Injection Point)
自定义注入点允许您精确指定 SQLmap 应在请求的哪个位置以及如何尝试注入载荷。这在处理 SQLmap 可能无法自动探测到的复杂或非标准注入场景时非常有用。
通过使用通配符 '*' 定义自定义注入点,您可以更精细地控制测试过程,确保 SQLmap 针对请求中您怀疑存在漏洞的特定部分进行攻击。
sqlmap -u "http://example.com" --data "username=admin&password=pass" --headers="x-forwarded-for:127.0.0.1*"
二阶注入 (Second Order Injection)
二阶 SQL 注入发生在注入到应用程序中的恶意 SQL 代码没有立即执行,而是存储在数据库中,稍后在另一个 SQL 查询中使用时。
sqlmap -r /tmp/r.txt --dbms MySQL --second-order "http://targetapp/wishlist" -v 3
sqlmap -r 1.txt -dbms MySQL -second-order "http://<IP/域名>/joomla/administrator/index.php" -D "joomla" -dbs
获取 Shell (Getting A Shell)
-
SQL Shell:
-
OS Shell:
-
Meterpreter:
-
SSH Shell:
爬虫与自动利用 (Crawl And Auto-Exploit)
此方法不建议用于正式的渗透测试,仅应在受控环境或挑战中使用。它会爬取整个网站并自动提交表单,这可能导致向敏感功能(如“删除”或“销毁”端点)发送意外请求。
sqlmap -u "http://example.com/" --crawl=1 --random-agent --batch --forms --threads=5 --level=5 --risk=3
--batch= 非交互模式。通常 Sqlmap 会向您提问,使用此参数将接受默认答案。--crawl= 爬取网站的深度。--forms= 解析并测试表单。
SQLmap 代理配置 (Proxy Configuration For SQLmap)
若要带代理运行 SQLmap,可以使用 --proxy 选项后跟代理 URL。SQLmap 支持多种类型的代理,如 HTTP、HTTPS、SOCKS4 和 SOCKS5。
sqlmap -u "http://www.target.com" --proxy="http://127.0.0.1:8080"
sqlmap -u "http://www.target.com/page.php?id=1" --proxy="http://127.0.0.1:8080" --proxy-cred="user:pass"
-
HTTP 代理:
-
SOCKS 代理:
-
SOCKS5 代理:
注入混淆 (Injection Tampering)
在 SQLmap 中,混淆(Tampering)可以帮助您以特定方式调整注入内容,以绕过 Web 应用程序防火墙 (WAF) 或自定义的过滤机制。SQLmap 提供了多种选项和技术来对 SQL 注入载荷进行混淆。
前缀与后缀 (Suffix And Prefix)
--suffix 和 --prefix 选项允许您指定应附加到 SQLMap 生成载荷末尾或开头的附加字符串。当目标应用程序需要特定的格式,或者当您需要绕过某些过滤器或保护措施时,这些选项非常有用。
--suffix=SUFFIX:在引擎生成的每个载荷末尾附加指定的字符串。--prefix=PREFIX:在引擎生成的每个载荷开头添加指定的字符串。
默认混淆脚本 (Default Tamper Scripts)
混淆脚本(Tamper Script)是一种修改 SQL 注入载荷以逃避 WAF 或其他安全机制检测的脚本。SQLmap 自带了多种预设的混淆脚本,可用于自动调整载荷。
下表列出了一些常用的混淆脚本:
| 脚本名 (Tamper) | 描述 |
|---|---|
| 0x2char.py | 将每个(MySQL)0xHEX 编码字符串替换为等效的 CONCAT(CHAR(),…) 形式 |
| apostrophemask.py | 将单引号字符替换为 UTF-8 全角形式 |
| apostrophenullencode.py | 将单引号字符替换为非法的双重 Unicode 形式 |
| appendnullbyte.py | 在载荷末尾附加编码后的 NULL 字节字符 |
| base64encode.py | 对给定载荷中的所有字符进行 Base64 编码 |
| between.py | 将大于号运算符 ('>') 替换为 'NOT BETWEEN 0 AND #' |
| bluecoat.py | 在 SQL 语句后将空格字符替换为有效的随机空白字符,随后将 = 运算符替换为 LIKE 运算符 |
| chardoubleencode.py | 对给定载荷中的所有字符进行双重 URL 编码(不处理已编码内容) |
| charencode.py | 对给定载荷中的所有字符进行 URL 编码(不处理已编码内容)(例如 SELECT -> %53%45%4C%45%43%54) |
| charunicodeencode.py | 对给定载荷中的所有字符进行 Unicode URL 编码(例如 SELECT -> %u0053%u0045%u004C%u0045%u0043%u0054) |
| charunicodeescape.py | 对给定载荷中未编码的字符进行 Unicode 转义(例如 SELECT -> \u0053\u0045\u004C\u0045\u0043\u0054) |
| commalesslimit.py | 将 'LIMIT M, N' 形式替换为 'LIMIT N OFFSET M' |
| commalessmid.py | 将 'MID(A, B, C)' 形式替换为 'MID(A FROM B FOR C)' |
| commentbeforeparentheses.py | 在括号前添加(内联)注释(例如 ( -> /**/() |
| concat2concatws.py | 将 'CONCAT(A, B)' 形式替换为 'CONCAT_WS(MID(CHAR(0), 0, 0), A, B)' |
| equaltolike.py | 将所有出现的等于号运算符 ('=') 替换为 'LIKE' 运算符 |
| escapequotes.py | 对引号 (' 和 ") 进行斜杠转义 |
| greatest.py | 将大于号运算符 ('>') 替换为 'GREATEST' 等效项 |
| halfversionedmorekeywords.py | 在每个关键字前添加带有版本的 MySQL 注释 |
| htmlencode.py | 对所有非字母数字字符进行 HTML 编码(使用代码点)(例如 ' -> ') |
| ifnull2casewhenisnull.py | 将 'IFNULL(A, B)' 形式替换为 'CASE WHEN ISNULL(A) THEN (B) ELSE (A) END' |
| ifnull2ifisnull.py | 将 'IFNULL(A, B)' 形式替换为 'IF(ISNULL(A), B, A)' |
| informationschemacomment.py | 在所有出现的(MySQL)"information_schema" 标识符末尾添加内联注释 (/**/) |
| least.py | 将大于号运算符 ('>') 替换为 'LEAST' 等效项 |
| lowercase.py | 将每个关键字字符替换为小写值(例如 SELECT -> select) |
| modsecurityversioned.py | 用版本化注释包裹完整查询 |
| modsecurityzeroversioned.py | 用零版本化注释包裹完整查询 |
| multiplespaces.py | 在 SQL 关键字周围添加多个空格 |
| nonrecursivereplacement.py | 替换预定义的 SQL 关键字,使其适用于会被简单的 .replace("SELECT", "") 过滤的场景 |
| overlongutf8.py | 将给定载荷中的所有字符转换为超长 UTF-8 编码 |
| overlongutf8more.py | 将给定载荷中的所有字符转换为更复杂的超长 UTF-8 编码 |
| percentage.py | 在每个字符前添加百分号 ('%') |
| plus2concat.py | 将加号运算符 ('+') 替换为 (MsSQL) 函数 CONCAT() 等效项 |
| plus2fnconcat.py | 将加号运算符 ('+') 替换为 (MsSQL) ODBC 函数 {fn CONCAT()} 等效项 |
| randomcase.py | 将每个关键字字符替换为随机大小写值 |
| randomcomments.py | 为 SQL 关键字添加随机注释 |
| securesphere.py | 附加特殊构造的字符串 |
| sp_password.py | 在载荷末尾附加 'sp_password',以便从 DBMS 日志中自动混淆 |
| space2comment.py | 将空格字符 (' ') 替换为注释 |
| space2dash.py | 将空格字符 (' ') 替换为短横线注释 ('--'),后跟随机字符串和换行符 ('\n') |
| space2hash.py | 将空格字符 (' ') 替换为井号 ('#'),后跟随机字符串和换行符 ('\n') |
| space2morehash.py | 与 space2hash 类似,但用于更多特定场景 |
| space2mssqlblank.py | 将空格字符 (' ') 替换为有效备选集中的随机空白字符 |
| space2mssqlhash.py | 将空格字符 (' ') 替换为井号 ('#') 和换行符 ('\n') |
| space2mysqlblank.py | 将空格字符 (' ') 替换为 MySQL 有效备选集中的随机空白字符 |
| space2mysqldash.py | 将空格字符 (' ') 替换为短横线注释 ('--') 和换行符 ('\n') |
| space2plus.py | 将空格字符 (' ') 替换为加号 ('+') |
| space2randomblank.py | 将空格字符 (' ') 替换为随机空白字符 |
| symboliclogical.py | 将 AND 和 OR 逻辑运算符替换为符号形式 (&& 和 ||) |
| unionalltounion.py | 将 UNION ALL SELECT 替换为 UNION SELECT |
| unmagicquotes.py | 将引号字符 (') 替换为多字节组合 %bf%27,并在末尾添加通用注释(使其生效) |
| uppercase.py | 将每个关键字字符替换为大写。 |
| varnish.py | 添加 HTTP 标头 'X-originating-IP' |
| versionedkeywords.py | 为每个非函数关键字加版本化 MySQL 注释 |
| versionedmorekeywords.py | 为每个关键字都加上版本化 MySQL 注释 |
| xforwardedfor.py | 添加伪造的 HTTP 标头 'X-Forwarded-For' |
自定义混淆脚本 (Custom Tamper Scripts)
编写自定义混淆脚本时,请注意以下关键点。脚本架构包含这些强制性的变量和函数:
__priority__:定义脚本的应用顺序,设置其在混淆流水线中的优先级。普通优先级为 0,最高为 100。dependencies():在使用脚本前被调用,用于检查依赖关系。tamper(payload):修改载荷的核心函数。
以下是一个将 'LIMIT M, N' 替换为等效 'LIMIT N OFFSET M' 的脚本示例:
import os
import re
from lib.core.common import singleTimeWarnMessage
from lib.core.enums import DBMS
from lib.core.enums import PRIORITY
__priority__ = PRIORITY.HIGH
def dependencies():
singleTimeWarnMessage("tamper 脚本 '%s' 仅适用于针对 %s 的运行" % (os.path.basename(__file__).split(".")[0], DBMS.MYSQL))
def tamper(payload, **kwargs):
retVal = payload
match = re.search(r"(?i)LIMIT\s*(\d+),\s*(\d+)", payload or "")
if match:
retVal = retVal.replace(match.group(0), "LIMIT %s OFFSET %s" % (match.group(2), match.group(1)))
return retVal
- 将其保存为:
mytamper.py -
放置在 SQLmap 的
tamper/目录下,通常位置为: -
在 SQLmap 中使用:
自定义 SQL 载荷 (Custom SQL Payload)
SQLmap 中的 --sql-query 选项用于在确认注入并获取必要访问权限后,直接在有漏洞的数据库上运行自定义 SQL 查询。
执行 Python 代码 (Evaluate Python Code)
--eval 选项允许您使用 Python 定义或修改请求参数。求值后的变量可用于 URL、标头、Cookie 等。
在以下场景中特别有用:
- 动态参数:当参数需要随机或顺序生成时。
- 令牌生成:处处理 CSRF 令牌或动态身份验证标头。
- 自定义逻辑:例如编码、加密、时间戳等。
sqlmap -u "http://example.com/vulnerable.php?id=1" --eval="import random; id=random.randint(1,10)"
sqlmap -u "http://example.com/vulnerable.php?id=1" --eval="import hashlib;id2=hashlib.md5(id).hexdigest()"
预处理与后处理脚本 (Preprocess And Postprocess Scripts)
sqlmap -u 'http://example.com/vulnerable.php?id=1' --preprocess=preprocess.py --postprocess=postprocess.py
预处理脚本 (Preprocessing Script - preprocess.py)
预处理脚本用于在请求发送到目标应用程序之前修改请求数据。这对于编码参数、添加标头或其他请求修改非常有用。
preprocess.py 示例:
后处理脚本 (Postprocessing Script - postprocess.py)
后处理脚本用于在从目标应用程序接收到响应后修改响应数据。这对于解码响应、提取特定数据或其他响应修改非常有用。
减少请求数量 (Reduce Requests Number)
--test-filter 参数在您只想关注特定类型的 SQL 注入技术或载荷时非常有用。您可以限制其仅测试符合特定模式的载荷,而不是测试 SQLMap 拥有的全部载荷,这在处理大型或响应慢的 Web 应用程序时更有效率。
sqlmap -u "https://www.target.com/page.php?category=demo" -p category --test-filter="Generic UNION query (NULL)"
sqlmap -u "https://www.target.com/page.php?category=demo" --test-filter="boolean"
默认情况下,SQLmap 以 level 1 和 risk 1 运行,生成请求较少。在没有明确目的的情况下增加这些值可能会导致产生大量耗时且不必要的测试。
使用 --technique 选项指定要测试的 SQL 注入技术类型,而不是测试所有可能的技术。
不依赖 SQL 注入使用 SQLmap (SQLmap Without SQL Injection)
即使不利用 SQL 注入漏洞,SQLmap 在各种场景下仍然很有用,特别是在安全评估、数据库管理和应用程序测试中。
您可以使用 SQLmap 通过端口而不是 URL 访问数据库。