PHP 5.2.3 在 CGI 请求处理中暴露了一个经典的安全缺陷——由于编程时一个细微的疏忽(缺少括号),导致字符串长度计算错误,最终引发堆缓冲区溢出。攻击者若成功利用该漏洞,完全可能实现远程代码执行。这看似是个老生常谈的“括号血案”,但在当时的环境中,其破坏力不可小觑。
那么,这个漏洞具体是如何触发的?在配置好 PHP 与 CGI 的映射后,攻击者只需发送类似 GET /test.php/aa HTTP/1.1 的请求即可触发。问题代码位于 php-5.2.3\sapi\cgi\cgi-main.c 的第 886 行:
int path_translated_len = ptlen + env_path_info ? strlen(env_path_info) : 0;
注意到问题了吗?由于运算符优先级的关系,这行代码实际上被解析为 (ptlen + env_path_info) ? strlen(env_path_info) : 0,而非原作者意图的 ptlen + (env_path_info ? strlen(env_path_info) : 0)。少了这对括号,整个逻辑就完全偏离了预期。
现在回顾一下整个处理流程。程序从 main() 开始,调用 init_request_info(TSRMLS_C)。在 init_request_info 函数内部,使用上述错误表达式计算 path_translated_len,然后通过 emalloc(path_translated_len + 1) 分配堆内存。最关键的一步在后面:
if (env_path_info) {
memcpy(path_translated + ptlen, env_path_info, path_translated_len - ptlen);
}
由于 path_translated_len 的计算值远大于实际所需长度(因为 ptlen + env_path_info 是一个指针加法,结果是一个很大的地址值),memcpy 复制的数据量远远超出了实际缓冲区容量,从而引发堆缓冲区溢出。攻击者精心构造的 env_path_info 内容,有可能改写堆上的关键数据结构,进而劫持执行流程。
值得强调的一点是:这类错误在实际开发中并不罕见,但常因运算符优先级和括号缺失而悄然潜伏。PHP 5.2.3 的这个案例,堪称教科书级的“括号缺失引发的安全危机”,也是后来许多静态代码审查工具重点检测的模式之一。从历史的角度看,它提醒我们:即使是最细微的语法疏忽,也有可能被攻击者盯上,成为突破口。
