哎哟喂!影响版本的C3P0利用,这坑我替你踩过了!
兄弟们,姐妹们,今天咱们不聊那些虚头巴脑的宏观趋势,咱们就来点实在的——聊聊那个让我又爱又恨的 C3P0,特别是影响版本的利用问题,说真的,每次挖洞碰到这玩意儿,我心里都跟坐过山车似的,刺激是真刺激,但稍不注意,那坑坑洼洼的底层逻辑就能让你怀疑人生!
咱们得把话撂这儿:C3P0这东西,在Java世界里那可是老牌连接池了,资历老,用的人多,自然也就成了攻击者的“心头好”,可问题就出在,不同版本的利用方式简直是天壤之别!有的版本,你构造个恶意类丢进去,直接就给你反弹个Shell回来,那叫一个痛快;可换个版本,你折腾半天,发现人家早就把口子堵上了,那种挫败感,啧啧,别提多难受了。
我印象最深的一次,是碰上一个老系统,用的C3P0版本,好家伙,我一看那版本号,心里就咯噔一下,这不是典型的影响版本嘛!当时那个激动啊,感觉KPI就在眼前了,我赶紧按照老思路,利用那个经典的com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase,想通过JndiRefForwardingDataSource来一波操作,结果呢?用是能触发,但要么是网络不通,要么是ClassLoader加载不了,那感觉就像你拿着钥匙去开门,明明锁孔对上了,可就是拧不动,你说气不气人?
后来我复盘了一下,发现关键利用点在于,C3P0在反序列化的时候,ObjectInputStream解析Referenceable对象的过程,不同版本对Reference的factoryClassLocation处理逻辑有细微差别,有的版本,你可以直接指到远程的http://evil.com/,让服务器加载你的恶意字节码;但有的版本呢,它非得要本地classpath里有这个类,或者说,它压根就不支持远程加载了,你看,这影响版本的细节,是不是得门儿清才行?
再聊聊那个更隐蔽的,关于exploit的变种,有些老哥喜欢用CommonsBeanutils那条链子去配合,但C3P0这里有个特性,就是它的SerializedIndirectly会绕一下,导致某些利用链子在特定版本下是失效的,我曾经为了一个目标,硬是把目标环境里的依赖jar包版本全猜了一遍,最后才凑出来一个能用的payload,那一刻,我真想对C3P0说一句:“老哥,咱俩谁是谁的劫啊?”
所以啊,我觉得吧,搞C3P0利用,千万别“一招鲜,吃遍天”,你得先摸清影响版本,是9.5.x还是9.2.x,亦或是那个更早期的8.x,每个分支的脾气都不一样,咱们做安全的,就得像侦探一样,从pom.xml或者web.xml里那不起眼的依赖信息里,嗅出那么一丝丝的突破口,而且啊,现在的目标防御越来越强,光靠一个简单的JndiRemoteClassLoad已经不够用了,你得多想想怎么绕过黑名单,怎么配合URLClassLoader,或者怎么利用那个隐藏的HexMe接口。
说到这儿,我突然想起那个让人头大的 C3P0 0.9.5.5 版本,官方号称修复了,但某些特定的getter方法,比如setJndiName,在配合Groovy或XStream这种二次反序列化的时候,还是有可能点起星星之火,这就像打地鼠,你按下这个,那个又冒头。
最后啰嗦一句,咱在本地复现的时候,一定要搭好环境,最好用Commons-Collections的老版本去测,不然根本走不到那条利用链上,我上次就是JDK版本太高(JDK8u341),com.sun.jndi.ldap.object.trustURLCodebase默认为false,导致整个攻击流产,那叫一个憋屈啊!
好了,就聊到这儿吧,这儿水深着呢,我也只是趟过了几块石头。

学习网络安全可以加QQ: 123456789(纯属虚构,别真加哦!)咱们下回再聊别的坑!

