news 2026/11/4 11:14:47

利用phpinfo与临时文件竞态:突破伪协议限制的PHP文件包含漏洞利用

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
利用phpinfo与临时文件竞态:突破伪协议限制的PHP文件包含漏洞利用

1. 从"一眼洞穿"到"无从下手":文件包含漏洞的另一面

说起PHP文件包含漏洞,很多人的第一反应是“老生常谈”——include $_GET['file'];,然后拼路径、读源码、搞个伪协议直接RCE,一套连招行云流水。诚然,在CTF赛题和靶场里,php://filter读源码、data://执行命令、php://input写马,这几招翻来覆去地用,几乎成了肌肉记忆。

但这只是文件包含漏洞最“温柔”的一面。真实环境里,程序员通常不会把file参数直接裸奔在代码里。更多的场景是:文件包含点被层层校验包裹,伪协议被禁用,路径被拼接前缀或后缀,allow_url_include设为Off,你手里拿着一个包含点却无从下手。这时候,很多人才意识到,自己此前对文件包含漏洞的理解,其实只覆盖了最容易的那部分。

有一种利用手法,恰恰能穿透这些限制,但它既不依赖伪协议,也不依赖路径穿越,而是另辟蹊径——利用phpinfo()页面与PHP临时文件机制的联动,完成一次“无中生有”的文件包含。这就是本文要聊的:利用phpinfo()的PHP文件包含漏洞利用。

我第一次接触这个思路时,第一反应是“这也太偏门了”。但把整个原理和利用链吃透之后,不得不承认,这是理解PHP文件上传临时文件生命周期、race condition(竞态条件)利用和LFI(本地文件包含)组合拳的一个绝佳切入点。即便你的目标是CTF拿分,这个姿势也能让你在遇到“伪协议全禁 + 仅本地包含 + 无上传点”的题目时,多一条活路。

这篇文章不讲虚的,直接拆解原理、梳理利用链、给出可落地的操作步骤,最后聊聊我在实际调试中踩过的坑和排查经验。内容偏技术向,但我会尽量把每一步背后的“为什么”讲清楚,让新手能跟着走,有经验的老手也能获得一些细节层面的参考。

2. 为什么常规思路会失效

在进入phpinfo()利用法之前,有必要先把“常规思路为什么会失效”这件事盘清楚。只有理解了限制条件,才能明白这个偏门姿势的价值。

2.1 伪协议被“锁死”的常见姿势

先问一个问题:一个存在文件包含漏洞的站点,什么情况下会让你连php://filter都用不了?

最典型的是PHP配置层面的限制:

  • allow_url_include = Off:这是PHP 5.2之后的默认配置。它会让http://、ftp://这类远程文件包含直接失效。注意,php://不归它管,但data://会受到直接影响。
  • allow_url_fopen = Off:有些环境会连这个一起关掉,进一步压缩攻击面。
  • 同时,不少框架或CMS会在代码层面对包含参数做校验。比如强制拼接.php后缀、限制只能包含指定目录下的文件、过滤../和绝对路径等。伪协议在这种场景下往往直接被代码逻辑拦掉。

php://filter能不能用,取决于allow_url_fopen。data://能不能用,取决于allow_url_include。一旦这两个开关都被关掉,常规伪协议体系基本就废了一大半。你手里剩下的选择只有:

  • 纯本地文件包含绝对路径 + 路径穿越——但如果代码拼接了路径前缀和固定后缀,路径穿越也会变得很尴尬。
  • /proc/self/environ、/proc/self/fd这类Linux下的特殊文件包含——这属于另一个经典思路,下文会简单对比。

2.2 没有“上传点”意味着什么

在伪协议被禁的情况下,最常见的“曲线救国”思路是:找一个可控内容的本地文件,把它包含进来,让其中的PHP代码被执行。这个可控文件通常来自:

  • 日志文件(Apache access.log、error.log),利用User-Agent写入恶意代码
  • /proc/self/environ,利用User-Agent或Referer写入
  • 临时文件,包括上传的临时文件和Session文件
  • /tmp目录下其他可预测路径的缓存文件

问题来了——如果目标站点的上传功能需要登录后才能使用,或者压根就没有上传接口,你怎么获得一个可控的本地文件?

日志注入是个办法,但前提是你能访问到日志文件的绝对路径,且日志文件对Web进程可读。/proc/self/environ依赖进程环境变量中有可控内容,且environ文件可读。这两个方案在真实环境里层出不穷,但都有各自的运气成分。

