成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Python 反序列化安全問(wèn)題(二)

zhoutk / 1868人閱讀

摘要:讀取新的一行作為模塊名,讀取下一行作為對(duì)象名,然后將壓入到堆棧中。讀取字符串進(jìn)行處理之后壓入堆棧。將一個(gè)元組和一個(gè)可調(diào)用對(duì)象彈出堆棧,然后以該元組作為參數(shù)調(diào)用該可調(diào)用的對(duì)象,最后將結(jié)果壓入到堆棧中。調(diào)用結(jié)束反序列化。


python pickle允許類定義__reduce__方法來(lái)聲明如何進(jìn)行序列化。其返回字符串或者tuple,前者可能代表著一個(gè)python的全局變量的名稱,后者則是描述在反序列化過(guò)程中如何進(jìn)行重構(gòu)。安全問(wèn)題也是主要出在后者,本文主要針對(duì)于該情況進(jìn)行pickle模塊源碼分析。
一、源碼分析

代碼結(jié)構(gòu)可以分為:基礎(chǔ)變量、自定義異常類、操作變量、序列化以及反序列化類以及普通函數(shù)。

1.1 基礎(chǔ)變量

代碼(28-57行)最先定義了部分變量,如最高協(xié)議號(hào)還有代碼中使用了struct.pack()以及marshal.loads()進(jìn)行序列化和反序列化,并且解釋了為何用這兩個(gè)函數(shù)。

1.2 自定義異常類

代碼(59-85行)中自定義了4個(gè)異常類,分別為PickleError、PicklingError、UnpicklingError以及_Stop.

PickleError:PickingError和UnpicklingError的基類

PicklingError:序列化過(guò)程中異常

UnpicklingError:反序列化過(guò)程中異常

_Stop:在反序列化過(guò)程中結(jié)尾處觸發(fā)該異常

1.3 操作變量

代碼(99-126行)定義了操作變量,我們可以理解為操作指令,每一個(gè)變量都對(duì)應(yīng)著相關(guān)操作,這些指令在序列化的過(guò)程中寫入,然后在反序列化過(guò)程中讀取進(jìn)行對(duì)應(yīng)操作;我們主要理解如下操作指令。

c:讀取新的一行作為模塊名module,讀取下一行作為對(duì)象名object,然后將module.object壓入到堆棧中。

p:將堆棧中索引為-1的對(duì)應(yīng)存儲(chǔ)入內(nèi)存。

