LFI to RCE
字数 1112 2025-08-29 08:32:01
LFI to RCE 漏洞利用技术详解
一、漏洞背景
本文基于[HITCON CTF 2018]One Line PHP Challenge题目环境,分析如何从本地文件包含(LFI)漏洞实现远程代码执行(RCE)。题目环境为Ubuntu 18.04 + PHP 7.2 + Apache。
二、漏洞代码分析
题目源码极为简洁:
<?php
($_ = @$_GET['orange']) && @substr(file($_)[0], 0, 6) === '@<?php' ? include($_) : highlight_file(__FILE__);
代码逻辑:
- 检查是否存在
orange参数 - 读取该参数指定的文件内容
- 检查文件前6个字符是否为
@<?php - 如果满足条件则包含该文件,否则显示源码
三、漏洞利用思路
1. 文件上传机制
PHP处理文件上传时:
- 文件流会被保存到临时目录
- 文件名格式:
php[0-9A-Za-z]{3,6} - 文件存活周期:
- PHP正常结束且文件未被移动/重命名:请求结束后删除
- PHP非正常结束(如崩溃):文件永久保留
- 正常情况下临时文件存活时间约30秒
2. 利用方法
方法一:暴力破解
在30秒内猜测临时文件名,但概率极低(1/2176782336)
方法二:使PHP崩溃
通过特定POC使PHP崩溃,使临时文件永久保留,从而有足够时间爆破
四、技术细节分析
1. 崩溃POC
php://filter/convert.quoted-printable-encode/resource=data://,%bfAAAAAAAAAAAAAAAAAAAAAAA%ff%ff%ff%ff%ff%ff%ff%ffAAAAAAAAAAAAAAAAAAAAAAAA
2. PHP底层漏洞分析
漏洞位于php-src/ext/standard/filters.c中的PHP_CONV_ERR_TOO_BIG错误处理:
case PHP_CONV_ERR_TOO_BIG: {
char *new_out_buf;
size_t new_out_buf_size;
new_out_buf_size = out_buf_size << 1;
if (new_out_buf_size < out_buf_size) {
// 处理逻辑
} else {
new_out_buf = perealloc(out_buf, new_out_buf_size, persistent);
// 内存分配会倍增,导致过大
}
break;
}
关键问题:
- 当输入字符串包含ASCII>126的字符时进入特定分支
lbchars_len变量未初始化- 通过控制
lbchars_len值可导致整数溢出 - 最终导致段错误(segfault)使PHP崩溃
3. 相关CVE
CVE-2016-7125:
- 影响版本:
- PHP 5.x < 5.6.25
- PHP 7.x < 7.0.10
- 漏洞描述:
ext/session/session.c中错误解析会话名称,允许通过控制会话注入任意会话数据
五、漏洞利用步骤
- 上传恶意文件
- 使用POC使PHP崩溃:
file(urldecode('php://filter/convert.quoted-printable-encode/resource=data://,%bfAAAAAAAAFAAAAAAAAAAAAAA%ff%ff%ff%ff%ff%ff%ff%ffAAAAAAAAAAAAAAAAAAAAAAAA')); - 临时文件被永久保留
- 爆破临时文件名
- 通过LFI包含临时文件实现RCE
六、防御措施
- 升级PHP版本
- 禁用危险函数和协议
- 对文件包含操作进行严格校验
- 设置
open_basedir限制文件访问范围 - 避免使用用户输入直接作为文件路径
七、影响版本测试
经测试,以下版本受影响:
- PHP 7.1.3
- PHP 5.6.28
PHP 7.4及以上版本不受此漏洞影响。
八、总结
该漏洞利用链结合了:
- PHP文件上传机制
- 过滤器内存处理缺陷
- 临时文件保留特性
- 本地文件包含漏洞
通过精心构造的输入触发PHP崩溃,绕过临时文件删除机制,最终实现从LFI到RCE的转换。