而phpinfo()利用法,本质上就是“无中生有”地制造一个可控临时文件。只要你找到了一个存在文件包含漏洞、同时能访问到phpinfo()页面的目标,就有机会在没有上传接口的情况下完成利用。

2.3 phpinfo()页面为什么会成为突破口

很多人可能压根没想过,一个只用于展示PHP配置信息的页面,会和文件包含漏洞产生化学反应。

关键在于PHP处理multipart/form-dataPOST请求时的临时文件机制。一次文件上传请求,PHP会先在upload_tmp_dir(默认是系统临时目录,如/tmp)下生成一个临时文件,存放上传内容,等请求处理完毕后再删除。这意味着:只要你能向目标发送一个包含文件部分的POST请求,目标服务器上就会短暂地出现一个你完全可控内容的临时文件。

phpinfo()页面的价值在于,它会忠实地展示当前请求的所有上下文数据,包括$_FILES相关信息。更关键的是,通过phpinfo()页面可以看到upload_tmp_dir、session.save_path等关键路径配置,为后续利用提供准确的路径参考。

而将phpinfo()和文件包含结合起来,思路就清晰了:

  1. 向phpinfo()页面发送一个包含恶意PHP代码的文件上传POST请求。
  2. PHP会在/tmp下生成一个临时文件,文件名形如php*.tmp。
  3. 在临时文件被删除之前,通过文件包含漏洞快速包含这个临时文件。
  4. 临时文件中的PHP代码被执行,实现RCE。

这整个链条的关键在于“快”——因为临时文件的生命周期极短,请求结束即被删除。这就是典型的竞态条件利用。

所以,phpinfo()页面在这里承担了两个角色:一是提供临时文件路径和配置信息,二是作为“靶子”接收上传请求、触发临时文件生成。这个页面本身不需要有任何漏洞,它就是利用链里的一环。

3. 利用链的完整拆解

理论说完了,下面进入正题。我会把这个利用链拆成几个环节,逐步讲清楚每一步在做什么、为什么这么做。

3.1 上游基础:LFI触发点和phpinfo()页面的确立

这个利用方式的前提条件有两个:存在文件包含漏洞的LFI点,以及可访问的phpinfo()页面。这两个页面可以位于同一主机,甚至同一Web应用下。

实际的LFI触发点可能是:

<?php // 假设这是某个存在漏洞的页面 $file = $_GET['file']; include($file); ?>

只要$file没有经过严格过滤、没有拼接固定后缀、且include可用,这个点就能配合进行包含。

phpinfo()页面则常见于:

  • 站点根目录下的phpinfo.php、info.php,这类文件在开发阶段遗留、上线后未删除的情况非常普遍。
  • 某些管理后台自带的“PHP信息”展示页面。
  • 安装向导或调试模式下的配置查看页面。

用我自己的话说:当你看到一个站点存在LFI点但又无从下手时,先去目录扫描里翻一翻有没有phpinfo相关文件,哪怕只是猜测路径,也值得一试。这个页面本身信息量巨大,而且它可能是你唯一能触发的“文件上传效果触发器”。

3.2 机制中枢:PHP临时文件的生命周期

要精准地利用这个临时文件,必须搞清楚它的生命周期。我们来捋一遍。

当客户端发出一个multipart/form-dataPOST请求时,PHP内部的执行流程大致是这样的:

  1. PHP解析multipart/form-data请求头,识别出文件字段。
  2. 在upload_tmp_dir指定的目录(默认通常是/tmp,可通过sys_get_temp_dir()确认)下,生成一个临时文件,文件名格式一般是php加上一串随机字符,例如php4B9C.tmp。
  3. 把上传的文件内容完整写入这个临时文件。
  4. 执行目标脚本(比如phpinfo())。
  5. 请求结束,临时文件被立即删除。

整个过程可能只有几十毫秒。在临时文件存在的那一瞬,任何能读取/tmp/phpXXXX.tmp的程序都有机会读到它的内容。LFI点就在此刻派上用场。

这里有个细节值得注意:临时文件的文件名是随机生成的,不可预测。所以利用链必须想办法“捕捉”这个文件名。而phpinfo()页面恰好会输出$_FILES的信息,其中就包括临时文件的路径。这也就回答了标题里那个疑问——“利用phpinfo()”到底在利用它的什么?利用的是它输出上下文信息的能力。

