☰
杂记14 敏感文件泄露
2026/9/30 3:19:46 网站建设 项目流程

敏感文件泄露的核心不是"能下载到一个文件",而是拿到源码之后读懂了它。 这四关的终点都不是"下载到压缩包",而是从源码里翻出一个不设防的后门文件,访问它,Flag 就出来了。

⚠️ 本文所有测试均在授权靶场中完成,仅用于安全学习与防御研究,请勿用于未授权目标。


〇、先看通关记录

关卡难度泄露点关键动作
备份文件泄露1 级网站根目录的backup.zip猜文件名 → 下载 → 解压审计 → 访问后门
SVN 泄露(旧版)2 级.svn/entries+.svn/text-base/读文件列表 → 拉.svn-base副本 → 访问后门
SVN 泄露(新版)2 级.svn/wc.db(SQLite)下载wc.db→sqlite3查文件名 → 访问后门
Git 泄露2 级.git/(目录浏览未关)解析.git/index→ 拿文件名 → 访问后门

四关殊途同归:先用任意方式拿到"文件清单",再从清单里挑出可疑的后门文件,直接访问它。


一、什么是敏感文件泄露

1.1 定义与危害

  • 定义:服务器上本该只在内部使用的文件(源码、备份、配置、版本控制元数据)被放在了 Web 目录下且可被直接访问,攻击者顺着 URL 就能拿到。

  • 本质:不是代码写错了,而是部署时"忘了收拾"。这是它和注入类漏洞最大的区别——所以它更像"信息收集"的延伸,而不是"注入"的同类。

  • 危害:泄露源码与数据库密码 → 顺藤摸瓜找到后门、密钥、Flag → 为进一步的 RCE 铺路。

1.2 必背:常见敏感文件清单

类型文件名示例泄露什么
源码备份www.zip、web.zip、backup.zip、website.tar.gz整站源码
数据库备份db.sql、database.sql、backup.sql数据库数据
编辑器备份index.php.bak、index.php~、index.php.swp单文件源码
配置文件.env、config.php、web.config数据库密码、密钥
版本控制.git/config、.svn/entries源码 + 版本信息
系统文件/etc/passwd、/proc/self/environ系统信息
日志文件/var/log/apache2/access.log用于 LFI to RCE

💡 这一关的靶场描述是"我有一个备份我网站的好习惯"——基本等于明示:去猜备份文件名。


二、核心机制:为什么"直接访问后门"就能拿 Flag

这是这几关最容易困惑的地方:为什么下载了源码、看到那个文件名,访问一下 Flag 就出来了?

因为那个文件本身就是个后门。它的源码长这样:

<?php $flag_file = '/tmp/flag.txt'; if (file_exists($flag_file)) { $content = file_get_contents($flag_file); echo htmlspecialchars($content, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); } else { echo "flag 文件不存在"; } ?>

逐行翻译成人话:

代码在做什么
$flag_file = '/tmp/flag.txt'只认一个地址:机密文件在这
file_exists(...)先看看它在不在
file_get_contents(...)在就整个读出来
echo htmlspecialchars(...)打印到页面上

它和正常网页的区别只有一个:

正常页面(index.php)后门文件(bac123321123.php)
访问前要验证吗要(登录、鉴权、参数校验)不要
访问后做什么按业务逻辑处理二话不说读/tmp/flag.txt并输出

🔑一句话:直接访问能拿到 Flag,不是因为这个 URL 有魔法,而是因为服务器上躺着一个不设防、专门用来读 Flag 的脚本。而"知道这个文件叫什么名字",就是从泄露的源码里来的——这才是源码审计的价值:你看到的不是页面表象,而是服务器的底牌。


三、实战复盘

3.1 1 级:备份文件泄露

目标:从网站备份文件中拿到源码,找到读 Flag 的入口。

思路:靶场描述"我有一个备份我网站的好习惯",等于把方向说了——去猜备份文件名。

Payload:

http://<靶场地址>/backup.zip

成功下载到整站源码压缩包。