(:將一個(gè)標(biāo)記對(duì)象插入到堆棧中。

t:構(gòu)建元組壓入堆棧。

S:讀取字符串進(jìn)行處理之后壓入堆棧。

R:將一個(gè)元組和一個(gè)可調(diào)用對(duì)象彈出堆棧,然后以該元組作為參數(shù)調(diào)用該可調(diào)用的對(duì)象,最后將結(jié)果壓入到堆棧中。

.:調(diào)用_Stop結(jié)束反序列化。

1.4 序列化以及反序列化類

代碼定義了Pickler和Unpickler類,這兩個(gè)類是pickle模塊進(jìn)行序列化反序列化的核心,下面看其實(shí)現(xiàn)過(guò)程:

1.4.1 序列化過(guò)程

dumps函數(shù)接收參數(shù)后首先進(jìn)行Pickler類的初始化,然后調(diào)用類中的dump函數(shù)進(jìn)行序列化。

dump()函數(shù)首先調(diào)用save函數(shù),save函數(shù)可以看做字典類型調(diào)度器,key為需要進(jìn)行序列化的對(duì)象的type,value為對(duì)應(yīng)type的存儲(chǔ)函數(shù)名。例如如果序列化對(duì)象為[1, 2, 3],也就是list類型,save函數(shù)判斷完類型之后,在調(diào)度器內(nèi)查找對(duì)應(yīng)的方法save_list,然后調(diào)用結(jié)束后將結(jié)果寫入內(nèi)存中,最后dump函數(shù)寫入結(jié)束符號(hào)完成整個(gè)序列化過(guò)程。

如果上一步查詢調(diào)度器并沒有查詢到對(duì)應(yīng)的方法,即對(duì)象的type不在NoneType/bool/builtin/classobj/dict/float/function/instance/int/list/long/str/tuple/type/unicode這些類型中的時(shí)候,首先查看是否存在__reduce_ex__,如果存在則不再查找__reduce__,不存在的話則繼續(xù)查找__reduce__;進(jìn)而判斷該函數(shù)返回值是string還是tuple,前者進(jìn)入save_global;后者進(jìn)入危險(xiǎn)開始的save_reduce函數(shù)。

save_reduce會(huì)將__reduce__返回的tuple結(jié)果,調(diào)用save_tuple方法進(jìn)行序列化存儲(chǔ)


測(cè)試代碼

import os
class A():
    def __reduce__(self):
        a = "whoami"
        return (os.system, (a,))
print type(A)
print dumps(A)
print type(A())
print  dumps(A())
class B(object):
    def __reduce__(self):
        a = "whoami"
        return (os.system, (a,))
print type(B)
print  dumps(B)
print type(B())
print dumps(B())

測(cè)試結(jié)果:


c__main__
A
p0
.

(i__main__
A
p0
(dp1
b.

c__main__
B
p0
.

cnt
system
p0
(S"whoami"
p1
tp2
Rp3
.

上述結(jié)果可以看出如果我們要達(dá)到執(zhí)行任意代碼的目的,需要使用的是第四種即dumps(B())才能進(jìn)入到save_reduce方法,前三種只能調(diào)用save_global方法,只是對(duì)于命名引用進(jìn)行序列化,所以也只能使用于相同環(huán)境中,否則在反序列化的過(guò)程中會(huì)報(bào)錯(cuò)。

1.4.2 反序列化過(guò)程

反序列化和序列化的過(guò)程挺相似,按字節(jié)讀取然后在調(diào)度器中查找對(duì)應(yīng)的處理函數(shù);上面我們提到過(guò)一些操作指令,反序列化的調(diào)度器中將上述的操作指令作為key,處理函數(shù)作為value,此處主要分析上述最后一個(gè)實(shí)例的反序列化過(guò)程。

序列化的結(jié)果:

cnt
system
p0
(S"whoami"
p1
tp2
Rp3
.

反序列化過(guò)程:

讀取第一個(gè)字符c,查詢調(diào)度器,對(duì)應(yīng)的方法為load_global;

調(diào)用load_global,讀取該行將該行后面nt作為模塊名,下一行system作為方法名,兩者作為參數(shù)進(jìn)入find_class;

find_class的目的就是返回nt.system方法,然后將返回結(jié)果壓入堆棧中;該方法的代碼如下所示:

    def find_class(self, module, name):
        __import__(module)
        mod = sys.modules[module]
        klass = getattr(mod, name)
        return klass

繼續(xù)讀取字節(jié)p,調(diào)用load_put,load_put從堆棧中獲取最后一個(gè)對(duì)象,放入內(nèi)存中,p后面的數(shù)字,為key;

繼續(xù)讀取字節(jié)(,調(diào)用load_mark,將object()壓入堆棧;

繼續(xù)讀取字節(jié)S,調(diào)用load_string,將"whoami"去除" "壓入堆棧;

到目前堆棧中有3個(gè)對(duì)象,分別為nt.system、object()、whoami;繼續(xù)讀取p,將whoami存儲(chǔ)到內(nèi)存中,key為1;

讀取字節(jié)t,調(diào)用load_tuple,其首先調(diào)用marker獲取object()的索引號(hào),此處為1,然后將stack[1:]變?yōu)?"whoami",),也就是說(shuō)執(zhí)行完這一步操作之后,堆棧中只有nt.system和("whoami",);

讀取字節(jié)p,調(diào)用load_put,將("whoami",)存儲(chǔ)如內(nèi)存,key為2,;

讀取字節(jié)R,調(diào)用load_reduce,運(yùn)行nt.system("whoami"),得出結(jié)果之后賦值給堆棧索引為-1;

讀取p,調(diào)用load_put,將結(jié)果存儲(chǔ)到內(nèi)存;

讀取.,即結(jié)束符號(hào),清空堆棧,結(jié)束反序列化。

總結(jié)

序列化以及反序列化其實(shí)是給每種能夠識(shí)別出來(lái)的類型的對(duì)象一個(gè)既定的方式去進(jìn)行序列化或者反序列化,如果碰到不認(rèn)識(shí)的,那就去查找__reduce__,將其序列化,然后在根據(jù)它去進(jìn)行反序列化過(guò)程中的重構(gòu);
從上面的分析過(guò)程中可以看出,如果我們要在反序列化的過(guò)程中去執(zhí)行命令,就要滿足在序列化的時(shí)候能執(zhí)行save_reduce,然后在反序列化的過(guò)程中才能執(zhí)行l(wèi)oad_reduce,進(jìn)而執(zhí)行命令;

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/41376.html

相關(guān)文章

  • Python 列化安全問(wèn)題

    摘要:讀取新的一行作為模塊名,讀取下一行作為對(duì)象名,然后將壓入到堆棧中。讀取字符串進(jìn)行處理之后壓入堆棧。將一個(gè)元組和一個(gè)可調(diào)用對(duì)象彈出堆棧,然后以該元組作為參數(shù)調(diào)用該可調(diào)用的對(duì)象,最后將結(jié)果壓入到堆棧中。調(diào)用結(jié)束反序列化。 python pickle允許類定義__reduce__方法來(lái)聲明如何進(jìn)行序列化。其返回字符串或者tuple,前者可能代表著一個(gè)python的全局變量的名稱,后者則是描...

    idealcn 評(píng)論0 收藏0
  • Python列化安全問(wèn)題

    摘要:反序列化安全問(wèn)題一這一段時(shí)間使用做開發(fā),使用了存儲(chǔ),閱讀了源碼,發(fā)現(xiàn)在存儲(chǔ)到過(guò)程中,利用了模塊進(jìn)行序列化以及反序列化正好根據(jù)該樣例學(xué)習(xí)一波反序列化相關(guān)的安全問(wèn)題,不足之處請(qǐng)各位表哥指出。 Python 反序列化安全問(wèn)題(一) 這一段時(shí)間使用flask做web開發(fā),使用了redis存儲(chǔ)session,閱讀了flask_session源碼,發(fā)現(xiàn)在存儲(chǔ)session到redis過(guò)程中,利用了...

    Amos 評(píng)論0 收藏0
  • TensorFlow 刪除 YAML 支持,建議 JSON 作為替補(bǔ)方案!

    摘要:據(jù)公告稱,和的包裝庫(kù)使用了不安全的函數(shù)來(lái)反序列化編碼的機(jī)器學(xué)習(xí)模型。簡(jiǎn)單來(lái)看,序列化將對(duì)象轉(zhuǎn)換為字節(jié)流。據(jù)悉,本次漏洞影響與版本,的到版本均受影響。作為解決方案,在宣布棄用之后,團(tuán)隊(duì)建議開發(fā)者以替代序列化,或使用序列化作為替代。 ...

    BlackFlagBin 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<