3.3 竞态条件:从“不存在”到“被包含”的时间窗口

竞态条件这个术语听起来高深,其实本质就是“抢时间”。服务端先创建临时文件,再删除临时文件,我们需要在这个存在窗口内完成包含操作。

但有个问题:LFI的请求和上传的POST请求是两个独立的HTTP请求。从你发出上传请求,到临时文件被删除,中间的时间窗口极短。怎么在这极短的时间里完成一次LFI请求?

答案是:并发。

利用脚本做的事,本质上就是:

  1. 不断向phpinfo()页面发送“上传恶意代码”的POST请求。
  2. 同时用另一个线程池,不断向LFI点发送“包含临时文件”的GET请求。
  3. 只要有一次“上传后、删除前”的瞬间被LFI请求逮住,恶意代码就被包含执行了。

因为临时文件的文件名是随机的,LFI请求不可能指定一个确定的文件名。所以要靠“碰运气”,靠大量的并发请求来提高命中概率。文件名虽然随机,但总归是/tmp/php??????这种格式,LFI点如果允许我们控制包含路径,直接包含/tmp/php??????这样的通配符是不行的——include不支持通配符。所以,我们必须在每次LFI请求中猜测或尝试一个文件名。

这就是大多数phpinfo()利用脚本要维护一个大循环的原因:每个上传请求,都猜测性地向LFI点发起大量请求,尝试多个可能的临时文件名。文件名的随机部分通常是字母数字组合,实际利用中会把猜测范围动态调整,提高命中率。

有些文章用“爆破”来描述这个过程,其实不太准确。更精确的说法是:利用PHP临时文件命名的弱随机性和大量并发请求,去覆盖一个短暂的时间窗口。这本质上是一个成功率问题,而不是一个确定性问题。

3.4 实际利用脚本的核心逻辑

先声明:我不会在这里直接给出一个完整可用的武器化脚本,因为这类代码在网络上已经大量存在,而且直接贴完整的利用代码对技术学习并没什么实际帮助。我更想带你走一遍核心逻辑,让你能理解脚本每一部分在做什么。

一个典型的phpinfo()利用脚本,核心结构大概是这样的:

# 伪代码,仅用于说明结构 import threading import requests import re # 目标配置 phpinfo_url = "http://target/phpinfo.php" lfi_url = "http://target/index.php?file=" # 每个线程干的事: # 线程A:持续向phpinfo发送文件上传请求,内容为恶意PHP代码 # 线程B:持续向LFI发送包含/tmp/phpXXXXXX的请求 # 线程C:从phpinfo响应中解析最新临时文件名,分发到线程B的猜测列表中 # 命中后,恶意代码输出标志,脚本停止。

这个结构里有三个关键模块:

  1. 上传模块:构造multipart/form-data请求,把一句话木马或命令执行代码作为文件内容发送。注意,文件字段名不能乱填,需要符合PHP的接收逻辑,但利用时往往不需要目标代码真的接收这个文件——只要PHP解析了multipart请求,临时文件就会生成。

  2. 解析模块:解析phpinfo()返回的HTML,提取临时文件路径。phpinfo()页面上会有一个$_FILES['xxx']的表格,展示Name、Type、Size、Tmp_name等字段。Tmp_name就是/tmp/phpXXXX.tmp。

  3. 包含模块:向LFI点发起包含请求。因为临时文件名随机,需要不断轮换猜测的路径。高并发是这个模块的灵魂。

这里要特别强调一个容易出错的点:phpinfo()页面输出Tmp_name的时候,临时文件可能已经被删了。解析到的文件名再用去包含时,大概率是失效的。所以脚本必须处理这种“拿到文件名 → 文件名已失效”的死循环。解法就是:不要等解析结果再包含,而是让“上传扫描”和“包含猜名”同时跑。扫描线程负责不断更新候选文件名池,包含线程则疯狂用最新的候选池去撞。

很多初学者写这类脚本时,习惯性地“请求phpinfo → 提取文件名 → 请求LFI”,串行执行,结果永远是“文件不存在”。因为在串行模式下,等你请求完phpinfo、解析完HTML、再发起LFI请求时,临时文件早就没了。这个时间差是致命的。正确做法就是把上传和包含做成两个并发流,用数量换概率。

