JEP 290
JEP:JDK Enhancement Proposal JDK增强建议 ;JEP是一个JDK核心技术相关的增强建议文档
JEP 290主要解决反序列化安全问题。 JEP 290 在 JDK 9 中加入,但在 JDK 6,7,8 一些高版本中也添加了
Java™ SE Development Kit 8, Update 121 (JDK 8u121)
Java™ SE Development Kit 7, Update 131 (JDK 7u131)
Java™ SE Development Kit 6, Update 141 (JDK 6u141)
JEP主要通过
(1)提供一个限制反序列化类的机制,白名单或者黑名单
(2)限制反序列化的深度和复杂度
(3)为RMI远程调用对象提供了一个验证类的机制
(4)定义一个可配置的过滤机制,比如可以通过配置properties文件的形式来定义过滤器
下面通过运行两个jdk版本运行rmi例子做对比验证
rmi例子
1.定义rmi接口
import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
public interface Hello extends Remote {
String hello() throws RemoteException;;
String hello(String name) throws RemoteException;;
String hello(Object object) throws RemoteException;;
}
2.实现接口
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
public class HelloImpl extends UnicastRemoteObject implements Hello {
protected HelloImpl() throws RemoteException {
}
@Override
public String hello() {
return "Hello world";
}
@Override
public String hello(String name) {
return "Hello world"+name;
}
@Override
public String hello(Object object) {
System.out.println(object);
return "Hello world"+object.toString();
}
}
3.注册服务,绑定接口在端口上
import java.io.ObjectInputStream;
import java.rmi.Naming;
import java.rmi.registry.LocateRegistry;
public class RMIServier {
public static String HOST = "127.0.0.1";
public static int PORT = 1099;
public static String RMI_PATH = "/hello";
public static final String RMI_NAME = "rmi://" + HOST + ":" + PORT + RMI_PATH;
public static void main(String[] args) {
try {
// 注册RMI端口
LocateRegistry.createRegistry(PORT);
// 创建一个服务
Hello hello = new HelloImpl();
// 服务命名绑定
Naming.rebind(RMI_NAME, hello);
System.out.println("启动RMI服务:" + RMI_NAME);
// ObjectInputStream o;
} catch (Exception e) {
e.printStackTrace();
}
}
}
下面通过运行两个不同jdk版本运行rmi例子做对比验证
当jdk 为1.7u80
输入java -cp ysoserial.jar ysoserial.exploit.RMIRegistryExploit 127.0.0.1 1099 CommonsCollections1 calc
就会弹出计算器
当Jdk为1.8u151
输入命令java -cp ysoserial.jar ysoserial.exploit.RMIRegistryExploit 127.0.0.1 1099 CommonsCollections1 calc
就会显示
十二月 07, 2022 1:53:20 下午 java.io.ObjectInputStream filterCheck
信息: ObjectInputFilter REJECTED: class sun.reflect.annotation.AnnotationInvocationHandler, array length: -1, nRefs: 8, depth: 2, bytes: 297, ex: n/a
JEP290实现对反序列化漏洞进行预防呢
JEP 290 进行过滤的具体实现方法是在 objectInputStream 类中增加了一个serialFilter属性和一个 filterChcek 函数,两者搭配来实现过滤的
每当进行一次反序列化操作时,底层就会根据filter中的内容来进行判断,从而防止恶意的类进行反序列化操作。此外,还可以限制反序列化数据的信息,比如数组的长度、字节流长度、字节流深度以及使用引用的个数等。filter返回accept,reject或者undecided几个状态,然后用户根据状态进行决策
ObjectInputStream这是Java.io中一个输入流,
public ObjectInputStream(InputStream in) throws IOException {
verifySubclass();
bin = new BlockDataInputStream(in);
handles = new HandleTable(10);
vlist = new ValidationList();
serialFilter = ObjectInputFilter.Config.getSerialFilter();//获取配置文件序列化配置
enableOverride = false;
readStreamHeader();
bin.setBlockDataMode(true);
}
private void filterCheck(Class<?> clazz, int arrayLength)
throws InvalidClassException {
if (serialFilter != null) {
RuntimeException ex = null;
ObjectInputFilter.Status status;
try {
status = serialFilter.checkInput(new FilterValues(clazz, arrayLength,
totalObjectRefs, depth, bin.getBytesRead()));
} catch (RuntimeException e) {
// Preventive interception of an exception to log
status = ObjectInputFilter.Status.REJECTED;
ex = e;
}
if (status == null ||
status == ObjectInputFilter.Status.REJECTED) {
// Debug logging of filter checks that fail
if (Logging.infoLogger != null) {
Logging.infoLogger.info(
"ObjectInputFilter {0}: {1}, array length: {2}, nRefs: {3}, depth: {4}, bytes: {5}, ex: {6}",
status, clazz, arrayLength, totalObjectRefs, depth, bin.getBytesRead(),
Objects.toString(ex, "n/a"));
}
InvalidClassException ice = new InvalidClassException("filter status: " + status);
ice.initCause(ex);
throw ice;
} else {
// Trace logging for those that succeed
if (Logging.traceLogger != null) {
Logging.traceLogger.finer(
"ObjectInputFilter {0}: {1}, array length: {2}, nRefs: {3}, depth: {4}, bytes: {5}, ex: {6}",
status, clazz, arrayLength, totalObjectRefs, depth, bin.getBytesRead(),
Objects.toString(ex, "n/a"));
}
}
}
}
可以通过配置文件设置一个黑白名单,允许(禁止)哪些类反序列化
(1)通过设置jdk.serialFilter这个System.property
(2)直接通过conf/security/java.properties文件进行配置
绕过jep290以及分析具体过滤代码就暂时不想看了
参考:https://cloud.tencent.com/developer/article/1850810
https://nosec.org/home/detail/4846.html
https://paper.seebug.org/454/
https://blog.csdn.net/u011721501/article/details/78555246
这也是22年学习java安全过程中搜集相关资料,然后实践过相关内容,仅作学习记录
原文始发于微信公众号(天才少女Alpha):JEP290
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论