最近有一篇写的很好的关于java17反序列化绕过模块化的文章:https://mp.weixin.qq.com/s/DrUUAJaLig_RtXZWaAm1IQ
关于本篇的方式方法也比较传统,直接jep290在java运行时增加命令行参数:
-Djdk.serialFilter=!com.sun.org.apache.xalan.internal.xsltc.**
有没有办法在反射时也能限制对TemplatesImpl的反射呢?可以使用如下java代码
import jdk.internal.reflect.Reflection;
import之后在反射形成反序列化链之前限制对TemplatesImpl的反射,如下
Reflection.registerMethodsToFilter(TemplatesImpl.class, Set.of("*"));
Reflection.registerFieldsToFilter(TemplatesImpl.class, Set.of("*"));
增加完之后发现系统提示:
Exception in thread "main" java.lang.IllegalAccessError: class SerializeJDK8 (in unnamed module @0x6d311334) cannot access class jdk.internal.reflect.Reflection (in module java.base) because module java.base does not export jdk.internal.reflect to unnamed module @0x6d311334at SerializeJDK8.main(SerializeJDK8.java:20)
所以我们要在java进程执行时增加vm参数:
--add-opens=java.base/jdk.internal.reflect=ALL-UNNAMED
其中我们要看一下Reflection的源代码:
static {fieldFilterMap = Map.of(Reflection.class, ALL_MEMBERS,AccessibleObject.class, ALL_MEMBERS,Class.class, Set.of("classLoader", "classData", "modifiers", "protectionDomain", "primitive"),ClassLoader.class, ALL_MEMBERS,Constructor.class, ALL_MEMBERS,Field.class, ALL_MEMBERS,Method.class, ALL_MEMBERS,Module.class, ALL_MEMBERS);methodFilterMap = Map.of();
}
Reflection的所有字段被限制反射了,但是方法却没有,所以还可以把上述代码增加一下改成:
Reflection.registerMethodsToFilter(TemplatesImpl.class, Set.of("*"));
Reflection.registerFieldsToFilter(TemplatesImpl.class, Set.of("*"));
Reflection.registerMethodsToFilter(Reflection.class, Set.of("*"));
防止对Reflection的方法进行随意反射减少未知绕过的可能性
上述代码在java8中略有不同,代码如下:
Reflection.registerMethodsToFilter(TemplatesImpl.class, Set.of("readObject","writeObject"));
Reflection.registerFieldsToFilter(TemplatesImpl.class, Set.of("_bytecodes"));
Reflection.registerMethodsToFilter(Reflection.class, Set.of("*"));
总结:
1)反序列化时对流进行反序列校验增加未知漏洞的防护
2)反射限制可以增加对未知的反射导致0day的防护能力
3)参照:https://alibaba.github.io/fastjson2/autotype_cn.html 对输入的校验使用白名单是目前已知最好的编码方式