反序列化漏洞的危害稍微了解一点的都知道,如果能找到前端某处存在反序列化漏洞,那基本上距离拿下服务器仅一步之遥,这个时候我们可以通过继承ObjectInputFilter添加tFilter实现对所有反序列化类的校验,当然这个需要java的高版本才支持jep290,或者我们可以针对需要进行反序列化的接口对将要反序列化的数据进行过滤,这样可以防止如果我们通过全局设置导致项目代码出现未知问题,并且可以针对暴露点进行比较严格的校验。
可以通过设置jep290来对一些高危险的类进行过滤,再配合继承ObjectInputStream实现对反序列化数据的精准严格过滤,这样可以最大限度的保证服务器的安全。
我们可以通过实现继承ObjectInputStream来实现对序列化数据的过滤,代码如下:
package com.example.seriallzpayload.controller;
import java.io.*;
public class FilteringObjectInputStream extends ObjectInputStream {
private String[] forbidClasses;
public FilteringObjectInputStream(InputStream in) throws IOException {
super(in);
String[] stringArray = {
"java.net.URL",
"bsh.XThis",
"bsh.Interpreter",
"com.mchange.v2.c3p0.PoolBackedDataSource",
"com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase",
"clojure.lang.PersistentArrayMap",
"clojure.inspector.proxy$javax.swing.table.AbstractTableModel$ff19274a",
"org.apache.commons.beanutils.BeanComparator",
"org.apache.commons.collections.Transformer",
"org.apache.commons.collections.functors.ChainedTransformer",
"org.apache.commons.collections.functors.ConstantTransformer",
"org.apache.commons.collections.functors.InstantiateTransformer",
"org.apache.commons.collections.map.LazyMap",
"org.apache.commons.collections.functors.InvokerTransformer",
"org.apache.commons.collections.keyvalue.TiedMapEntry",
"org.apache.commons.collections4.comparators.TransformingComparator",
"org.apache.commons.collections4.functors.InvokerTransformer",
"org.apache.commons.collections4.functors.ChainedTransformer",
"org.apache.commons.collections4.functors.ConstantTransformer",
"org.apache.commons.collections4.functors.InstantiateTransformer",
"org.apache.commons.fileupload.disk.DiskFileItem",
"org.apache.commons.io.output.DeferredFileOutputStream",
"org.apache.commons.io.output.ThresholdingOutputStream",
"org.apache.wicket.util.upload.DiskFileItem",
"org.apache.wicket.util.io.DeferredFileOutputStream",
"org.apache.wicket.util.io.ThresholdingOutputStream",
"org.codehaus.groovy.runtime.ConvertedClosure",
"org.codehaus.groovy.runtime.MethodClosure",
"org.hibernate.engine.spi.TypedValue",
"org.hibernate.tuple.component.AbstractComponentTuplizer",
"org.hibernate.tuple.component.PojoComponentTuplizer",
"org.hibernate.type.AbstractType",
"org.hibernate.type.ComponentType",
"org.hibernate.type.Type",
"org.hibernate.EntityMode",
"com.sun.rowset.JdbcRowSetImpl",
"org.jboss.interceptor.builder.InterceptionModelBuilder",
"org.jboss.interceptor.builder.MethodReference",
"org.jboss.interceptor.proxy.DefaultInvocationContextFactory",
"org.jboss.interceptor.proxy.InterceptorMethodHandler",
"org.jboss.interceptor.reader.ClassMetadataInterceptorReference",
"org.jboss.interceptor.reader.DefaultMethodMetadata",
"org.jboss.interceptor.reader.ReflectiveClassMetadata",
"org.jboss.interceptor.reader.SimpleInterceptorMetadata",
"org.jboss.interceptor.spi.instance.InterceptorInstantiator",
"org.jboss.interceptor.spi.metadata.InterceptorReference",
"org.jboss.interceptor.spi.metadata.MethodMetadata",
"org.jboss.interceptor.spi.model.InterceptionType",
"org.jboss.interceptor.spi.model.InterceptionModel",
"sun.rmi.server.UnicastRef","sun.rmi.transport.LiveRef",
"sun.rmi.transport.tcp.TCPEndpoint",
"java.rmi.server.RemoteObject",
"java.rmi.server.RemoteRef",
"java.rmi.server.UnicastRemoteObject",
"sun.rmi.server.ActivationGroupImpl",
"sun.rmi.server.UnicastServerRef",
"org.springframework.aop.framework.AdvisedSupport",
"net.sf.json.JSONObject",
"org.jboss.weld.interceptor.builder.InterceptionModelBuilder",
"org.jboss.weld.interceptor.builder.MethodReference",
"org.jboss.weld.interceptor.proxy.DefaultInvocationContextFactory",
"org.jboss.weld.interceptor.proxy.InterceptorMethodHandler",
"org.jboss.weld.interceptor.reader.ClassMetadataInterceptorReference",
"org.jboss.weld.interceptor.reader.DefaultMethodMetadata",
"org.jboss.weld.interceptor.reader.ReflectiveClassMetadata",
"org.jboss.weld.interceptor.reader.SimpleInterceptorMetadata",
"org.jboss.weld.interceptor.spi.instance.InterceptorInstantiator",
"org.jboss.weld.interceptor.spi.metadata.InterceptorReference",
"org.jboss.weld.interceptor.spi.metadata.MethodMetadata",
"org.jboss.weld.interceptor.spi.model.InterceptionModel",
"org.jboss.weld.interceptor.spi.model.InterceptionType",
"org.python.core.PyObject",
"org.python.core.PyBytecode",
"org.python.core.PyFunction",
"org.mozilla.javascript.**",
"org.apache.myfaces.context.servlet.FacesContextImpl",
"org.apache.myfaces.context.servlet.FacesContextImplBase",
"org.apache.myfaces.el.CompositeELResolver",
"org.apache.myfaces.el.unified.FacesELContext",
"org.apache.myfaces.view.facelets.el.ValueExpressionMethodExpression",
"com.sun.syndication.feed.impl.ObjectBean",
"org.springframework.beans.factory.ObjectFactory",
"org.springframework.aop.framework.AdvisedSupport",
"org.springframework.aop.target.SingletonTargetSource",
"com.vaadin.data.util.NestedMethodProperty",
"com.vaadin.data.util.PropertysetItem"
};
String[] stringArray1 = {};
this.forbidClasses = stringArray;
}
@Override
protected Class> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
String className = desc.getName();
// 检查类名是否在不允许的类列表中
for (String forbidClass : forbidClasses) {
if (className.equals(forbidClass)) {
throw new InvalidClassException("Unauthorized deserialization attempt: " + className);
}
}
// 如果类名被允许,则使用默认的类解析逻辑
return super.resolveClass(desc);
}
}
其中的黑名单内容是根据ysoserial的调用链提取出来的,来源为如下地址:
https://github.com/mogwailabs/deserialization-filter-blacklists/blob/master/blacklist-filter.properties
由于大部分测试是否存在反序列化问题采用的是URLDNS攻击链,所以添加了对java.net.URL的过滤,代价就是不能调用URL类下的方法,需要注意。
代码原理就是我们通过重写了resolveClass方法,为什么要重写resolveClass,先看看源代码中哪里调用了resolveClass方法:
让数据首先进入我们的函数进行一次校验,这里严格点可以采用白名单校验,我这里采用黑名单校验,如果存在在列表中就抛出异常,否则就执行。
调用的时候我们只需要将序列化数据传入上述函数即可:
@RequestMapping(value = "/jep290")
public ModelAndView TryJep(HttpServletRequest request, HttpServletResponse response) throws Exception {
String filename= request.getParameter("filename");
// 进行反序列化操作
FileInputStream serializedData = new FileInputStream(filename);
FilteringObjectInputStream objIn = new FilteringObjectInputStream(serializedData);
Object obj = objIn.readObject();
serializedData.close();
ModelAndView mv = new ModelAndView();
mv.setViewName("index");
return mv;
}
当我们执行URLDNS序列化数据的时候,检测到存在调用java.net.URL就会报错:
代码很简单,最安全的是采用白名单,可以防止被绕过,通过继承 ObjectInputStream可以实现对接口的精准过滤,防止通过jep290过滤太严格影响代码的正常运行,毕竟后端服务器也有很多需要序列化的地方,所以两个配合才能更好的防御反序列化漏洞。