3.5 核心利用请求的构造方式

在phpinfo()利用中,核心的恶意请求是“文件上传”请求。它的HTTP报文大致是这样的:

POST /phpinfo.php HTTP/1.1 Host: target Content-Type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW Content-Disposition: form-data; name="file"; filename="shell.php" Content-Type: application/x-php <?php system($_GET['cmd']); ?>

这段报文的关键在于:只要Content-Type是multipart/form-data,且包含一个filename字段,PHP就会把这个字段当作文件上传处理,并在/tmp下生成临时文件。至于目标脚本是不是phpinfo(),其实不重要——重要的只是它能处理这个请求并展示配置信息。phpinfo()的特殊之处在于它会输出Tmp_name,方便脚本做路径校准,仅此而已。

有些利用方式会故意把phpinfo()输出“污染”——比如在上传内容里塞入大量垃圾数据,让phpinfo()的HTML输出变得异常庞大,从而拖延脚本执行时间、增加临时文件的存活时间窗口。不过这个技巧比较脏,实际效果因环境而异,不是每个场景都好使。

3.6 触发成功后的效果与利用价值

一旦竞态命中,LFI点成功包含了那个临时文件,意味着什么?

临时文件的内容是我们上传的PHP代码,比如<?php system($_GET['cmd']); ?>。包含之后,这段代码被执行,配合GET参数cmd,就实现了远程命令执行。也就是说,从“一个不可控的文件包含点”,升级到了“远程代码执行”。

到了这一步,后续能做的事就常规多了:

  • 读取数据库配置文件,拿到数据库账号密码。
  • 写入Webshell到站点目录。
  • 反弹Shell到攻击机。
  • 内网横向渗透。

但要注意,利用成功只是一瞬间的事。临时文件被包含执行后,很快会被PHP删除。你写入的代码是“一次性”的。所以,如果你想要一个持久化的后门,必须在利用成功后的同一时间窗口里,用file_put_contents之类的函数把恶意代码写到Web目录中的某个固定文件里。这是实战中非常常见的一个后续动作。

4. 实操过程与调试实录

理论拆完了,接下来进入实操层面。我会按实际操作顺序,把整个过程串一遍,包括环境准备、利用脚本的编写思路、关键参数的调试方法,以及我实际调试过程中记录的一些现象。

4.1 环境准备:本地搭建一个靶场

如果你想把整个利用链跑通,建议先在本地搭一个靶场。环境清单如下:

  • PHP版本建议选择5.x或7.x早期版本,部分高版本PHP对临时文件删除时机做了调整,但整体机制不变。
  • Web服务器选Apache或Nginx + PHP-FPM均可。
  • 需要关闭allow_url_include和allow_url_fopen,模拟真实环境。
  • 准备两个PHP文件:lfi.php(漏洞文件)和phpinfo.php。

lfi.php的代码可以是:

<?php $file = $_GET['file']; include($file); ?>

phpinfo.php就一行:

<?php phpinfo(); ?>

这样简陋的环境,恰恰能模拟出真实场景中“无伪协议、无上传点”的困境。

4.2 利用脚本的编写要点

如果你决定自己写脚本,下面这些核心函数和参数是我建议你先确定下来的。

上传线程:

def upload_thread(phpinfo_url, payload): while True: files = { 'file': ('shell.php', payload, 'application/x-php') } try: requests.post(phpinfo_url, files=files, timeout=0.5) except Exception: pass

注意两点:files参数构造的multipart请求会触发临时文件生成;timeout要设置得短一些,避免请求阻塞导致线程堆积。

解析线程:

def parse_thread(phpinfo_url, name_queue): while True: resp = requests.get(phpinfo_url) pattern = re.compile(r'php[0-9A-Za-z]{6}\.tmp') matches = pattern.findall(resp.text) for name in matches: name_queue.put(name)

解析线程不断刷新phpinfo()页面,把出现的临时文件名塞进队列。注意:队列里的名字可能已经失效,这是正常的,包含线程就是要用数量去覆盖它。

包含线程:

def include_thread(lfi_url, name_queue): while True: try: name = name_queue.get(timeout=1) except Exception: continue full_path = "/tmp/" + name target = lfi_url + full_path resp = requests.get(target, timeout=0.5) if "FLAG{success}" in resp.text: print("[+] 利用成功") break

