Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CLI improvements #45

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 102 additions & 14 deletions src/main/java/ysoserial/GeneratePayload.java
Original file line number Diff line number Diff line change
@@ -1,29 +1,61 @@
package ysoserial;

import java.io.File;
import java.io.FileInputStream;
import java.io.PrintStream;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

import ysoserial.payloads.ObjectPayload;
import ysoserial.payloads.ObjectPayload.Utils;
import ysoserial.Serializer.Format;
import ysoserial.annotation.Bind;
import ysoserial.interfaces.ObjectPayload;
import ysoserial.payloads.Utils;
import ysoserial.payloads.annotation.Dependencies;

@SuppressWarnings("rawtypes")
public class GeneratePayload {

private static final int INTERNAL_ERROR_CODE = 70;

private static final int USAGE_CODE = 64;

public static class ToStringComparator implements Comparator<Object> {
public int compare(Object o1, Object o2) { return o1.toString().compareTo(o2.toString()); }
}

public static void main(final String[] args) {
if (args.length != 2) {
if (args.length < 1) {
printUsage();
System.exit(USAGE_CODE);
}
final String payloadType = args[0];
final String command = args[1];
Format format = Format.Raw;

int genArgs = 0;
// Find generator args (as opposed to payload args)
for( int i = 0; i < args.length; i++ ) {
if ( !args[i].startsWith( "-" ) ) {
break;
}

if ( args[i].equals( "-raw" ) ) {
format = Format.Raw;
} else if ( args[i].equals( "-hex" ) ) {
format = Format.Hex;
} else if ( args[i].equals( "-base64" ) ) {
format = Format.Base64;
}

genArgs++;
}

final String payloadType = args[genArgs++];

final Class<? extends ObjectPayload> payloadClass = Utils.getPayloadClass(payloadType);
if (payloadClass == null) {
Expand All @@ -32,13 +64,24 @@ public static void main(final String[] args) {
System.exit(USAGE_CODE);
return; // make null analysis happy
}


String[] newArgs = new String[ args.length - genArgs ];
System.arraycopy( args, genArgs, newArgs, 0, newArgs.length );

try {
final ObjectPayload payload = payloadClass.newInstance();
final Object object = payload.getObject(command);
PrintStream out = System.out;
Serializer.serialize(object, out);
ObjectPayload.Utils.releasePayload(payload, object);
try {
final ObjectPayload payload = payloadClass.newInstance();
Utils.wire( payload, newArgs );

final Object object = payload.getObject();
PrintStream out = System.out;
Serializer.serialize(object, out, format);
Utils.releasePayload(payload, object);
} catch( IllegalArgumentException e ) {
System.err.println( "Invalid arguments for payload type '" + payloadType + "'" );
printHelp( payloadClass );
}
} catch (Throwable e) {
System.err.println("Error while generating or serializing payload");
e.printStackTrace();
Expand All @@ -47,20 +90,65 @@ public static void main(final String[] args) {
System.exit(0);
}

private static void printHelp(Class<? extends ObjectPayload> payloadClass) throws Exception {
System.err.println( "Y SO SERIAL?" );
System.err.println("Usage: java -jar ysoserial-[version]-all.jar [format] " + payloadClass.getSimpleName() + " [params...]");
System.err.println( "Available formats: -raw, -hex, -base64" );
System.err.println( "Parameters for this payload type: " );

Set<String> params = new TreeSet<String>();

Class<?> cls = payloadClass;
while( cls != null ) {
for( Field f : cls.getDeclaredFields() ) {
if ( f.getAnnotation( Bind.class ) != null ) {
Bind binding = f.getAnnotation( Bind.class );
params.add( f.getName() + " [" + type(f) + "]: " + binding.helpText() );
}
}

cls = cls.getSuperclass();
}

for( String s : params ) {
System.err.println( " * " + s );
}
}

private static void printUsage() {
System.err.println("Y SO SERIAL?");
System.err.println("Usage: java -jar ysoserial-[version]-all.jar [payload type] '[command to execute]'");
System.err.println("Usage: java -jar ysoserial-[version]-all.jar [format] payload_type [params...]");
System.err.println( "Available formats: -raw, -hex, -base64" );
System.err.println("\tAvailable payload types:");
final List<Class<? extends ObjectPayload>> payloadClasses =
new ArrayList<Class<? extends ObjectPayload>>(ObjectPayload.Utils.getPayloadClasses());
new ArrayList<Class<? extends ObjectPayload>>(Utils.getPayloadClasses());
Collections.sort(payloadClasses, new ToStringComparator()); // alphabetize
for (Class<? extends ObjectPayload> payloadClass : payloadClasses) {
System.err.println("\t\t" + payloadClass.getSimpleName() + " " + Arrays.asList(Dependencies.Utils.getDependencies(payloadClass)));
}
}

public static class ToStringComparator implements Comparator<Object> {
public int compare(Object o1, Object o2) { return o1.toString().compareTo(o2.toString()); }
private static String type(Field f) {
Class<?> type = f.getType();
if ( type.equals( String.class ) ) {
return "string";
} else if ( type.equals( URL.class ) ) {
return "url";
} else if ( type.equals( Integer.TYPE ) ) {
return "number";
} else if ( type.equals( Long.TYPE ) ) {
return "number";
} else if ( type.equals( Boolean.TYPE ) ) {
return "boolean";
} else if ( type.equals( File.class ) ) {
return "filename";
} else if ( type.equals( FileInputStream.class ) ) {
return "filename";
} else if ( type.equals( ObjectPayload.class ) || ObjectPayload.class.isAssignableFrom( type ) ) {
return "payload name";
}

return "unknown";
}

}
29 changes: 25 additions & 4 deletions src/main/java/ysoserial/Serializer.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,23 @@
package ysoserial;

import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.util.concurrent.Callable;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;

public class Serializer implements Callable<byte[]> {

public static enum Format {
Hex,
Raw,
Base64
}

private final Object object;
public Serializer(Object object) {
this.object = object;
Expand All @@ -18,13 +29,23 @@ public byte[] call() throws Exception {

public static byte[] serialize(final Object obj) throws IOException {
final ByteArrayOutputStream out = new ByteArrayOutputStream();
serialize(obj, out);
serialize(obj, out, Format.Raw );
return out.toByteArray();
}

public static void serialize(final Object obj, final OutputStream out) throws IOException {
final ObjectOutputStream objOut = new ObjectOutputStream(out);
objOut.writeObject(obj);
public static void serialize(final Object obj, final OutputStream out, Format format) throws IOException {
if ( format.equals( Format.Raw ) ) {
final ObjectOutputStream objOut = new ObjectOutputStream(out);
objOut.writeObject(obj);
} else {
byte[] bytes = serialize( obj );
DataOutputStream dos = new DataOutputStream( out );
if ( format.equals( Format.Base64 ) ) {
dos.write( Base64.encodeBase64(bytes, false) );
} else if ( format.equals( Format.Hex ) ) {
dos.writeBytes( Hex.encodeHexString( bytes ) );
}
}
}

}
49 changes: 49 additions & 0 deletions src/main/java/ysoserial/annotation/Bind.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package ysoserial.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

@Retention( RetentionPolicy.RUNTIME )
@Target( { ElementType.FIELD, ElementType.TYPE } )
public @interface Bind {

/**
* All allowed String values for this Bind variable. If not populated, or empty, the wiring
* code will allow all values.
*/
String[] allowed() default {};

/**
* If this is an ObjectPayload variable, this specifies the allowed types of payloads. For other
* types, this value is ignored. Classes not tagged with a type will be assumed to be type
* Remote_Code_Execution.
*/
PayloadTypes.Type[] allowedTypes() default {};

/**
* The default value for this Bind variable, which effectively makes it
* optional if populated. Any fields not populated by command line switches
* will be populated by their default values.
*/
String defaultValue() default "";

/**
* Any forbidden String values for this Bind variable
*/
String[] forbidden() default {};

/**
* If this is an ObjectPayload variable, this specifies the forbidden types of payloads. For other
* types, this value is ignored.
*/
PayloadTypes.Type[] forbiddenTypes() default {};

/**
* Printed if the payload or exploit is not validly used
*/
String helpText() default "";


}
16 changes: 16 additions & 0 deletions src/main/java/ysoserial/annotation/PayloadTypes.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package ysoserial.annotation;

public @interface PayloadTypes {

public static enum Type {
Code_Injection,
Denial_of_Service,
Remote_Code_Execution,
Reverse,
Shell,
Wrapper
}

Type[] value() default {};

}
9 changes: 5 additions & 4 deletions src/main/java/ysoserial/exploit/JBoss.java
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
import org.xnio.ssl.JsseXnioSsl;
import org.xnio.ssl.XnioSsl;

import ysoserial.payloads.ObjectPayload.Utils;
import ysoserial.payloads.Utils;


/**
Expand Down Expand Up @@ -100,13 +100,14 @@ public class JBoss {
public static void main ( String[] args ) {

if ( args.length < 3 ) {
System.err.println("Usage " + JBoss.class.getName() + " <uri> <payload> <payload_arg>");
System.err.println("Usage " + JBoss.class.getName() + " <uri> <payload> <payload_args...>");
System.exit(-1);
}

URI u = URI.create(args[ 0 ]);

final Object payloadObject = Utils.makePayloadObject(args[1], args[2]);

String[] payloadArgs = Utils.trimArgs( args, 2 );
final Object payloadObject = Utils.makePayloadObject(args[1], payloadArgs);

String username = null;
String password = null;
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/ysoserial/exploit/JRMPClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
import javax.net.SocketFactory;

import sun.rmi.transport.TransportConstants;
import ysoserial.payloads.ObjectPayload.Utils;
import ysoserial.payloads.Utils;


/**
Expand All @@ -35,11 +35,11 @@ public class JRMPClient {

public static final void main ( final String[] args ) {
if ( args.length < 4 ) {
System.err.println(JRMPClient.class.getName() + " <host> <port> <payload_type> <payload_arg>");
System.err.println(JRMPClient.class.getName() + " <host> <port> <payload_type> <payload_args>");
System.exit(-1);
}

Object payloadObject = Utils.makePayloadObject(args[2], args[3]);
Object payloadObject = Utils.makePayloadObject(args[2], Utils.trimArgs(args, 3));
String hostname = args[ 0 ];
int port = Integer.parseInt(args[ 1 ]);
try {
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/ysoserial/exploit/JRMPListener.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
import javassist.ClassPool;
import javassist.CtClass;
import sun.rmi.transport.TransportConstants;
import ysoserial.payloads.ObjectPayload.Utils;
import ysoserial.payloads.Utils;
import ysoserial.payloads.util.Reflections;


Expand Down Expand Up @@ -104,12 +104,12 @@ public void close () {
public static final void main ( final String[] args ) {

if ( args.length < 3 ) {
System.err.println(JRMPListener.class.getName() + " <port> <payload_type> <payload_arg>");
System.err.println(JRMPListener.class.getName() + " <port> <payload_type> <payload_args>");
System.exit(-1);
return;
}

final Object payloadObject = Utils.makePayloadObject(args[ 1 ], args[ 2 ]);
final Object payloadObject = Utils.makePayloadObject(args[ 1 ], Utils.trimArgs( args, 2) );

try {
int port = Integer.parseInt(args[ 0 ]);
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/ysoserial/exploit/JSF.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

import org.apache.commons.codec.binary.Base64;

import ysoserial.payloads.ObjectPayload.Utils;
import ysoserial.payloads.Utils;


/**
Expand All @@ -37,11 +37,11 @@ public class JSF {
public static void main ( String[] args ) {

if ( args.length < 3 ) {
System.err.println(JSF.class.getName() + " <view_url> <payload_type> <payload_arg>");
System.err.println(JSF.class.getName() + " <view_url> <payload_type> <payload_args..>");
System.exit(-1);
}

final Object payloadObject = Utils.makePayloadObject(args[ 1 ], args[ 2 ]);
final Object payloadObject = Utils.makePayloadObject(args[ 1 ], Utils.trimArgs( args, 2 ));

try {
URL u = new URL(args[ 0 ]);
Expand Down
Loading