Java反序列化
slug
series-status
status
summary
date
series
type
password
icon
tags
category
Java反序列化
CC

工具
Burp
Yakit
- 压测
- jndi注入
log4j2
log4j引入了一个lookup接口,允许在写日志的时候,通过关键词去查找对象,输出对象,并实现对象功能。这个对象可以存储在硬盘中或者服务器上。 JNDI是lookup接口的一种思想,提供了命名关键词到目录的映射,允许开发者提供一个key,就可以得到对应的映射。 LDAP即JNDI中的一种底层实现,是轻量级目录访问协议,可以方便我们查询分布式数据库,所以允许从远程服务器上加载对象。 故log4j2存在注入漏洞,可以从远程服务器下载编译好的class恶意文件并执行。
绕过

Fastjson
首先,Fastjson提供了autotype功能,允许用户在反序列化数据中通过“@type”指定反序列化的类型。
其次,Fastjson自定义的反序列化机制时会调用指定类中的setter方法及部分getter方法,那么当组件开启了autotype功能并且反序列化不可信数据时,攻击者可以构造数据,使目标应用的代码执行流程进入特定类的特定setter或者getter方法中,若指定类的指定方法中有可被恶意利用的逻辑(也就是通常所指的“Gadget”),则会造成一些严重的安全问题。并且在Fastjson 1.2.47及以下版本中,利用其缓存机制可实现对未开启autotype功能的绕过。
三种利用链做分析和对比
JdbcRowSetImpl(JNDI注入)
总结:
- 实战可以利用,JDNI注入基于较低版本的JDK,LDAP适用范围更广
- 必须能出网,加载远端的恶意字节码,造成了局限性
绕过
dataSourceName
和autoCommit
在fastjson里会自动模糊化处理,所以可以通过大小写绕过。
autoCommit
写0或1也行
payload中的a对象用来当作缓存绕过,需要关注的是第二个对象
注意到其中
"autoCommit":true
,反序列化时,会反射设置属性,调用com.sun.rowset.JdbcRowSetImpl.setAutoCommit()
跟入
com.sun.rowset.JdbcRowSetImpl.connect()
,触发lookup
,加载远程恶意对象根据lookup到
com.sun.jndi.rmi.registry.RegistryContext.lookup()
跟入
decodeObject
方法,看到加载了远程Reference
绑定的恶意对象TemplateImpl(CC,没有实战价值)
修改了以下配置以后才能使用(因为对于传入的那些name、tfactory这些如果想要正常执行get、set方法的话,因为他们不是public,所以要开启这个开关才能用)
总结:
- TemplatesImpl类是Java反序列化界比较常用的类,更容易理解和上手
- 需要开启
Feature.SupportNonPublicField
,实战中不适用

注意其中的Payload来自于恶意类,该类应该继承自
com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet
类似第一条链,使用两个对象绕过,其中的Payload为恶意类的字节码再Base64编码的结果,给出简易的py脚本
该链需要开启
Feature.SupportNonPublicField
参数再反射设置属性,查看官方说明,如果某属性不存在set方法,但还想设置值时,需要开启该参数,这里的情况正好符合,而实际项目中很少出现这种情况,导致该链较鸡肋,没有实际的意义(其实TemplateImpl
类中有set方法,比如setTransletBytecodes
,但是名称和Bytecodes
不一致)在
com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer.parseField
设置属性时会有判断反序列化时,fastjson中会把”_”开头的属性替换为空。并在
outputProperties
设置值时调用getOutputProperties
调用到
com.sun.org.apache.xalan.internal.xsltc.trax.newTransformer
方法跟入
getTransletInstance
再跟入
defineTransletClasses
,对父类进行了验证,这样解释了为什么Payload恶意类要继承自该类。如果验证没有问题,将在上方的newInstance
方法中实例化该类,造成RCE为什么
_bytescode
要对字节码进行base64编码?反序列化的过程中会调用很多类,在经过该类com.alibaba.fastjson.serializer.ObjectArrayCodec.deserialze
的时候,会对字段进行一次base64的解码跟入
lexer.bytesValue()
方法,看到decodeBase64
BasicDataSource(不出网,本地动态类加载,getter)
总结:
- 不需要出网,不需要开启特殊的参数,适用范围较广
- 目标需要引入tomcat依赖,虽说比较常见,但也是一种限制

