詳解pythonpickle中的反序列化漏洞

互聯架構唠唠嗑 2024-06-27 17:57:08
1. 引言

大家好,今天我們來聊聊Python裏的反序列化攻擊。先來看看什麽是序列化和反序列化。簡單來說,序列化就是把數據結構轉換成字節流,這樣我們就可以把數據保存到文件裏或者通過網絡傳輸。反序列化則是把這些字節流再轉換回原來的數據結構。

在Python裏,常用的模塊之一就是Pickle。它可以幫我們很方便地進行序列化和反序列化操作。比如,你可以把一個複雜的Python對象序列化保存下來,等需要用的時候再反序列化回來。

反序列化攻擊的概述

反序列化過程有漏洞:如果我們反序列化了一個不可信的數據源,那就可能引發反序列化攻擊。攻擊者可以在序列化的數據裏嵌入惡意代碼,當你反序列化這個數據時,這些惡意代碼就會被執行,可能會導致數據泄露、系統崩潰,甚至讓攻擊者遠程控制你的系統。

2. Python Pickle模塊概述

Pickle的基本功能

Pickle模塊是Python自帶的,它主要用來序列化和反序列化Python對象。你可以用Pickle把任何Python對象(包括複雜的數據結構)保存成字節流,然後在需要的時候再加載回來。

Pickle的工作原理

Pickle的工作原理其實很簡單。序列化的時候,它會把Python對象轉換成字節流,反序列化的時候,它會把字節流還原成Python對象。下面我們來看幾個具體的例子。

Pickle的序列化

序列化就是把Python對象轉換成字節流。我們可以用pickle.dump和pickle.dumps來做這件事。pickle.dump把對象序列化後寫入文件,pickle.dumps則返回一個字節流。

import pickle# 創建一個對象data = {'name': 'Alice', 'age': 25, 'city': 'New York'}# 序列化對象並寫入文件with open('data.pickle', 'wb') as file: pickle.dump(data, file)# 或者返回一個字節流data_bytes = pickle.dumps(data)

Pickle的反序列化

反序列化就是把字節流還原成Python對象。我們可以用pickle.load和pickle.loads來做這件事。pickle.load從文件中讀取字節流並反序列化,pickle.loads則直接反序列化一個字節流。

import pickle# 從文件中反序列化對象with open('data.pickle', 'rb') as file: data = pickle.load(file)# 或者直接反序列化一個字節流data = pickle.loads(data_bytes)3. 反序列化攻擊的原理

攻擊機制

現在我們來看看反序列化攻擊是怎麽回事。攻擊者可以在序列化的數據裏嵌入惡意代碼,當你反序列化這個數據時,這些惡意代碼就會被執行。換句話說,如果你從不可信的數據來源反序列化數據,就等于是給了攻擊者在你系統裏執行代碼的機會。

攻擊者可以做什麽

攻擊者可以利用反序列化漏洞執行任意命令、修改或竊取數據。

示例代碼

爲了更清楚地說明問題,我們來看一個簡單的反序列化攻擊示例。

import pickleimport os# 構造惡意代碼class Malicious: def __reduce__(self): return (os.system, ('echo Hacked!',))# 序列化惡意對象malicious_data = pickle.dumps(Malicious())# 反序列化時執行惡意代碼pickle.loads(malicious_data)

在這個示例中,我們創建了一個名爲Malicious的類。這個類的__reduce__方法返回一個元組,第一個元素是os.system,第二個元素是要執行的命令。當我們反序列化這個對象時,os.system('echo Hacked!')會被執行,輸出“Hacked!”。

詳細解釋

構造惡意代碼:我們定義了一個Malicious類,並在__reduce__方法中指定要執行的命令。序列化惡意對象:我們用pickle.dumps序列化這個惡意對象。反序列化惡意對象:當我們用pickle.loads反序列化這個對象時,__reduce__方法會被調用,並執行指定的命令。4. 如何防範Pickle反序列化攻擊

安全反序列化的原則

防範反序列化攻擊的第一原則就是:避免從不可信來源反序列化。只有當你完全信任數據的來源時,才可以使用反序列化。

我們來看一些具體的防禦方法和代碼示例。

安全的反序列化代碼示例

如果必須使用Pickle進行反序列化,可以考慮重載find_class來限定範圍限制反序列化的對象類型:

import pickleimport types# 自定義Unpickler,限制可反序列化的類型class RestrictedUnpickler(pickle.Unpickler): def find_class(self, module, name): if module == "builtins" and name in {"str", "list", "dict", "set", "int", "float", "bool"}: return getattr(__import__(module), name) raise pickle.UnpicklingError(f"global '{module}.{name}' is forbidden")def restricted_loads(s): return RestrictedUnpickler(io.BytesIO(s)).load()

在這個示例中,我們自定義了一個RestrictedUnpickler類,只允許反序列化某些安全的內置類型。

使用其他安全的序列化模塊(如JSON)

一個更安全的做法是使用JSON替代Pickle進行序列化和反序列化。JSON只支持基本數據類型,不會執行任意代碼,因而更安全。

import json# 序列化對象data = {'name': 'Alice', 'age': 25, 'city': 'New York'}data_json = json.dumps(data)# 反序列化對象data = json.loads(data_json)總結

本文說明了什麽是序列化和反序列化,以及Python中的Pickle模塊。文中還詳細解釋了反序列化攻擊的原理,並給出了攻擊代碼示例。最後討論了如何防範Pickle反序列化攻擊,並提供了一些具體的防禦方法。如果你有任何問題,歡迎在評論區討論!

作者:大鯨魚crush鏈接:https://juejin.cn/post/7383342927508701235

0 阅读:0

互聯架構唠唠嗑

簡介:感謝大家的關注