九维团队-绿队(改进)| 服务攻防-FastJson框架渗透总结(一)
文章
导览
因本文篇幅较长,将会拆分为上下两篇内容发出。文章内容概览如下:
一、FastJson 简介
二、Java反序列化-JNDI注入
1、什么是JNDI
2、利用JNDI References进行注入
三、自搭建FastJson
1、IDEA自动加载fastjson_jra包
2、安装jdk1.8.0_171
3、安装IDEA
4、新建java项目
5、方法1:手动导入jar包
6、方法2:IDEA_pom加载fastjson.jar包并运行
7、编辑fastjson代码并运行测试
8、IDEA搭建spring+fastjson(windows环境)
9、IDEA认识断点Fastjson(Debug)
四、FastJson渗透总结
1、fastjson 1.2.24 反序列化导致任意命令执行漏洞(CVE-2017-18349)
1)漏洞介绍
2)漏洞环境准备
3)漏洞复现
4)DNSLog回显测试漏洞
5)RMI调用和java版本问题
6)反弹shell
2、windows环境使用IDEA详细复现fastjson 1.2.24反序列化漏洞
1)创建测试项目
2)启动springbooot验证是否存在fastjson反序列化漏洞
3、Fastjson 1.2.47远程命令执行漏洞
1)漏洞简介
2)漏洞环境准备
3)漏洞复现
4)反弹shell方法
4、windows环境使用IDEA详细复现fastjson 1.2.47反序列化漏洞
1)环境准备
2)漏洞复现
5、fastjson 1.2.80版本反序列化漏洞本地测试
1)漏洞描述
2)影响版本
3)准备环境
6、fastjson 不出网利用总结
1)漏洞简介
2)漏洞分析
3)com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl方法利用
4)org.apache.tomcat.dbcp.dbcp2.BasicDataSource 方法利用
五、Fastjson漏洞机制分析
1、fastjosn <= 1.2.24漏洞
2、fastjson <= 1.2.41漏洞
3、fastjson <= 1.2.42漏洞
4、fastjson <= 1.2.45漏洞
5、fastjson <= 1.2.47漏洞
6、fastjson <= 1.2.50漏洞
7、fastjson <= 1.2.62漏洞
8、fastjson <= 1.2.62漏洞
9、fastjson <= 1.2.68漏洞
一、FastJson 简介
FastJson是一个java语言编写的高性能功能完善的JSON库。它采用“假定有序快速匹配“算法,把json parse的性能提升到了极致,是目前java语言中最快的json库。fastjson接口简单易用,已经被广泛在缓存序列化、协议交互、web输出、Android客户端等多种应用场景,下图是fsatjson组件的反序列化流程。
https://github.com/alibaba/fastjson
Fastjson解析复杂的数据包:
二、Java反序列化-JNDI注入
1、什么是JNDI
简单来说JNDI(java Naming and Directory Interface)是一组应用程序接口,他为开发人员查找和访问各种资源提供统一的通用的接口,可以用来定位用户、网络、机器、对象和服务等资源。
比如可以利用JNDI在局域网上定位一台打印机,也可以用JNDI来定位数据库服务或一个远程java对象,JNDI底层支持RMI远程对象,RMI注册的服务可以通过JNDI接口来访问和调用。
JNDI是应用程序设计的API、JNDI可以根据名字动态加载数据、支持的服务主要有以下几种:DNS、LDAP、CORBA对象服务、RMI。
2、利用JNDI References进行注入
如何利用JNDI References进行注入,现在开始了解RMI的作用。
首先RMI服务端除了可以直接绑定远程对象之外,还可以通过references类来绑定一个外部远程对象,当RMI绑定了References之后,首先会利用 Referenceable.getRenferce() 获取绑定对象的引用,并且在目录中保存(简单理解就是在Registry中保存远程对象的引用)。
当客户端使用lookup获取对应名字的时候,会返回ReferenceWrapper类的代理文件,然后会调用getReference()获取Refence类,最终通过Factory类将Reference转换为具体的对象实例。
客户端:
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
public class JNDIClient {
public static void main(String[] args) throws Exception{
try {
Context ctx = new InitialContext();
ctx.lookup("rmi://localhost:8000/refObj");
}
catch (NamingException e) {
e.printStackTrace();
}
}
}
*左右滑动查看更多
服务端:
import com.sun.jndi.rmi.registry.ReferenceWrapper;
import javax.naming.Reference;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
public class RMIServer {
public static void main(String args[]) throws Exception {
//regerence需要传入三个参数(className,factory,factoryLoaction)
//第一个参数随意填写即可,第二个参数填写我们http服务下的类名,第三个服务填写我们的远程地址
Registry registry = LocateRegistry.createRegistry(1099);
Reference refObj = new Reference("Evil", "EvilObject","http://127.0.0.1:8000/");
//ReferenceWrapper包裹Referencel类,使其能够通过RMI进行远程访问
ReferenceWrapper refObjWrapper = new ReferenceWrapper(refObj);
registry.bind("refObj", refObjWrapper);
}
}
在ReferenceWrapper 源码中不难看出,该类继承自UnicastRemoteObject,实现Reference进行包裹从而让Reference使其能够通过RMI进行远程访问。
上面是正常加载的流程,那么从安全学习者的角度考虑我们如何操作才能让客户端进行命令执行?
如果我们可以控制JNDI客户端中传入的URL,那么我们是不是可以自己启动一个恶意的RMI,让JNDI来加载我们恶意类从而进行命令执行。
首先来看一下References,References类有两个属性,className和codebase url,className就是远程引用的类名,codebase决定了我们远程类的位置,当本地classpath中没有找到对应的类的时候,就会去请求对应codebase地址下的类(codebase支持http协议),那么我们将codebase 地址下的类替换成我们的恶意类,这样我们就能让客户端执行命令了。
ps:在java版本大于1.8U191之后版本存在truestCodebaseURL限制,只信任已有的codebase地址,不在能够从远程地址加载类。
所以整个流程如下:
1、首先开启HTTP服务,并将我们的恶意类放在目录下。
2、开启恶意RMI服务器。
3、攻击者控制URL参数为上一步开启的而已RMI服务器地址。
4、恶意RMI服务器返回ReferenceWrapper类。
5、目标(JNDI_Client)在执行lookup操作的时候,在decode0ject中将ReferenceWrapper变成Reference类,然后远程加载并实例化我们的Factory类(即远程加载我们HTTP服务器上的恶意类),在实例化时触发静态代码片段中的恶意代码。
三、自搭建FastJson
1、IDEA自动加载fastjson_jra包
https://mvnrepository.com/artifact/com.alibaba/fastjson
*左右滑动查看更多2、安装jdk1.8.0_171
ps:只要是版本小于1.8U191就可以。
3、安装IDEA
这里我们选择体验三十天:
点击新建,设置jdk:
4、新建java项目
5、方法1:手动导入jar包
创建文件夹,名为lib:
导入jastjson-1.2.24.jar包:
将fastjson放在lib文件夹里面:
选择jar包:
应用完点击OK即可!
6、方法2:IDEA_pom加载fastjson.jar包并运行
这里有maven的导入方式:
代码添加到pom.xml中:
<dependencies>
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.24</version>
</dependency>
</dependencies>
*左右滑动查看更多保存后,刷新导入:
正在下载中,最后会导入成功:
7、编辑fastjson代码并运行测试
不同于java反序化,fastjson的序列化有其自身特点,我们通过一些小的demo来展示如何使用fastjson。我们常说jastjson的序列化就是将java对象转化为json字符串,而反序列化就是将json字符串转化为java对象。
fastjson序列化demo:
将java目录下创建一个测试用的java文件。
public static void main(String[] args){
}
再将fastjson序列化内容填入:
User user = new User();
user.setName("张三");
user.setAge(18);
String jsonStr = JSON.toJSONString(user);
System.out.print(jsonStr);
添加User类
public class User {
//设置私有类
private String name;
private Integer age;
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
public Integer getAge(){
return age;
}
public void setAge(Integer age){
this.age = age;
}
@Override
public String toString(){
return "User{" + "name=" + name +'\'' + ", age" + age + '}';
}
}
*左右滑动查看更多现在在Test中还是有报错,我们这里需要调用json:
调用JSON
import com.alibaba.fastjson.JSON;
*左右滑动查看更多运行java,查看输入:
8、IDEA搭建spring+fastjson(windows环境)
创建一个新项目:
点击下一步,选择web-spring web:
等待下载spring包:
导入fastjson的jar包:
在com.example目录下创建class文件:
写入调用函数:
package com.example.demo1;
import com.alibaba.fastjson.JSON;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
*左右滑动查看更多引入调用前面的函数:
public String enentest(){
}
再把之前的数据拷贝过来:
User user = new User();
user.setName("张三");
user.setAge(18);
String jsonStr = JSON.toJSONString(user);
*左右滑动查看更多再把User文件拷贝出来
加个return:
return jsonStr;
运行项目:
访问该项目web界面:
http://127.0.0.1:8080/testmulu
如果修改默认端口为8888,添加文件并重启:
server.port=8888
部署成功。
9、IDEA认识断点Fastjson(Debug)
先设置两处断点测试,左击标红处即可设置断点:
先暂停:
再使用Debug运行:
启动完成后访问url,会发现url不能访问,左上角会进行转动,然后后调用到断点处:
然后按F8进行下一步,按三次F8即可看到断点跳转的详细:
然后按F9跳过该断点:
(未完待续)
— 往期回顾 —
关于安恒信息安全服务团队安恒信息安全服务团队由九维安全能力专家构成,其职责分别为:红队持续突破、橙队擅于赋能、黄队致力建设、绿队跟踪改进、青队快速处置、蓝队实时防御,紫队不断优化、暗队专注情报和研究、白队运营管理,以体系化的安全人才及技术为客户赋能。