国产日韩欧美一区二区三区三州_亚洲少妇熟女av_久久久久亚洲av国产精品_波多野结衣网站一区二区_亚洲欧美色片在线91_国产亚洲精品精品国产优播av_日本一区二区三区波多野结衣 _久久国产av不卡

?

Oj庫(kù)反序列化攻擊面分析

2022-12-08 04:32:10吳紅
關(guān)鍵詞:序列化字符串調(diào)用

◆吳紅

Oj庫(kù)反序列化攻擊面分析

◆吳紅

(國(guó)網(wǎng)眉山供電公司 四川 620010)

Oj是一個(gè)快速的JSON解析Ruby庫(kù),由于它極其高效且易用,根據(jù)Github統(tǒng)計(jì),有上萬(wàn)項(xiàng)目以其作為依賴(lài)項(xiàng)。Oj庫(kù)默認(rèn)使用一個(gè)類(lèi)型系統(tǒng)來(lái)解析Ruby對(duì)象,這允許應(yīng)用代碼在反序列化JSON字符串時(shí)恢復(fù)原始的對(duì)象,但這種能力可能導(dǎo)致安全漏洞,如遠(yuǎn)程代碼執(zhí)行或拒絕服務(wù)。本文將分析Oj庫(kù)反序列化時(shí)可能造成的漏洞,并給出消除此類(lèi)漏洞的建議。

Oj;反序列化漏洞;類(lèi)型系統(tǒng)

Oj(https://github.com/ohler55/oj)是一個(gè)快速的JSON解析及對(duì)象序列化器。它可以序列化絕大多數(shù)的Ruby對(duì)象,在反序列化時(shí)則解析JSON字符串中約定的格式來(lái)恢復(fù)對(duì)象信息。不安全的反序列化作為OWASP TOP10中的一種通用漏洞類(lèi)型[1],在各類(lèi)編程語(yǔ)言中廣泛存在,近年來(lái)在Java應(yīng)用中尤其嚴(yán)重,一些知名Java組件,如FastJSON[2]、XStream等頻頻爆出反序列化漏洞,這類(lèi)漏洞特點(diǎn)是利用簡(jiǎn)單、危害巨大,通常能造成遠(yuǎn)程代碼執(zhí)行。由此看來(lái),Oj提供的反序列化對(duì)象的能力同樣是一種攻擊面,值得深入研究。

1 Oj用例分析

Oj提供兩個(gè)核心API用戶(hù)序列化與反序列化過(guò)程:

(1)Oj.load(json,options={}){ ... }

(2)Oj.dump(obj,options={})

Oj.load方法用于反序列化一個(gè)字符串,返回類(lèi)型取決于具體配置。可以全局配置Oj選項(xiàng),存儲(chǔ)在Oj.default_options變量中。我們僅關(guān)注反序列化時(shí)可能造成安全風(fēng)險(xiǎn)的一些配置:

(1)auto_define

(2)mode

(3)create_additions與create_id

auto_define選項(xiàng)指定反序列化時(shí)類(lèi)名不存在時(shí)是否進(jìn)行自動(dòng)定義;mode選項(xiàng)指定Oj模式;create_additions與create_id選項(xiàng)為一組,指定特定情況下反序列化對(duì)象的鍵名,之后會(huì)詳細(xì)說(shuō)明。

Oj.dump方法用于將一個(gè)Ruby對(duì)象序列化為JSON字符串。

1.1 模式

Oj當(dāng)前支持6種模式[3]:strict、null、compat、rails、object、custom,我們對(duì)object模式感興趣,這也是默認(rèn)的模式,因?yàn)樵撃J皆试S將Ruby對(duì)象進(jìn)行序列化與反序列化。當(dāng)使用object模式時(shí),Oj遵循一組特定的編碼來(lái)確定JSON字符串中哪些部分需要重建為對(duì)象或類(lèi)。具體規(guī)則如下:

(1)原生JSON類(lèi)型,true,false,nil,String,Hash,Array,Numbers正常編碼。

(2)Symbol類(lèi)型編碼為以“:”開(kāi)頭的字符串。

(3)以“^”開(kāi)頭的鍵名表示這是一個(gè)特殊的鍵。

(4)以':','^i'或'^r開(kāi)頭的字符串,將這三種前綴編碼為unicode字符串形式。