如果你想让脚本在命中后停下来,可以在上传的payload里加入一个固定标志,然后在包含响应中搜索这个标志。

实际测试时,你会发现一个现象:进程跑起来以后,大量请求会得到404或500,因为包含的文件不存在。这正是竞态利用的常态。我通常的做法是:先把并发线程数从10、20、50逐步调上去,观察在哪个量级能命中。不同机器、不同PHP版本上,这个阈值差异很大。

4.3 关键参数的调整心得

根据我的实测,有几个参数会直接决定成功率。

upload_tmp_dir的位置。如果phpinfo()里显示upload_tmp_dir是非默认路径,比如/var/tmp或项目自定义目录,包含路径也要跟着改。这是最容易翻车的地方——脚本跑得飞起,命中率却是零,最后发现是你把临时文件路径猜错了。

并发线程数。这个值的设定,本质上是“请求频率 vs 服务器负载”的权衡。线程太少,可能半天碰不上;线程太多,服务器直接拒绝服务或PHP进程崩溃。我实测中比较稳妥的做法是:先以20~50个并发起步,观察服务器响应情况,再逐步增加。超过200个并发时,很多本机环境就开始出现大量连接被重置的情况了。

PHP版本差异。老版本PHP(5.x)中,临时文件删除逻辑相对简单,命中率往往更高。PHP 7.2以后,某些环境下临时文件在请求结束到真正删除之间存在更微妙的时序,脚本命中率会降低。这不是说利用失效了,而是需要更精细的时序控制。网上很多旧脚本跑不动,多半是因为版本差异导致窗口缩短、但并发量没跟上。

payload大小的影响。payload内容越大,临时文件写入时间越长,理论上存在窗口也越长。所以,适当在payload前后填充一些注释字符,比如<?php system($_GET['cmd']); ?>/*AAA...*/,可以延长窗口。但代价是每次请求传输的数据量变大,会拖慢整体频率。需要根据实际情况权衡。

4.4 一次实际操作现象记录

为了写这篇文章,我在本地环境(PHP 7.4 + Nginx)又跑了一次完整利用。大致流程如下:

开启三个终端,一个运行攻击脚本,一个用watch监控/tmp下的临时文件生成情况,一个用tail查看Web服务器的错误日志。

一开始我把并发设为10,跑了大约两分钟,没有任何命中。原因是10个并发线程里,上传和包含各占一半,上传频率太低,临时文件的生成数量很有限。随后把并发直接拉到50,大约30秒左右,/tmp下开始频繁出现phpXXXX.tmp文件,但随即被删除。

命中发生在脚本启动约1分20秒的时候——包含线程收到了包含成功的响应,页面内容出现了我植入的标志字符串,同时恶意代码执行了system('id'),成功返回了运行Web服务的用户信息。

整个过程验证下来,核心要点无非三个:临时文件路径要对、并发量要够大、payload要简洁有效。

5. 常见问题与排查技巧实录

这一章我来集中整理实践中常见的坑,以及我排查时用的方法。每一条后面都附一个“为什么”,希望能帮你少走弯路。

5.1 为什么临时文件名总是解析不到

这个问题的典型表现是:脚本跑了很久,phpinfo()返回的HTML里始终提取不到Tmp_name字段,或者提取到的总是空值。

原因通常是:上传请求的multipart结构不对。PHP只有在正确解析到filename字段时才会生成临时文件。如果你的请求里文件字段名不叫file而叫别的,也没关系,PHP不在乎字段名——但如果你把filename参数写错了,或者Content-Disposition头格式不规范,PHP可能把你的“文件”当成了普通表单字段,自然就没有临时文件生成。

排查方法:手动用requests发一个上传请求,打印响应文本,搜索Tmp_name。如果搜不到,多半是请求构造有误。把整个multipart报文用抓包工具打开看一遍,对照标准格式逐字段检查。

5.2 为什么解析到了文件名,包含却总是404

这是最让人沮丧的情况:phpinfo()页面明明显示了/tmp/phpABC123.tmp,但LFI请求返回404或文件不存在。

原因有几种可能:

  1. 时序错位:解析到文件名的时候,临时文件已被删除。这是最常见的情况。处理方式是增加并发、把解析和包含彻底解耦。
  2. 路径拼写错误:phpinfo()显示的临时文件路径,和你实际拼接的路径不一致。比如它显示的是绝对路径,你却在前面多加了一个目录;或者upload_tmp_dir设置了相对路径。
  3. open_basedir限制:PHP配置了open_basedir,LFI点所在脚本无法访问/tmp目录。这种情况在虚拟主机环境尤其常见。