审计与利用:

  1. 解压backup.zip,翻源码目录。

  2. 发现一个命名很可疑的文件 ——bac123321123.php(正常业务不会这么取名)。

  3. 打开一看,正是第二章那个"读/tmp/flag.txt"的后门。

  4. 直接访问http://<靶场地址>/bac123321123.php,拿到 Flag。

小结:这关考的不是技术难度,而是信息收集的常识——备份文件名有固定字典,猜中即可。

3.2 2 级:SVN 源码泄露(旧版text-base)

信息收集:用dirb扫目录

dirb http://<靶场地址>/ /usr/share/wordlists/dirb/common.txt

扫出/.svn/entries返回 200 —— 确认存在 SVN 源码泄露。

原理:开发者用 SVN 管理代码,发布网站时忘了删掉.svn隐藏目录。而这个目录里:

  • .svn/entries:记录了所有受版本控制的文件列表。

  • .svn/text-base/<文件名>.svn-base:每个文件在版本库中的原始副本(纯源码)。

利用:

  1. 访问http://<靶场地址>/.svn/entries,拿到文件列表。

  2. 列表里有个随机命名的文件,极其可疑:

3b96e9fc-ae54-46bf-9e30-c167f825d7cf.php
  1. 拉它的源码副本确认:

http://<靶场地址>/.svn/text-base/3b96e9fc-ae54-46bf-9e30-c167f825d7cf.php.svn-base

看到的正是第二章那个后门。

  1. 既然确认是后门,直接访问原文件:

http://<靶场地址>/3b96e9fc-ae54-46bf-9e30-c167f825d7cf.php

拿到 Flag

⚠️ 易错点:三种 URL,只有两种能通
访问路径结果原因
/3b96e9fc-...php✅网站根目录下真实存在这个文件,服务器执行它
/.svn/text-base/3b96e9fc-...php❌ 404.svn/text-base/下只有.php.svn-base,没有.php
/.svn/text-base/3b96e9fc-...php.svn-base✅源码副本,服务器当静态文件返回(浏览器显示或下载)

📌要分清"执行"和"显示": 以.php结尾 → PHP 处理器执行它,输出运行结果; 以.php.svn-base结尾 → 不匹配.php的处理规则,服务器只把它当普通文件原样吐出来。 所以副本用来"看代码",原文件用来"跑代码"。

3.3 2 级:SVN 泄露进阶(新版wc.db)

这一关出题人把上一关的捷径堵了——.svn/text-base/目录被删掉。但 SVN 从 1.7 开始换了存储方式,源码依然在。