(5)一個(gè)"^c "的JSON對(duì)象鍵表示該值應(yīng)該被轉(zhuǎn)換為一個(gè)Ruby類(lèi)。

(6)一個(gè)"^t"的JSON對(duì)象鍵表示該值應(yīng)該被轉(zhuǎn)換為Ruby Time。

(7)一個(gè)"^o"的JSON對(duì)象鍵表示該值應(yīng)該被轉(zhuǎn)換為Ruby對(duì)象。JSON對(duì)象中的第一個(gè)條目必須是一個(gè)帶有"^o"鍵的類(lèi)。在這之后,每個(gè)條目都被視為Object的一個(gè)變量,其中的鍵是沒(méi)有前面的'@'的變量名。

(8)一個(gè)"^u"JSON對(duì)象的鍵表示該值應(yīng)該被轉(zhuǎn)換為Ruby Struct。JSON對(duì)象中的第一個(gè)條目必須是一個(gè)帶有"^u"鍵的類(lèi)。之后,每個(gè)條目在結(jié)構(gòu)中被賦予一個(gè)數(shù)字位置,并被用作JSON對(duì)象的鍵。

(9)當(dāng)對(duì)一個(gè)對(duì)象進(jìn)行編碼時(shí),如果變量名稱(chēng)不是以'@'字符開(kāi)始,那么名稱(chēng)前面會(huì)有一個(gè)'~'字符。

(10)如果一個(gè)Hash條目有一個(gè)不是字符串或符號(hào)的鍵,那么該條目將被編碼為"^#n"形式的鍵,其中n是一個(gè)十六進(jìn)制數(shù)字。值是一個(gè)數(shù)組,其中第一個(gè)元素是Hash中的鍵,第二個(gè)元素是值。

(11)在一個(gè)對(duì)象或數(shù)組中的"^i"JSON條目是被編碼的Ruby對(duì)象的ID。當(dāng)circular標(biāo)志被設(shè)置時(shí)被使用。它可以出現(xiàn)在一個(gè)JSON對(duì)象或JSON數(shù)組中。在一個(gè)對(duì)象中,"^i"鍵有一個(gè)相應(yīng)的引用。在一個(gè)數(shù)組中,該序列將包括一個(gè)嵌入的引用號(hào)。

(12)一個(gè)對(duì)象中的"^r"JSON條目是對(duì)已經(jīng)出現(xiàn)在JSON字符串中的一個(gè)對(duì)象或數(shù)組的引用。它必須與之前的"^i"引用號(hào)相匹配。

(13)如果一個(gè)數(shù)組元素是一個(gè)字符串,并且以"^i"開(kāi)頭,那么第一個(gè)字符'^'被編碼為一個(gè)十六進(jìn)制字符序列。

下面展示一些實(shí)例。定義類(lèi)A如下:

class A

def initialize(name)

@count = 1

@name = name

end

end

使用Oj序列化A的實(shí)例:Oj.dump(A.new(“John”)),結(jié)果如下:

{"^o":"A","count":1,"name":"John"}

對(duì)于這一結(jié)果,“^o”鍵的值為A,表示類(lèi)A的實(shí)例,后續(xù)的count及name鍵代表其實(shí)例變量名,值為實(shí)例變量的值。使用Oj.load方法反序列化:

Oj.load %Q({"^o":"A","count":1,"name":"John"})

=> #

獲得A類(lèi)的新實(shí)例,對(duì)應(yīng)的實(shí)例變量已被設(shè)置。

2 攻擊面分析

2.1 拒絕服務(wù)攻擊(內(nèi)存耗盡)

在第1小節(jié)中提到auto_define配置,該配置設(shè)置為true時(shí),Oj解析到未定義的類(lèi)時(shí),將自動(dòng)定義該類(lèi)。例如,執(zhí)行下列代碼后,對(duì)象命名空間中將存在類(lèi)NotDefined:

Oj.load %Q({"^c":"NotDefined"}),auto_define:true

我們可以模擬攻擊者大量請(qǐng)求反序列化不存在的類(lèi):

10000000000.times { Oj.load %Q({"^c":"A#{SecureRandom.hex(4)}"}),auto_define:true }

將觀察到Ruby進(jìn)程內(nèi)存占用顯著增長(zhǎng)。

2.2 拒絕服務(wù)攻擊(內(nèi)存損壞)