排查建议:先用一个确定存在的文件测试LFI点是否正常工作,比如包含/etc/passwd,看能否读到内容。如果连这个都读不到,说明问题不在竞态利用,而在LFI点本身的可控性上。

5.3 为什么脚本跑得飞快,却没有任何命中

这个情况我也遇到过。脚本每秒发出大量请求,服务器负载也很高,但就是没有一次成功。

排查方向:

  1. LFI点是否真的能包含任意路径。有的LFI点会拼接固定前缀或后缀,比如include('/var/www/' . $file . '.php')。这种情况下,包含/tmp/phpXXX.tmp会变成/var/www//tmp/phpXXX.tmp.php,文件自然不存在。如果目标是这种LFI,这个利用链就需要先找到绕过拼接限制的方法,比如用路径穿越把路径拉回/tmp,再配合截断,但成功率和环境适配度都会下降。

  2. 并发量是否足够。我看过一些讨论帖,有人说“我开了10个线程跑了1小时都没成功”。10个线程在这种竞态利用里太少了。我自己的经验是,至少50个线程起步,如果服务器扛得住,直接上100。

  3. PHP版本/服务器处理方式差异。Apache mod_php和PHP-FPM在处理并发时的行为差异很大。PHP-FPM默认的pm.max_children如果太小,大量并发请求会直接排队或产生502。可以观察错误日志,如果大量worker进程被占满,就需要调整并发策略。

5.4 为什么利用成功后,写马的请求又失败了

典型的翻车现场:竞态命中了,执行了system('id'),你已经看到了结果,但紧接着发送的“写入Webshell”请求失败了。或者,你明明在payload里写入了file_put_contents,但目标目录里却没有生成后门文件。

原因分两种:

  • 如果你是把写入动作放在同一个临时文件payload里,那么临时文件被删除的同时,它执行的写入动作已经生效了——除非写入的目录没有写权限。Web目录的写权限经常是受控的。所以,写入目标要优先选择/tmp这类一定可写的路径,然后配合其他方式二次利用。
  • 如果你是想在RCE之后,再通过另一个请求去写马,那就回到了“竞态命中只是一瞬间”的问题上。命令执行是瞬时的,执行完临时文件就没了,你不可能用一个后续请求去依赖已经消失的临时文件。

实际做法是:把“写入后门”的动作直接包含在payload里,让它和命令执行在同一个临时文件生命周期内完成。比如payload里同时写上命令执行后门和文件写入后门,命中一次就一步到位。

5.5 利用链变体:Session文件包含

严格来说,phpinfo()利用法只是“临时文件制造LFI”家族里最出名的一种。同思路的还有Session文件包含。如果你的目标站点开启了Session,且session.save_path可预测,你可以通过构造一个包含恶意代码的Session值,再通过LFI包含Session文件。这个变体在很多CTF题里出现过,实战中的价值也取决于Session文件的路径和权限。这里顺带提一句,是因为它和phpinfo()利用法的逻辑高度相似——本质上都是“制造一个短暂存在的可控本地文件,然后在它消失前包含它”。

5.6 防护视角:这个漏洞该怎么堵

聊利用也得聊防御,防守方的思路反而能帮助你更深刻地理解进攻方的逻辑。

要防住这个利用链,最有效的几个手段:

  1. 严格限制文件包含参数。对file参数做白名单校验,禁止包含非预期目录的文件。这是最根本的修复。
  2. 禁用phpinfo()页面。线上环境删除所有phpinfo()文件,防止攻击者获取配置信息和触发临时文件生成。
  3. 调整upload_tmp_dir到Web进程不可读的目录,并用open_basedir限制LFI脚本的访问范围。
  4. 配置WAF规则,对/tmp/php*.tmp这类路径特征做拦截。
  5. 升级PHP版本并启用sys_temp_dir等安全加固配置。

可以看到,这项攻击之所以能成立,靠的不是哪个单一组件的漏洞,而是“PHP临时文件机制 + 文件包含点 + 信息泄露页面”组合在一起产生的化学反应。任何一个环节被卡住,整条链都会断掉。

6. 写在最后的一点体会

