0x00 Hessian協議解析 Hessian是一個輕量級的Java還原序列化架構,和Java原生的序列化對比,hessian更加高效並且非常適合位元據傳輸。 既然是一個序列化/還原序列化架構,hessian也有還原序列化命令執行的問題,這個在marshalsec工具中有所體現。這裡有個有趣的點,在hessian架構中,ysoserial架構提供的gadget無法使用,你會發現在hessian產生序列化資料,即writeObject的時候就直接彈窗報錯了,這是為什麼呢。 以Groovy1這個gadget為例,我們看一下ysoserial的gadgets在hessian中的表現:
這段代碼中產生了Groovy1這個對象,然後丟進hessian序列化和還原序列化過程中,其實這裡在writeObject的部分就觸發了RCE,成了一個自己日自己的漏洞,為什麼會這樣呢。其實這和hessian的序列化實現有關係,看一下源碼:
在hessian將對象進行序列化操作的時候,會提取對象的欄位然後執行序列化操作,注意到這裡直接調用了memberValues的get方法,即提前觸發了ConvertedClosure的invoke方法,這導致了序列化的過程直接失敗了。而ysoserial的這些gadgets基本都是基於原生Java還原序列化過程進行構造的,hessian是一種不同於原生序列化的庫,因此ysoserial的gadgets在這裡就用不上。
0x01 Gadget原理分析 針對hessian還原序列化過程進行攻擊,就需要使用特殊的gadget,在marshalsec這個工具裡,已經有了5個可用的Gadgets。分別是: Rome XBean Resin SpringPartiallyComparableAdvisorHolder SpringAbstractBeanFactoryPointcutAdvisor 這裡以Rome這個Gadget分析,代碼如下:
(1)首先建立一個ToStringBean的對象item,設定其beanClass和obj屬性為JdbcRowSetImpl (2)然後建立了一個EqualsBean的對象root,將這個item放進去 (3)最後把root放在一個HashMap中,這裡的JDKUtil.makeMap方法使用了反射動態建立數組,防止在構造gadget的時候觸發put方法導致RCE。
ToStringBean對象中有個toString方法,會調用其beanClass欄位的全部getter方法,這裡設定為了JdbcRowSetImpl,這個類的一個getter叫getDatabaseMetaData會調用connect方法,即通過lookup方式觸發RCE。
而EqualBean裡有個hashCode方法,該方法通過hash(obj)進行觸發,這個方法就調用了對象的toString()方法。
下面我們來看看是如何觸發命令執行的,過程很有意思。hessian在處理map還原序列化的時候,調用了MapDeserializer的readMap方法,這裡會調用HashMap的put方法
put方法中會調用hash(key)計算對象hash,這裡實際上就是調用的EqualBean的hashCode,進而調用了ToStringBean的toString方法,在ToStringBean.toString方法中調用了JdbcRowSetImpl的所有getter方法,其中當調用getDatabaseMetaData這個方法的時候觸發lookup,從而完成JNDI觸發RCE。
0x02 Dubbo Exploit Dubbo是一個SOA架構,用於服務管理、註冊、發現、調用等功能。下圖就是dubbo的各個模組關係圖:
可以理解為consumer通過RPC遠程調用的方法調用provider上面的方法。既然是遠程調用,就免不了使用對象序列化和還原序列化,dubbo也不例外。在配置provider的時候可以選擇幾個不同的協議,對應著不同的序列化方式,預設情況支援dubbo協議,配置如下:
曆史上,這個地方也出過漏洞,即從consumer端指定serialization=java的方法修改provider端的還原序列化方式為java原生還原序列化,這樣就可以使用ysoserial裡的gadgets去攻擊dubbo了,但是這個漏洞在2.5.9版本被修複了。不過今天,我們是直接攻擊hessian還原序列化的過程。 攻擊情境如下,provider和registry對外開放,惡意consumer通過本攻擊方法可以在provider機器上執行任意命令。 複現代碼如下:
直接手動構造好payload,通過調用遠程方法的方式將對象傳遞過去即可觸發了。
0x03 總結 marshal和unmarshal實際上是一種比傳統序列化更加廣泛的攻擊面,因為它涉及了諸多個物件儲存和還原的方式,比如json、YAML、hessian等。並且每個序列化方式實現都不同,所以gadgets也比較靈活好找,可以預見2018年會出現更多的gadgets來拓寬該領域的攻擊面。