SVN 版本源码存哪怎么利用
旧版(< 1.7).svn/text-base/*.svn-base直接访问副本;或用dvcs-ripper批量还原
新版(≥ 1.7).svn/wc.db(SQLite 数据库)下载wc.db,用sqlite3查询

利用:

  1. 扫到/.svn/,发现text-base/没了,但多了一个wc.db(约 12K)。

  2. 下载下来:

curl -o /tmp/wc.db http://<靶场地址>/.svn/wc.db
  1. 用sqlite3查文件清单(NODES表是核心):

sqlite3 /tmp/wc.db "SELECT local_relpath FROM NODES WHERE kind='file';"
  1. 列表里又出现一个随机命名的可疑文件:

ef217624-b2d3-4bad-8b33-9b975db7d46a.php
  1. 直接访问它,成功返回 Flag。

NODES表关键字段:

字段说明
local_relpath文件在工作副本中的相对路径(如index.php)
kind类型:file/dir
checksum文件校验和,指向真正的源码副本
content内容字段,对普通文件通常为空(见下方提醒)

⚠️一个容易踩的坑:不少教程会写SELECT content FROM NODES WHERE ...来直接读源码。但在 SVN 1.7+ 里,普通文件的content字段基本都是NULL——真正的文件内容被单独放在.svn/pristine/<校验和前两位>/<校验和>.svn-base,通过checksum关联。 所以稳妥的做法是:先用local_relpath拿到文件名清单,再顺着checksum去读pristine/;嫌麻烦就直接上dvcs-ripper一键还原。

3.4 2 级:Git 源码泄露(.git/index)

漏洞确认:直接访问http://<靶场地址>/.git/,目录浏览是开着的,返回了标准结构:

HEAD config index objects/

确认存在 Git 源码泄露。

原理:和 SVN 一样,开发者发布时忘了删.git目录。其中:

文件 / 目录作用
.git/HEAD指向当前分支
.git/config仓库配置
.git/index核心索引,记录当前版本所有文件的路径与哈希
.git/objects/所有文件内容的压缩对象

利用:

  1. 用 VSCode 打开.git/index(二进制文件),右侧的文本解码区能看到明文文件路径。直接读出了:

index.php 3367f1809c1eb10b2e87c5544da3a097.png 3b96e9fc-ae54-46bf-9e30-c167f825d7cf.php ← 可疑
  1. 那个随机命名的.php就是后门。

  2. 直接访问它:

http://<靶场地址>/3b96e9fc-ae54-46bf-9e30-c167f825d7cf.php

拿到 Flag

另一种思路(还原整站源码):index只给文件名,要拿内容还得配objects/,用工具一把梭:

python3 GitHack.py http://<靶场地址>/.git/

💡.git/index为什么能直接看出文件名?它是二进制格式,但其中的文件路径是以明文、用\0分隔存储的——所以随便一个文本 / 十六进制编辑器,往右边一看,文件名就全露出来了,不用装任何工具。


四、SVN 与 Git:一张表和一个比喻

这两个漏洞常被统称"源码泄露双雄",核心区别在于文件内容怎么存:

维度SVNGit
核心目录.svn/.git/
关键文件.svn/entries(旧)、.svn/wc.db(新).git/index、.git/HEAD
内容存储直接存原文副本(text-base/、pristine/)存压缩对象(objects/)
拿源码难度低:访问.svn-base就能看中:要用工具(GitHack)还原对象
常见利用读entries/ 查wc.db找文件名读index找文件名,或用工具还原

一个好记的比喻:

  • SVN 像复印机:把原稿复印一份塞进你的抽屉(.svn/text-base),找到复印件内容直接就能看。

  • Git 像保险箱:把原稿锁进保险箱(.git/objects),只给你一张清单(.git/index);清单写着"文件在哪",但要把原稿掏出来得用工具。

两者本质完全一样:开发者忘了把"管理工具的抽屉"从网站目录里搬走,被攻击者翻了个底朝天。


五、工具速查

用途工具 / 命令
目录扫描(找泄露点)dirb、dirsearch、御剑
还原 SVN 源码rip-svn.pl -v -u http://<目标>/.svn/(dvcs-ripper,Kali 自带)
还原 Git 源码python3 GitHack.py http://<目标>/.git/
解析新版 SVNsqlite3 wc.db "SELECT local_relpath FROM NODES WHERE kind='file';"
手动看 Git 索引VSCode,或xxd .git/index

六、安全防御建议(运维 / 开发者视角)

这一节的答案很朴素:敏感文件泄露几乎全是部署环节的疏忽,防御重点是"上线前把不该留在 Web 目录里的东西清掉"。

  1. 发布前清理版本控制目录:.svn、.git、.hg一律删除;更稳妥的做法是用git archive/svn export导出干净副本再部署。

  2. 备份文件不放 Web 目录:备份产物放在 Web 根目录之外,或至少加鉴权;备份完及时删除。

  3. 关闭目录浏览:Nginxautoindex off;、ApacheOptions -Indexes。

  4. 在 Web 服务器层直接拒绝:拦截.svn、.git、.bak、.swp、.zip、.sql、.env等路径 / 后缀的访问。

  5. 源码与运行目录分离:Web 根目录只放对外需要的文件。

  6. 统一错误信息:不要把详细报错回显给用户,避免二次泄露路径信息。


七、总结

这一专题四关下来,真正的收获不是"会下载.zip",而是这条固定套路:

  1. 找泄露点:目录扫描 + 常识字典(backup.zip、.svn、.git……)。

  2. 拿文件名清单:text-base目录、wc.db的NODES表、.git/index,本质都是"文件清单"的三种不同载体。

  3. 审计清单:业务不会用随机 UUID 给.php命名——越不像人取的名字,越像后门。

  4. 直接访问后门:它不设防,不需要参数,访问即执行。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询