步骤三:检查PHP配置
查看配置:
php -i | grep -E 'session.upload_progress.enabled|memory_limit|post_max_size|upload_max_filesize'
Docker环境:
docker exec <PHP容器名> php -i | grep -E 'session.upload_progress.enabled|memory_limit|post_max_size|upload_max_filesize'
重点看三个地方:
session.upload_progress.enabled有没有开启。
memory_limit、上传大小限制设置了多少。
- Web服务实际加载了哪个PHP配置文件。
注意:php -i显示的是命令行PHP配置。Apache和PHP-FPM可能加载不同的配置,要检查对应服务实际使用的配置。
步骤四:检查Web日志
Apache访问日志:
tail -n 50 /var/log/apache2/access.log
Apache错误日志:
tail -n 50 /var/log/apache2/error.log
Nginx访问日志:
tail -n 50 /var/log/nginx/access.log
Nginx错误日志:
tail -n 50 /var/log/nginx/error.log
重点检查:
- 短时间内出现大量POST请求,重点看上传接口。
- HTTP 500突然增多,PHP报内存错误或工作进程崩溃。
- 同一个IP反复发请求,PHP工作进程频繁退出或重启。
- 异常请求之后,服务器出现可疑下载、文件写入或外联连接。
普通访问日志通常不保存POST请求体。需要查看请求内容时,再查WAF、网关或应用侧的请求记录。
步骤五:检查文件、进程和网络连接
查最近两小时修改过的网站文件:
find /var/www/html -type f -mmin -120 -ls
查PHP和Web服务进程:
ps -ef | grep -E '[p]hp|[a]pache2|[h]ttpd|[n]ginx'
查当前网络连接:
如果服务器有进程审计或EDR,再查PHP、Apache进程有没有启动sh、wget、curl等程序。
发现可疑文件,先保存日志和文件信息,确认来源后再处理。
步骤六:升级PHP
先确认PHP分支,再升级到官方修复版本或发行商提供的安全更新版本。
本次实验使用的是8.4分支:
PHP 8.4.26 → PHP 8.4.27或更高的已修复版本
Docker部署的服务,要更新镜像、重新部署容器,并验证业务。直接在运行中的容器里改PHP,下一次重建容器可能又回到旧版本。
生产升级前备份配置,检查扩展兼容性,并安排维护窗口或灰度发布。
步骤七:暂时不能升级怎么办?
针对session.upload_progress相关风险,按PHP官方安全公告检查实际生效的配置,并评估临时关闭上传进度功能:
session.upload_progress.enabled=0
修改后重启对应的PHP服务或工作进程,再检查配置有没有生效。
同时检查上传大小、请求体大小和业务接口的访问限制。最终还是要安装官方安全更新。
步骤八:验证修复
检查版本:
检查网站:
检查上传进度配置:
php -i | grep 'session.upload_progress.enabled'
最后检查访问日志、错误日志、异常文件和外联连接,确认服务恢复正常。
03 漏洞攻击过程与结果验证
1. 攻击过程是怎样的?
攻击程序大致分四步:
| 阶段 | 具体做什么 |
|---|
| 识别环境 | 获取PHP版本、Web服务器类型等信息,选择对应的利用配置。 |
| 触发内存错误 | 发送HTTP POST文件上传请求,让存在漏洞的PHP走到有问题的内存处理流程。 |
| 泄露内存地址 | 通过越界读取拿到PHP进程的部分地址,再推算相关代码的位置。 |
| 执行命令 | 继续利用内存管理缺陷,改变PHP进程的执行流程,让它执行系统命令。 |
攻击程序可能多次发送请求,所以Web日志里可能出现一批POST请求、HTTP 500和PHP进程异常。
2. 怎么确认服务器受到了影响?
重点查服务器上发生了什么。
| 检查内容 | 重点看什么 |
|---|
| Web访问日志 | 异常POST请求的时间、来源IP和HTTP状态码。 |
| PHP错误日志 | 内存错误、进程崩溃和工作进程重启。 |
| 系统进程 | PHP或Apache有没有启动sh、wget、curl等程序。 |
| 网站文件 | 有没有新增的PHP文件、脚本和异常下载文件。 |
| 网络连接 | PHP或Apache进程有没有向陌生地址发起连接。 |
把这些记录按时间对上,确认异常请求发生后,服务器有没有执行异常操作。
3. 实机案例
本次在两台隔离虚拟机上验证:
| 角色 | 环境 |
|---|
| 测试机 | Linux,运行公开的agrresore/php2shell PoC。 |
| 目标机 | Docker容器,PHP 8.4.26 + Apache。 |
测试内容是让目标PHP进程执行下载命令,把一个普通文本文件保存到网站目录。
PoC依次完成环境识别、版本配置匹配、工作进程处理和漏洞利用尝试,最后输出:
[phase 0] RECON
[phase 1] PROFILE LOOKUP
[phase 2] WORKER PINNING
[phase 3] EXPLOIT CHAIN (file-based)
[try 1/5]
...
[try 5/5]
[-] all attempts exhausted
切换到目标机,查看网站目录:
docker exec php2shell-target ls -lh /var/www/html/
目录里新增了robots.txt、robots.txt.1到robots.txt.4,每个文件都是295字节。wget重复下载同名文件,会自动添加数字后缀。
验证结果:目标PHP进程执行了下载命令。 PoC最后提示尝试次数耗尽,是因为它没有从自己的结果检查中收到成功确认。
04 常用排查命令
| 检查内容 | 命令 |
|---|
| PHP版本 | php -v |
| PHP运行方式 | php -i | grep 'Server API' |
| PHP配置文件 | php --ini |
| 上传进度功能 | php -i | grep session.upload_progress.enabled |
| PHP内存限制 | php -i | grep memory_limit |
| Web响应 | curl -I http://127.0.0.1 |
| Apache错误日志 | tail -n 50 /var/log/apache2/error.log |
| Nginx错误日志 | tail -n 50 /var/log/nginx/error.log |
| 最近修改的文件 | find /var/www/html -type f -mmin -120 -ls |
| PHP/Web进程 | ps -ef | grep -E '[p]hp|[a]pache2|[h]ttpd' |
| 网络连接 | ss -tunap |
| 容器PHP版本 | docker exec <容器名> php -v |
05 面试回答:PHP底层内存漏洞为什么会导致远程命令执行?
这类漏洞跟PHP的内存管理有关。PHP处理请求的时候会用到内存,请求结束后会把不用的内存释放掉。但是有漏洞的版本,在一些情况下会出现内存已经释放、程序还继续使用原来引用的问题。这个问题叫Use-After-Free,也就是释放后使用。
攻击者可以利用这个问题读取PHP进程的内存数据,拿到部分内存地址。因为Linux一般开着ASLR,程序每次运行,代码地址可能不一样,所以攻击者要先定位地址。
找到相关代码的位置以后,攻击者再利用内存管理缺陷影响PHP的执行流程,最后让PHP执行系统命令。这样就可能出现没有服务器账号密码,也能远程执行命令的情况。
如果线上遇到这类漏洞,我会先查实际运行的PHP版本和配置,确认哪些服务受影响,然后升级PHP。接着检查Web日志、错误日志、异常文件、进程和外联连接,排查有没有被利用的痕迹。
06 面试追问与回答
Q1:RCE是什么?
RCE就是远程代码执行。攻击者通过网络触发漏洞,让服务器执行指定代码或系统命令。
Q2:什么是Use-After-Free?
内存已经释放了,程序却还继续使用指向这块内存的引用。这就叫释放后使用。
Q3:为什么要泄露内存地址?
因为ASLR会改变程序加载到内存中的位置。攻击程序要先拿到一些地址,才能推算相关代码的位置。
Q4:ASLR是什么?
ASLR就是地址空间布局随机化。程序每次运行,相关代码和数据的内存地址可能不同。
Q5:HTTP 500代表什么?
代表服务器处理请求时出错了。还要结合错误日志、进程状态和文件变化判断发生了什么。
Q6:业务代码没有漏洞,也可能受影响吗?
可能。这个问题出在PHP运行环境本身。重点查PHP版本和实际运行配置。
Q7:使用PHP-FPM就不用处理了吗?
也需要检查。先确认版本,再按官方公告和发行商的安全更新处理。
Q8:关闭session.upload_progress.enabled就够了吗?
还要升级PHP。关闭这个功能是针对相关风险的临时处理办法。
Q9:升级以后为什么还要查异常文件?
升级会修复PHP漏洞,但攻击者之前留下的文件可能还在,需要继续检查和清理。
Q10:运维接到这类漏洞通知,第一步做什么?
先盘点哪些服务在使用PHP,查清实际版本、访问入口和运行方式,再安排修复。
07 PHP安全信息收集脚本(只读)
这个脚本只收集版本、配置、进程和监听端口,不修改系统。
保存为check_php_security.sh:
#!/usr/bin/env bash
if command -v php >/dev/null 2>&1; then
echo '=== PHP版本 ==='
php -v | head -n 2
echo '=== PHP CLI配置 ==='
php -i | grep -E 'Server API|Loaded Configuration File|session.upload_progress.enabled|memory_limit|post_max_size|upload_max_filesize'
else
echo '没有找到php命令,请检查PHP容器'
fi
echo '=== Web进程 ==='
ps -ef | grep -E '[p]hp-fpm|[a]pache2|[h]ttpd|[n]ginx'
echo '=== 监听端口 ==='
ss -lntp
执行:
bash check_php_security.sh
**注意:**脚本读取的是CLI配置。Apache或PHP-FPM使用的配置需要单独核查。
08 现场处理要点与配套资料
现场处理按这个顺序来:
- 找出所有运行PHP的服务器和容器。
- 确认版本、运行方式和外部访问入口。
- 保存相关时间段的访问日志、错误日志和可疑文件信息。
- 排查异常进程、文件写入和外联连接。
- 升级PHP,重启或替换对应工作进程。
- 验证业务,继续观察日志。
配套资料
建议资料包包含实验环境说明、版本对照表、真实日志截图、只读检查脚本、修复检查清单,以及公开PoC项目的GitHub地址和许可证。
参考资料