欢迎来到 无奈人生 安全网 聚焦网络安全前沿资讯,精华内容,交流技术心得!

Fastjson 1.2.24反序列化漏洞分析

来源: 作者: 时间:2019-02-24 19:29 点击: 我要投稿
广告位API接口通信错误,查看德得广告获取帮助

0×00 fastjson
fastjson是一个非常流行的库,可以将数据在JSON和Java Object之间互相转换,但是在2017年官方主动爆出了fastjson的反序列化漏洞以及升级公告,这次我们就学习一下这个漏洞。
最终的payload会放到我的GitHub上。
这次使用的fastjson是1.2.23版本:
dependency>    groupId>com.alibabagroupId>    artifactId>fastjsonartifactId>    version>1.2.23version>dependency>
在分析漏洞之前,我们先看下这个库都有什么样的功能,我们先创建一个User对象:
class User {    private int age;    public String username;    private String secret;    public int getAge() {        return age;    }    public void setAge(int age) {        this.age = age;    }    public String getUsername() {        return username;    }    public void setUsername(String username) {        this.username = username;    }    public String getSecret() {        return secret;    }}
我们主要关注一下从JSON还原回Object的方法,主要的API有两个,分别是JSON.parseObject和JSON.parse,最主要的区别就是前者返回的是JSONObject而后者返回的是实际类型的对象,当在没有对应类的定义的情况下,通常情况下都会使用JSON.parseObject来获取数据。
fastjson接受的JSON可以通过@type字段来指定该JSON应当还原成何种类型的对象,在反序列化的时候方便操作。
String myJSON = "{\"@type\":\"me.lightless.fastjsonvuln.User\",\"age\":99,\"username\":\"lightless\",\"secret\":\"2333\"}";JSONObject u3 = JSON.parseObject(myJSON);System.out.println("u3 => " + u3.get("secret"));
如果需要还原出private成员的话,还需要加上Feature.SupportNonPublicField:
User u3 = (User) JSON.parseObject(myJSON, User.class, Feature.SupportNonPublicField);
0×01 跟踪分析
根据官方的公告中的WAF检测方法来看,问题很有可能是因为反序列化了任意类型的class从而导致的RCE。

从网上找到的payload中也能看出利用的是TemplatesImpl来执行的命令,这个在之前的JDK7u21中已经分析过了,可能还存在其他的执行命令方法,这些我们暂且不谈,主要来看fastjson的部分。
我们搭建一个简单的Web应用来接受用户POST过来的JSON并且进行反序列化:
@RestControllerpublic class IndexController {    @RequestMapping(value = "/fastjson", method = RequestMethod.GET)    public String fastjson() {        return "Hello World!";    }    @RequestMapping(value = "/fastjson", method = RequestMethod.POST)    public JSONObject testVuln(@RequestBody String data) {        JSONObject obj = JSON.parseObject(data, Feature.SupportNonPublicField);        JSONObject ret = new JSONObject();        ret.put("code", 1001);        ret.put("data", "Hello " + obj.get("name"));        return ret;    }}
传入我们带有@type类型的JSON字符串并且开始调试。在JSON.parseObject处下断并开始向下跟。

一开始会跟进到JSON.parse方法,并且调用了parse()方法继续进行JSON格式的匹配。继续跟进parser.parse()方法。