盡管Oj默認(rèn)允許反序列化幾乎任意類(lèi)型,但它與FastJSON等庫(kù)的顯著區(qū)別在于反序列化過(guò)程中對(duì)象的方法不會(huì)被調(diào)用,例如實(shí)例化方法initialize及其他鉤子方法,這在一定程度上提供了安全性,至少不太可能在反序列化過(guò)程中被利用。

由于Oj代碼庫(kù)比較龐大,為了研究反序列化時(shí)的行為,我們可以先從結(jié)果入手。考慮下列代碼,嘗試反序列化一個(gè)Proc對(duì)象的實(shí)例:

Oj.load %Q({"^o":"Proc"})

這將導(dǎo)致拋出TypeError:allocator undefined for Proc。這與調(diào)用allocate方法[4]的行為一致。類(lèi)或模塊的allocate方法將分配一個(gè)對(duì)象實(shí)例但不調(diào)用initialize方法,這很好地避免了initialize方法在反序列化時(shí)被濫用,而限制在于并非所有的類(lèi)都支持allocate。默認(rèn)情況下Ruby提供allocate方法實(shí)現(xiàn),對(duì)于C擴(kuò)展可以使用rb_define_alloc_func函數(shù)注冊(cè)自己的allocate方法,或使用rb_undef_alloc_func禁用allocate方法。

盡管調(diào)用allocate可以避免調(diào)用初始化方法,但這種行為可能導(dǎo)致其他問(wèn)題。對(duì)于完全由運(yùn)行時(shí)托管的對(duì)象,僅調(diào)用allocate雖可能產(chǎn)生未定義的行為,例如由于某些變量未初始化而導(dǎo)致拋出異常,但這種異常可以被捕獲并處理,并不會(huì)導(dǎo)致進(jìn)程崩潰;然而如果某一對(duì)象的數(shù)據(jù)操作交由原生代碼處理,例如直接訪問(wèn)未初始化地址,則可能導(dǎo)致內(nèi)存損壞。一個(gè)例子是Ruby3.0.0中Ractor類(lèi)存在的Bug。Ractor是Ruby3中新增的Actor模型的實(shí)現(xiàn),它幾乎完全使用C代碼實(shí)現(xiàn)。在3.0.0版本中Ractor允許調(diào)用allocate方法并返回一個(gè)實(shí)例,但這將導(dǎo)致一些必要的初始化操作被跳過(guò),并在某一時(shí)刻產(chǎn)生對(duì)進(jìn)程地址的非法讀寫(xiě),最終使程序崩潰。

雖然這并不是Oj的責(zé)任,但如果Oj反序列化一個(gè)Ractor對(duì)象,則將導(dǎo)致返回一個(gè)僅調(diào)用allocate方法的對(duì)象,調(diào)用它的多數(shù)方法都將導(dǎo)致進(jìn)程崩潰進(jìn)而拒絕服務(wù),漏洞概念證明如下:

Oj.load(%Q({"^o":"Ractor"})).whatever

2.3 遠(yuǎn)程代碼執(zhí)行

當(dāng)反序列化一個(gè)對(duì)象時(shí),對(duì)象的實(shí)例變量將設(shè)置為攻擊者可控制的值。獲取到返回的對(duì)象后,應(yīng)用代碼可能調(diào)用該對(duì)象上的任意方法,此時(shí)會(huì)產(chǎn)生類(lèi)型混淆,例如應(yīng)用代碼期望獲得一個(gè)Hash或Array對(duì)象,但實(shí)際上是一個(gè)String對(duì)象。一個(gè)String對(duì)象也許沒(méi)有什么危險(xiǎn),但攻擊者可以構(gòu)造一條Gadget鏈,通過(guò)操作對(duì)象實(shí)例變量的值,從應(yīng)用代碼的一次非預(yù)期調(diào)用開(kāi)始執(zhí)行到進(jìn)行危險(xiǎn)操作的方法。一個(gè)著名的例子是ActiveSupport中的DeprecatedInstanceVariableProxy[5]類(lèi),該類(lèi)代碼大體如下:

class DeprecatedInstanceVariableProxy < DeprecationProxy

def initialize(instance, method, ...)

@instance = instance

@method = method

end

private

def target

@instance.__send__(@method)

end

end

