PHP老版本劫持神器:runkit.internal_override 彻底解决 PHP5.4 函数重写问题

17次阅读
没有评论

大家好,本篇继续更新 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");
?>

运行逻辑解析

  1. 开启 runkit.internal_override 后,用户自定义函数可直接覆盖内置函数;
  2. 精准拦截高危命令,普通业务命令正常放行,无业务侵入;
  3. 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 所有环境的劫持原理、实战、踩坑、防护,欢迎收藏关注!

正文完
可以使用微信扫码关注公众号(ID:xzluomor)
post-qrcode
 0
评论(没有评论)
验证码