老实说,这个利用技巧在真实渗透中未必是最高效的路径——如果你有路径穿越或者日志注入的机会,成功率可能会更高。但phpinfo()利用法给我最大的启发是:漏洞利用从来不是背POC、套脚本这么简单,它考验的是你对目标运行机制的理解深度。

我在第一次跑通这个利用链的时候,感触很深。整个过程中,最让我意外的不是“临时文件居然可以被包含”,而是“PHP在解析multipart请求时,竟然会在脚本执行前就把文件写入磁盘”。这个细节,如果你不主动去深挖,可能永远都不会意识到。而攻击者恰恰就是抓住了这个极其短暂的瞬间,完成了一次击杀。

所以如果你是往安全方向学习的新人,我非常建议你亲手把这个利用链从头到尾跑一遍,而不是只看文章和POC。自己写脚本、自己调整并发参数、自己观察临时文件的生成与消失,这个过程比看十篇分析文章都更有价值。当你能完全掌控这个竞态的节奏时,你对PHP运行时机制的理解、对HTTP请求细节的敏感度,都会上一个台阶。

最后分享一个小技巧:在调试这类竞态利用时,别盯着payload本身调来调去,先确认“临时文件有没有生成”和“LFI点能不能包含任意路径”这两个前置条件。前置条件不满足,再怎么调并发都是白费工夫。先做最小化验证,再谈优化,这条经验适用于所有需要“抢时间”的漏洞利用场景。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/22 15:23:40

Claude Code离线安装包制作与部署全指南

简介&#xff1a;这份离线安装包面向需要在公司内网、局域网大模型环境下使用 Claude Code 的开发者与运维人员&#xff0c;解决外网不可达时工具链无法安装、插件无法下载的问题。资源共 32 个文件&#xff0c;以 exe、whl、zip、md、json、cjs 等类型为主&#xff0c;涵盖 Gi…

作者头像 李华
网站建设 2026/10/22 13:13:13

Paperxie一站式论文写作实测:写作绘图排版与AI率检测全解析

有没有一种感觉&#xff0c;论文写作最耗精力的不是想不出观点&#xff0c;而是工具之间的来回切换&#xff1f;写两段文字切到通用文字处理器&#xff0c;画一张示意图打开绘图软件&#xff0c;调格式再切到排版工具&#xff0c;最后把全文复制到检测系统看AI疑似比例。一天下…

作者头像 李华
网站建设 2026/11/2 20:05:59

插入排序Java实现详解:从原理到代码实践

1. 排序算法与插入排序的定位排序算法是数据结构课程里绕不开的基础模块&#xff0c;也是面试和实际开发中最常碰到的算法类型。说到排序&#xff0c;很多初学者第一反应是“Arrays.sort()不就完了吗”&#xff0c;但真要让你解释清楚排序背后的思想、复杂度的推导过程、不同数…

作者头像 李华
网站建设 2026/10/24 12:27:59

Kubernetes Ingress 实战:服务端口暴露与路由配置指南

1. 项目背景与需求拆解前几天同事跑来问我一个标题&#xff0c;说在搜索引擎里怎么都搜不到结果&#xff0c;标题写的是“k8s degress 暴漏服务端口”。我先愣了一下&#xff0c;然后反应过来&#xff0c;这里的“degress”八成是 Ingress 的笔误&#xff0c;而“暴漏”其实是“…

作者头像 李华
网站建设 2026/10/26 7:17:21

PDF定点绘制表格:用Apache PDFBox精准控制坐标与内容流

1. 项目概述&#xff1a;为什么非得在PDF固定位置“手绘”表格和内容&#xff1f;最近帮某高校实验室处理一批实验报告归档&#xff0c;遇到个典型场景&#xff1a;所有原始PDF都是扫描件或模板生成的静态文件&#xff0c;但每份报告末尾都需要插入统一格式的审核意见表——三列…

作者头像 李华
网站建设 2026/10/23 14:50:24

LlamaIndex RAG多智能体手机客服实战:从知识问答到协作下单全流程

手机客服这个场景&#xff0c;我陆陆续续做了几个项目&#xff0c;最深的感受是&#xff1a;它不像通用聊天机器人那样问两句闲话就完事&#xff0c;而是要把“查参数、比型号、判故障、查库存、引导下单”这些具体动作串起来。前阵子我用一份手机机型数据集&#xff0c;把 Lla…

作者头像 李华