該類(lèi)繼承DeprecationProxy類(lèi),DeprecationProxy定義了method_missing鉤子方法,該方法在調(diào)用對(duì)象上未定義的方法時(shí)被調(diào)用:

def method_missing(...)

...

target.__send__(...)

end

對(duì)于這個(gè)Gadget,@instance與@method變量可控的情況下,在返回對(duì)象上調(diào)用任意不存在的方法(很容易滿足條件,因?yàn)檫@個(gè)類(lèi)本身就沒(méi)有實(shí)現(xiàn)太多方法),將導(dǎo)致父類(lèi)DeprecationProxy上的method_missing方法被調(diào)用,而該方法實(shí)現(xiàn)上又調(diào)用target方法,此時(shí)@instance對(duì)象的@method方法被執(zhí)行。@instance對(duì)象可以使用ERB對(duì)象,@method則為result方法,ERB對(duì)象設(shè)置其src實(shí)例變量為需要執(zhí)行的代碼,result方法被調(diào)用時(shí)將會(huì)執(zhí)行,從而實(shí)現(xiàn)遠(yuǎn)程代碼執(zhí)行。

3 如何防御此類(lèi)漏洞

經(jīng)過(guò)分析,產(chǎn)生反序列化漏洞的根源在于使用不安全輸入創(chuàng)建任意對(duì)象。Oj本身在其文檔中已指明這一點(diǎn),并提供了非常簡(jiǎn)單的解決方案:不使用object模式。如果使用compat模式,且開(kāi)啟了create_additions選項(xiàng),則還需要審計(jì)所有類(lèi)中的json_create方法是否存在代碼執(zhí)行的可能。

4 結(jié)束語(yǔ)

本文介紹了Oj庫(kù)反序列化攻擊面中的不同漏洞類(lèi)型,并給出防御解決方案。隨著近年攻防演練持續(xù)升溫,反序列化漏洞也越來(lái)越受關(guān)注,利用簡(jiǎn)單、危害巨大的特點(diǎn)使其在未來(lái)將被更多安全研究者進(jìn)一步研究、挖掘、利用。

[1]A8:2017-Insecure Deserialization[EB/OL].https://owasp.org/www-project-top-ten/2017/A8_2017-Insecure_Deserialization,2017-12.

[2]Fastjson 反序列化漏洞史[EB/OL].https://paper. seebug. org/1192/,2020-05-08.

[3]Oj Modes[EB/OL].https://github.com/ohler55/oj/blob/ develop/pages/Modes.md,2021-08-03.

[4]method-i-allocate[EB/OL].https://ruby-doc.org/core-2.5.0/Class.html#method-i-allocate,2020-05.

[5]DeprecatedInstanceVariableProxy[EB/OL].https://github.com/rails/rails/blob/18707ab17fa492eb25ad2e8f9818a320dc20b823/activesupport/lib/active_support/deprecation/proxy_wrappers.rb#L88,2021-07-30.

猜你喜歡
序列化字符串調(diào)用
如何建構(gòu)序列化閱讀教學(xué)
甘肅教育(2020年14期)2020-09-11 07:58:36
核電項(xiàng)目物項(xiàng)調(diào)用管理的應(yīng)用研究
LabWindows/CVI下基于ActiveX技術(shù)的Excel調(diào)用
基于系統(tǒng)調(diào)用的惡意軟件檢測(cè)技術(shù)研究
Java 反序列化漏洞研究
作文訓(xùn)練微格化、序列化初探
一種新的基于對(duì)稱(chēng)性的字符串相似性處理算法
利用RFC技術(shù)實(shí)現(xiàn)SAP系統(tǒng)接口通信
依據(jù)字符串匹配的中文分詞模型研究
Java序列化技術(shù)的探討
永城市| 武乡县| 梅州市| 玉龙| 宁武县| 都兰县| 自治县| 巴青县| 博兴县| 沙河市| 齐河县| 新竹市| 桐乡市| 红桥区| 福贡县| 方山县| 丹东市| 永安市| 高青县| 潜江市| 西昌市| 田东县| 衡阳市| 依兰县| 金平| 炎陵县| 响水县| 和田市| 北流市| 永嘉县| 乡城县| 杭锦后旗| 花垣县| 和静县| 邹平县| 绵阳市| 许昌市| 聂荣县| 衡山县| 肇东市| 平顺县|