大家好,本篇继续更新 PHP 底层函数劫持系列。
在前两篇博文中,我们详细拆解了两种主流劫持方案:
1、override_function:原生函数,但必须 Debug 编译版 PHP 才能用,99% 的 PHP5.4/7.x 集成环境直接报未定义错误;
2、uopz_set_mock:能力最强,可劫持 eval,但仅支持 PHP7~8.1,完全不兼容 PHP5.x。
这就出现了一个巨大的空白:PHP5.4 Release 正式版,到底用什么劫持内置函数?
答案就是今天的主角:runkit.internal_override。
它是 PHP5.x 专属的终极函数重写方案,无需 Debug 编译、无需特殊内核参数,普通宝塔/PHPstudy/LNMP 一键安装的 PHP5.4 环境即可完美运行,也是老版本后门、审计、动态调试的核心利用手段。
一、核心痛点复盘(为什么需要它?)
很多师傅在实战中卡死在同一个问题:
PHP5.4 环境,调用 override_function 直接报错:Call to undefined function
原因我们在上篇已经讲透:override_function 仅在带 --enable-debug 编译的 PHP 中存在,普通生产/测试环境完全没有。
而 runkit + internal_override 就是为解决这个问题而生:
普通 Release 版 PHP5.4,开启该配置后,可直接重写 PHP 所有内置函数,平替 override_function!
二、runkit 与 internal_override 原理详解
1. 什么是 runkit 扩展?
runkit 是一款老牌 PHP 动态操作扩展,主打运行时修改函数、方法、常量,在 PHP5 时代是官方最主流的动态劫持扩展,PHP7 之后逐渐被 uopz 替代。
其核心能力包含:函数重定义、函数删除、方法修改、常量覆盖等。
2. runkit.internal_override 核心作用
默认情况下,runkit 也无法重写 PHP 内核内置函数,只能重写用户自定义函数。
而 runkit.internal_override = On 是 php.ini 中的核心开关:
开启后,放开内核限制,允许 runkit 函数直接覆盖 PHP 原生内置函数(system、file_get_contents、exec 等)。
3. 能力边界与版本限制
- 适配版本:完美支持 PHP5.2 ~ PHP5.6(PHP5.x 专属神器)
- 失效版本:PHP7.0+ 废弃 runkit 主流特性,完全无法使用
- 环境要求:普通 Release 版本即可,无需 Debug 编译
- 劫持范围:仅内置函数,不支持 eval、include 等语法结构(同 override_function)
三、环境部署(PHP5.4 专属)
1. 安装 runkit 扩展
PHP5.x 需安装适配旧版本的 runkit,高版本 runkit 不兼容 PHP5:
# pecl 安装旧版本 runkit
pecl install runkit-1.0.4
安装完成后,在 php.ini 载入扩展:
extension=runkit.so
2. 开启核心劫持开关
这一步是重中之重,不开启则无法劫持内置函数
在 php.ini 末尾添加:
runkit.internal_override = On
重启 PHP 服务,通过 phpinfo() 验证参数已开启,环境搭建完成。
四、完整实战:runkit 劫持内置函数 Demo
下面提供 PHP5.4 可直接运行 的完整代码,实现劫持 system 命令执行,完成捕获、拦截、放行、还原全流程,完美平替 override_function。
<?php
// 检测环境是否支持
if (!extension_loaded('runkit') || !ini_get('runkit.internal_override')) {
die("[-] 请安装 runkit 并开启 runkit.internal_override = On");
}
// 1. 重写内置 system 函数
function system($cmd) {
// 捕获执行命令
echo "[+] runkit 劫持命令:" . $cmd . "\n";
// 恶意拦截:禁止执行系统高危命令
if (strpos($cmd, 'whoami') !== false || strpos($cmd, 'id') !== false) {
echo "[-] 高危系统命令已拦截\n";
return false;
}
// 放行原生逻辑:调用原始 system 函数
return runkit_function_restore('system') && call_user_func_array('system', func_get_args());
}
// 测试1:高危命令拦截
system("whoami");
// 测试2:普通命令放行
system("echo hello runkit");
// 2. 彻底还原原生函数
runkit_function_restore('system');
echo "[+] 已恢复 system 原生逻辑\n";
// 恢复后正常执行
system("whoami");
?>
运行逻辑解析
- 开启
runkit.internal_override后,用户自定义函数可直接覆盖内置函数; - 精准拦截高危命令,普通业务命令正常放行,无业务侵入;
runkit_function_restore()可随时还原原生函数,不留残留。
五、核心函数讲解
runkit 配套两大核心函数,对应 override 的劫持与还原:
1. runkit_function_redefine
动态重定义函数,支持运行时修改内置/自定义函数逻辑,灵活性极高。
2. runkit_function_restore
恢复被重写的函数至原生状态,对应 restore_function。
六、常见报错与排错方案
1. 自定义重写内置函数不生效
原因:未开启 runkit.internal_override = On,默认禁止覆盖内置函数。
解决:修改 php.ini 开启参数,重启 PHP 生效。
2. Call to undefined function runkit_function_redefine()
原因:未安装 runkit 扩展,或扩展版本不匹配 PHP5。
解决:安装适配 PHP5 的 runkit-1.0.4 旧版本。
3. PHP7+ 无法使用
原因:runkit 已废弃,高版本 PHP 彻底淘汰该扩展。
解决:PHP7+ 统一使用 uopz 扩展替代。
七、三大劫持方案终极对比(覆盖全版本PHP)
至此,PHP 所有主流函数劫持方案全部集齐,覆盖 PHP5~PHP8 全环境,彻底解决所有版本适配问题。
| 劫持方案 | 适配版本 | 环境要求 | 劫持范围 | 实战可用性 |
|---|---|---|---|---|
| override_function | PHP5~7.3 | 必须 Debug 编译版 | 仅内置函数 | 极低(几乎用不了) |
| runkit.internal_override | PHP5.x 专属 | 普通 Release 版 + runkit扩展 | 仅内置函数 | 极高(PHP5 唯一可用) |
| uopz_set_mock | PHP7~8.1 | 安装 uopz 扩展 | 函数+eval语法结构 | 极高(全能方案) |
八、安全风险与恶意利用
runkit.internal_override 是 PHP5 老旧服务器的高危隐患,被攻击者频繁利用:
- 劫持
system/exec/passthru,绕过 disable_functions 执行系统命令; - 劫持
file_get_contents/file_put_contents,窃取源码、植入隐形后门; - 劫持
assert动态执行代码,隐藏 Webshell 行为; - PHP5 老旧服务器普遍存在该扩展残留,防护意识薄弱,极易被穿透利用。
九、生产环境防护方案
针对老旧 PHP5 服务器,必须做如下加固:
1. 关闭核心危险开关
php.ini 中强制关闭劫持能力:
runkit.internal_override = Off
2. 卸载高危扩展
生产环境无调试需求,直接注释/卸载 runkit 扩展,彻底杜绝风险。
3. 禁用危险函数
在 disable_functions 加入 runkit 核心函数:
disable_functions = runkit_function_redefine,runkit_function_restore
4. 版本升级(终极方案)
PHP5 早已停止维护,存在大量底层漏洞,建议直接升级 PHP7.4/8+ 高版本,从根源规避所有老旧劫持风险。
十、全文总结
1、runkit.internal_override 是 PHP5.4 环境的救命方案,完美解决 override_function 必须 Debug 编译的痛点,是老旧PHP版本唯一稳定的内置函数劫持方案;
2、能力边界清晰:仅支持函数劫持,无法劫持 eval 等语法结构,能力弱于 uopz;
3、版本专一性强:仅适配 PHP5.x,PHP7+ 完全废弃,新旧环境需区分选型;
4、安全风险极高,老旧服务器极易被利用,生产环境务必关闭、卸载、禁用。
至此,PHP 全版本函数劫持三部曲(override_function / runkit / uopz)全部更新完毕,覆盖 PHP5~PHP8 所有环境的劫持原理、实战、踩坑、防护,欢迎收藏关注!