到了这里之后,开始依次进行JSON的解析,我们传入的第一个字符是{,所以进入LBRACE这个分支中,并继续进入parseObject(object, fieldName)方法来解析对象。

这个时候lexer所在的字符为”,会进入下面这个分支继续解析JSON字符串,通过scanSymbol方法获取到双引号之间的字符串也就是@type

之后会获取@type字段的值,并且尝试获取这个类的Class,经过一系列的判断后,调用了deserializer.deserialize(this, clazz, fieldName)方法进行反序列化。

[1] [2]  下一页

0×00 fastjson
fastjson是一个非常流行的库,可以将数据在JSON和Java Object之间互相转换,但是在2017年官方主动爆出了fastjson的反序列化漏洞以及升级公告,这次我们就学习一下这个漏洞。
最终的payload会放到我的GitHub上。
这次使用的fastjson是1.2.23版本:
dependency>    groupId>com.alibabagroupId>    artifactId>fastjsonartifactId>    version>1.2.23version>dependency>
在分析漏洞之前,我们先看下这个库都有什么样的功能,我们先创建一个User对象:
class User {    private int age;    public String username;    private String secret;    public int getAge() {        return age;    }    public void setAge(int age) {        this.age = age;    }    public String getUsername() {        return username;    }    public void setUsername(String username) {        this.username = username;    }    public String getSecret() {        return secret;    }}

内容来自无奈安全网


我们主要关注一下从JSON还原回Object的方法,主要的API有两个,分别是JSON.parseObject和JSON.parse,最主要的区别就是前者返回的是JSONObject而后者返回的是实际类型的对象,当在没有对应类的定义的情况下,通常情况下都会使用JSON.parseObject来获取数据。
fastjson接受的JSON可以通过@type字段来指定该JSON应当还原成何种类型的对象,在反序列化的时候方便操作。
String myJSON = "{\"@type\":\"me.lightless.fastjsonvuln.User\",\"age\":99,\"username\":\"lightless\",\"secret\":\"2333\"}";JSONObject u3 = JSON.parseObject(myJSON);System.out.println("u3 => " + u3.get("secret"));
如果需要还原出private成员的话,还需要加上Feature.SupportNonPublicField:
User u3 = (User) JSON.parseObject(myJSON, User.class, Feature.SupportNonPublicField);
0×01 跟踪分析
根据官方的公告中的WAF检测方法来看,问题很有可能是因为反序列化了任意类型的class从而导致的RCE。
内容来自无奈安全网

从网上找到的payload中也能看出利用的是TemplatesImpl来执行的命令,这个在之前的JDK7u21中已经分析过了,可能还存在其他的执行命令方法,这些我们暂且不谈,主要来看fastjson的部分。
我们搭建一个简单的Web应用来接受用户POST过来的JSON并且进行反序列化:
@RestControllerpublic class IndexController {    @RequestMapping(value = "/fastjson", method = RequestMethod.GET)    public String fastjson() {        return "Hello World!";    }    @RequestMapping(value = "/fastjson", method = RequestMethod.POST)    public JSONObject testVuln(@RequestBody String data) {        JSONObject obj = JSON.parseObject(data, Feature.SupportNonPublicField);        JSONObject ret = new JSONObject();        ret.put("code", 1001);        ret.put("data", "Hello " + obj.get("name"));        return ret;    }} 无奈人生安全网
传入我们带有@type类型的JSON字符串并且开始调试。在JSON.parseObject处下断并开始向下跟。

一开始会跟进到JSON.parse方法,并且调用了parse()方法继续进行JSON格式的匹配。继续跟进parser.parse()方法。

到了这里之后,开始依次进行JSON的解析,我们传入的第一个字符是{,所以进入LBRACE这个分支中,并继续进入parseObject(object, fieldName)方法来解析对象。

这个时候lexer所在的字符为”,会进入下面这个分支继续解析JSON字符串,通过scanSymbol方法获取到双引号之间的字符串也就是@type

copyright 无奈人生


之后会获取@type字段的值,并且尝试获取这个类的Class,经过一系列的判断后,调用了deserializer.deserialize(this, clazz, fieldName)方法进行反序列化。

本文来自无奈人生安全网

[1] [2]  下一页 本文来自无奈人生安全网

。 (责任编辑:admin)
【声明】:无奈人生安全网(http://www.wnhack.com)登载此文出于传递更多信息之目的,并不代表本站赞同其观点和对其真实性负责,仅适于网络安全技术爱好者学习研究使用,学习中请遵循国家相关法律法规。如有问题请联系我们,联系邮箱472701013@qq.com,我们会在最短的时间内进行处理。