这个Payload适用于1.2.37版本,并且需要导入Tomcat相关的包
生成
driverClassName
的工具如下关于
com.sun.org.apache.bcel.internal.util.ClassLoader
参考P师傅(phith0n)的《Java安全漫谈》BCEL的全名是Apache Commons BCEL,Apache Commons项目下的一个子项目,包含在JDK的原生库中。我们可以通过BCEL提供的两个类 Repository 和 Utility 来利用: Repository 用于将一个Java Class先转换成原生字节码,当然这里也可以直接使用javac命令来编译java文件生成字节码; Utility 用于将原生的字节码转换成BCEL格式的字节码。
将这种格式的字符串,作为“字节码”传入
new ClassLoader().loadClass(code).newInstance();
将会被实例化,当我们在Fastjson反序列化中构造出这种链,将会造成反序列化漏洞回到Payload,开头一部分用于绕Fastjson黑白名单,没有什么特殊的意义,核心部分如下:
这个版本利用的是
$ref
这个特性:当fastjson版本>=1.2.36时,我们可以使用$ref
的方式来调用任意的getter,比如这个Payload调用的是x.y.c.connection
,x是这个大对象,最终调用的是c对象的connection方法,也就是BasicDataSource.connection
参考代码
com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer.deserialze:591
漏洞的触发点在
com.alibaba.fastjson.JSON.parse:154
跟入
com.alibaba.fastjson.parser.DefaultJSONParser.handleResovleTask:1465
跟入
JSONPath.eval
,这里的segement
数组中的是[x,y,c,connection]
到达
com.alibaba.fastjson.JSONPath:1350
继续跟入
path.getPropertyValue
跟入
com.alibaba.fastjson.serializer.JavaBeanSerializer:439
跟入
com.alibaba.fastjson.serializer.FieldSerializer:145
到达
com.alibaba.fastjson.util.FieldInfo
,达到最终触发点:method.invoke
看到这里的javaObject正是
BasicDataSouce

回到
BasicDataSource
本身最终触发点,其中
driverClassName
和driverClassLoader
都是可控的,由用户输入,指定ClassLoader为com.sun.org.apache.bcel.internal.util.ClassLoader
,设置ClassName为BCEL...
这种格式后,在newInstance
方法执行后被实例化。第二个参数initial
为true时,类加载后将会直接执行static{}
块中的代码。高版本绕过
< 1.2.41
第一个Fastjson反序列化漏洞爆出后,阿里在1.2.25版本设置了autoTypeSupport属性默认为false,并且增加了checkAutoType()函数,通过黑白名单的方式来防御Fastjson反序列化漏洞,因此后面发现的Fastjson反序列化漏洞都是针对黑名单绕过来实现攻击利用的目的的。
com.sun.rowset.jdbcRowSetlmpl在1.2.25版本被加入了黑名单,fastjson有个判断条件判断类名是否以"L"开头、以";"结尾,是的话就提取出其中的类名在加载进来
那么就可以构造如下exp
< 1.2.42
阿里在发现这个绕过漏洞之后做出了类名如果为
L
开头,;结尾的时候就先去掉L
和;
进行黑名单检验的方法,但是没有考虑到双写或多写的情况,也就是说这种方法只能防御一组L
和;
,构造exp如下,即双写L
和;
< 1.2.47
在1.2.47版本及以下的情况下,loadClass中默认cache为true,首先使用java.lang.Class把获取到的类缓存到mapping中,然后直接从缓存中获取到了com.sun.rowset.jdbcRowSetlmpl这个类,即可绕过黑名单
< 1.2.66
基于黑名单绕过,autoTypeSupport属性为true才能使用,在1.2.25版本之后autoTypeSupport默认为false
Shiro550
Struts2
OGNL表达式注入
payload:
Loading...