
1. 从“备份是个好习惯”这个标题说起“备份是个好习惯”这个说法放在日常运维里确实没毛病——定期备份数据库、备份站点文件、备份配置文件出了事故能快速回滚。但放到Web安全攻防的语境下这句话就变成了一句反讽开发者的备份习惯恰恰是攻击者最爱的突破口之一。这道题属于典型的Web信息泄露类题目核心考点就一个备份文件泄露。题目给了一个看似平平无奇的页面没有明显的注入点、没有上传入口、没有花哨的前端逻辑但只要你意识到“备份文件可能被放在了Web目录下”整道题就迎刃而解。我写这篇复盘的目的不是单纯给一个flag而是想把这类题背后的通用排查思路讲透。因为备份文件泄露在真实渗透测试中出现的频率极高很多企业的运维人员会把www.zip、index.php.bak、web.rar这类文件直接丢在网站根目录攻击者用几个常见的字典就能扫出来。这道题就是把这个真实场景浓缩成了一个CTF关卡。适合阅读这篇内容的人刚接触CTF Web方向的新手、对目录扫描和源码审计还不熟悉的安全爱好者、以及想系统梳理“信息收集阶段该做什么”的从业者。下面我会从题目入口分析、备份文件命名规律、源码审计、参数绕过逻辑、以及实战中容易踩的坑这几个维度把这道题彻底拆开。2. 题目入口的初步判断与信息收集方向2.1 页面表现与第一反应打开题目给定的URL页面内容通常非常简洁可能只有一行文字或者一个空白页面。这种“什么都没有”的页面恰恰是最需要警惕的。很多新手看到空白页就不知道下一步该干什么其实这时候应该立刻切换到信息收集思维。我拿到这类题目的第一反应是先看页面源代码再看HTTP响应头最后做目录扫描。这三步是固定的肌肉记忆。页面源代码里可能藏着注释、隐藏表单、JS文件路径响应头里可能暴露服务器类型、框架版本、Cookie特征目录扫描则是找那些“不该被访问到”的文件。这道题的关键线索不在页面本身而在于题目名称给出的暗示——“备份是个好习惯”。出题人已经把答案的方向写在标题里了就是在告诉你去找备份文件。2.2 常见的备份文件命名规律备份文件的命名是有套路的不是随便乱起。根据我这些年做渗透测试和CTF的经验常见的备份文件命名可以归为以下几类类型常见命名说明源码压缩包www.zip、web.zip、wwwroot.rar、backup.tar.gz整站打包备份单文件备份index.php.bak、index.php~、index.php.swp编辑器自动备份数据库备份db.sql、database.sql、backup.sql数据库导出文件配置文件备份config.php.bak、.env.bak配置类文件副本版本控制残留.git/、.svn/版本控制目录泄露这道题最可能的方向是源码压缩包或者单文件备份。因为题目没有给出任何其他线索出题人大概率是把一个备份文件放在了Web根目录下等着你去发现。提示在实际测试中目录扫描工具如dirsearch、gobuster配合一份好的字典能在几秒内发现这类文件。但在CTF中有时候需要你手动猜测文件名因为出题人可能用了非常规命名。2.3 目录扫描的实操要点如果你用工具扫描建议字典里至少包含以下条目www.zip web.zip backup.zip wwwroot.zip html.zip index.php.bak index.php~ index.php.swp .bak .zip .rar .tar.gz扫描的时候注意状态码200表示文件存在且可访问403表示存在但禁止访问301/302表示重定向。这道题里备份文件应该是可以直接下载的所以关注200的条目。我个人的习惯是先用小字典快速扫一遍找到可疑文件后再用大字典深挖。因为大字典跑起来慢先缩小范围效率更高。3. 备份文件到手后的源码审计重点3.1 下载与解压假设你已经找到了备份文件比如www.zip下载下来解压会得到网站的源码。这时候不要急着乱翻要有条理地看。我通常按照以下顺序审计入口文件index.php、index.html看整体逻辑配置文件config.php、db.php看数据库连接、密钥等功能文件根据入口文件引用的文件逐个查看工具函数functions.php、common.php看有没有危险函数这道题的源码结构应该比较简单核心逻辑就在一两个文件里。3.2 关键代码的识别在审计过程中要特别关注以下几类代码特征文件包含include、require、include_once如果参数可控就是文件包含漏洞命令执行system、exec、shell_exec、passthru参数可控就是命令执行代码执行eval、assert、preg_replace的/e修饰符SQL查询拼接式SQL语句可能存在注入反序列化unserialize配合魔术方法可能触发漏洞这道题的核心应该是一个变量覆盖或者参数绕过的逻辑。因为题目名称强调的是“备份”而备份文件泄露后源码里通常会有一个判断逻辑比如检查某个参数是否等于特定值或者检查请求来源。3.3 一个典型的源码逻辑还原根据这类题目的常见套路源码里大概率有这样一段逻辑?php include flag.php; $key $_GET[key]; if ($key backup) { echo $flag; } else { echo 备份是个好习惯; } ?或者更复杂一点涉及到MD5碰撞、弱类型比较、数组绕过等。但结合“备份”这个主题最可能的还是变量覆盖或者直接比较绕过。还有一种可能是源码里有一个extract()函数把GET或POST的参数直接提取为变量导致可以覆盖原有的变量值。比如?php $flag flag{xxxxx}; extract($_GET); if ($backup yes) { echo $flag; } ?这种情况下你只需要传?backupyes就能拿到flag。4. 参数构造与绕过的完整推演4.1 从源码到Payload的推导假设你审计源码后发现逻辑是这样的?php $file $_GET[file]; if (isset($file)) { if (strstr($file, ..) || strstr($file, flag)) { die(禁止访问); } include $file; } ?这是一个典型的文件包含题目但加了过滤。过滤了..和flag。这时候你需要绕过过滤。绕过方式有很多使用绝对路径/var/www/html/flag.php使用编码绕过%2e%2e代替..使用PHP伪协议php://filter/convert.base64-encode/resourceflag.php但注意如果过滤了flag这个字符串伪协议里的flag.php也会被拦截。这时候可以用php://filter/convert.base64-encode/resourcefla.g.php这种方式拼接或者用大小写绕过如果过滤不严格。4.2 弱类型比较的经典绕过如果源码里是比较逻辑比如?php $password $_GET[password]; if ($password admin) { echo $flag; } ?这种弱类型比较可以用?password0或者?passwordadmin之外的任何在PHP弱类型比较下等于admin的值。但更常见的是MD5比较?php if ($_GET[a] ! $_GET[b] md5($_GET[a]) md5($_GET[b])) { echo $flag; } ?这时候可以用数组绕过?a[]1b[]2因为md5()函数不能处理数组会返回null而null null为真。4.3 本题最可能的Payload形式结合“备份”这个主题我推测本题的Payload可能是以下几种之一直接访问备份文件http://target/www.zip下载后审计源码找到flag变量覆盖?backup1或?keybackup文件包含?fileflag.php配合某种绕过如果是第一种那flag可能直接写在源码的注释里或者在一个被包含的flag.php文件里。如果是第二种那就是一个简单的参数判断。如果是第三种就需要结合过滤规则来构造。注意在实际操作中不要一上来就尝试复杂的Payload。先把简单的情况试一遍直接访问常见备份文件名、传最简单的参数、看页面回显变化。很多时候答案比你想的简单。5. 实战中容易踩的坑与排查经验5.1 备份文件找不到怎么办这是新手最常遇到的问题知道要找备份文件但扫不出来。原因可能有几个字典不够全你用的字典里没有出题人设定的文件名。这时候需要根据题目名称、页面特征去猜。比如题目叫“备份是个好习惯”那文件名可能是backup.zip、www.zip、web.rar。路径不对备份文件可能不在根目录而在某个子目录下。比如/admin/backup.zip、/data/www.zip。需要特定请求头有些题目会检查Referer或User-Agent不满足条件就返回404。文件扩展名被改比如www.zip.bak、www_zip.txt。我的经验是先用常见字典扫一遍如果没有结果就根据题目名称手动构造几个候选文件名逐个尝试。同时注意观察响应状态码和响应长度有时候文件存在但返回的是302跳转。5.2 源码审计时容易忽略的细节拿到源码后很多人只看主逻辑忽略了注释和次要文件。我踩过的坑包括flag藏在注释里!-- flag{xxxxx} --这种最气人但也最常见flag在图片的EXIF里备份包里有一张图片flag写在EXIF信息中flag在数据库导出文件里backup.sql里有一条insert语句包含flagflag需要二次解码源码里看到的flag是base64编码的需要解码所以审计的时候不要只盯着PHP代码HTML注释、SQL文件、图片、文本文件都要看一遍。5.3 参数传递方式的坑有时候源码里用的是$_POST你却一直在用GET传参或者源码里用的是$_REQUEST但你只试了GET没试POST。这些细节会导致你明明构造对了Payload却拿不到flag。还有一种情况是参数名大小写敏感。PHP的变量名是区分大小写的$Key和$key是两个不同的变量。如果源码里写的是$Key你传key是没用的。另外注意参数传递的编码问题。比如你传?fileflag.php但服务器可能对URL进行了二次解码导致你的Payload被改变。这时候需要用%00截断或者双重编码。6. 从这道题延伸出的通用排查方法论6.1 信息收集阶段的检查清单这道题虽然简单但它代表了一类非常常见的漏洞。我把这类题目的排查流程整理成一个清单以后遇到类似场景可以直接套用查看页面源代码找注释、隐藏字段、JS文件路径查看HTTP响应头找Server、X-Powered-By、Set-Cookie等查看robots.txt可能泄露敏感路径目录扫描用常见字典扫备份文件、敏感目录尝试常见备份文件名www.zip、backup.zip、index.php.bak等检查版本控制残留.git/、.svn/检查编辑器临时文件.swp、~、.bak这个清单不仅适用于CTF也适用于真实的渗透测试。很多企业的网站就是因为运维人员把备份文件放在了Web目录下导致源码泄露进而被攻击者发现更多漏洞。6.2 备份文件泄露的真实危害在真实环境中备份文件泄露的危害远不止拿到一个flag。攻击者可以通过源码审计发现数据库连接信息直接连上数据库拖走所有数据API密钥调用内部接口获取敏感信息硬编码的后门开发者留下的调试入口框架版本根据版本号查找已知漏洞业务逻辑漏洞比如支付逻辑、权限校验逻辑所以“备份是个好习惯”这句话对开发者来说是提醒对攻击者来说是机会。正确的做法是备份文件不要放在Web目录下如果必须放要加访问控制并且定期清理。6.3 防御视角的思考从防御的角度看这道题给我们的启示是Web目录下不要放任何备份文件包括压缩包、SQL文件、编辑器临时文件配置Web服务器禁止访问特定扩展名比如在Nginx里配置location ~* \.(zip|rar|bak|sql|swp)$ { deny all; }定期做安全扫描用工具扫描自己的站点看看有没有意外的文件暴露版本控制目录要正确配置.git目录不能被外部访问这些措施成本很低但能挡住大部分自动化扫描工具。安全这件事很多时候就是比谁少犯低级错误。7. 我在这道题上花时间最多的环节说实话这道题的技术难度不高但我第一次做的时候还是卡了一会儿。卡住的点不是技术问题而是思维定势。我一开始一直在找注入点、找上传点完全忽略了题目名称给出的提示。后来是队友提醒了一句“备份是个好习惯”我才反应过来应该去找备份文件。这个经历让我意识到CTF题目里的每一句话都可能是线索尤其是题目名称。出题人不会无缘无故起一个名字名字本身就是提示。后来我做题的习惯就变了先读三遍题目名称把每个词都拆开想一遍再开始动手。另一个花时间的点是字典的选择。我一开始用的字典里没有www.zip这个条目扫了半天没结果。后来换了一个专门针对备份文件的字典才扫出来。所以工具和字典的准备很重要平时要积累一份好用的字典关键时刻能省很多时间。最后拿到flag的时候其实flag本身很简单但整个排查过程让我对“信息收集”这个阶段有了更深的理解。很多新手觉得信息收集枯燥不如直接上Payload来得爽但实际上信息收集决定了你后续攻击的上限。收集得越充分攻击路径越清晰。8. 给刚入门的朋友几点实在建议如果你刚开始接触CTF Web方向这道题是一个很好的练手素材。我的建议是第一不要急着看Writeup。先自己动手试哪怕试不出来也要把尝试的过程记录下来。你试过的每一个文件名、每一个参数都是经验积累。第二建立自己的字典库。把每次遇到的新文件名、新路径记下来慢慢你的字典就会越来越全。我现在的字典里有一千多条备份文件相关的条目都是这些年一点点攒的。第三学会看源码。不要只依赖工具工具扫不出来的东西往往需要你手动审计源码才能发现。PHP的基本语法、常见危险函数、弱类型比较规则这些都要熟悉。第四多总结套路。CTF题目千变万化但底层套路是有限的。备份文件泄露、文件包含、SQL注入、反序列化、SSRF把这些核心套路吃透遇到新题就能快速定位方向。这道题虽然简单但它背后的“备份文件泄露”这个知识点在真实场景中非常实用。希望这篇复盘能帮你把这类题彻底搞明白下次遇到类似题目能秒出思路。