2012-04-24 67 views
7

它在Python文檔中聲明pickle不安全,不應解析不可信用戶輸入。如果你研究這個;幾乎所有的例子都通過os.systemsystem()聯繫。瞭解Python Pickle不安全

什麼不是我明白,是如何os.system正確解釋沒有os模塊被導入。

>>> import pickle 
>>> pickle.loads("cos\nsystem\n(S'ls /'\ntR.") # This clearly works. 
bin boot cgroup dev etc home lib lib64 lost+found media mnt opt proc root run sbin selinux srv sys tmp usr var 
0 
>>> dir() # no os module 
['__builtins__', '__doc__', '__name__', '__package__', 'pickle'] 
>>> os.system('ls /') 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
NameError: name 'os' is not defined 
>>> 

有人能解釋一下嗎?

回答

9

模塊(os)的名稱是操作碼的一部分,並且pickle自動導入模塊:

# pickle.py 
def find_class(self, module, name): 
    # Subclasses may override this 
    __import__(module) 
    mod = sys.modules[module] 
    klass = getattr(mod, name) 
    return klass 

注意__import__(module)線。

執行GLOBAL 'os system' pickle字節碼指令時會調用該函數。

爲了能夠取消模塊未被顯式導入到調用者名稱空間的類的實例,必須使用此機制。

+1

+1查找模塊代碼 – tMC 2012-04-24 17:03:48

2

導入模塊只把它添加到本地命名空間,它不一定是一個你是除了當它不:

>>> dir() 
['__builtins__', '__doc__', '__name__', '__package__'] 
>>> __import__('os') 
<module 'os' from '/usr/lib64/python2.7/os.pyc'> 
>>> dir() 
['__builtins__', '__doc__', '__name__', '__package__'] 
6

如果使用pickletools.dis拆解鹹菜你可以看到這是如何工作的:

import pickletools 
print pickletools.dis("cos\nsystem\n(S'ls ~'\ntR.") 

輸出:

0: c GLOBAL  'os system' 
11: ( MARK 
12: S  STRING  'ls ~' 
20: t  TUPLE  (MARK at 11) 
21: R REDUCE 
22: . STOP 

Pickle使用一個簡單的基於堆棧的虛擬機來記錄用於重建對象的指令。換句話說在你的榜樣醃漬說明:

推self.find_class(MODULE_NAME,CLASS_NAME),即推動使用os.system 推絃「LS〜」 生成的元組,從最頂層的棧項目 應用調用到argtuple,在堆棧上。即使用os.system(*( 'LS〜',))

Source

+2

是的,但爲什麼不需要'import os'? – NPE 2012-04-24 16:48:13

+1

dir()試圖提供一組有趣的名稱,而不是試圖提供嚴格或一致定義的名稱集,並且其詳細行爲可能會在不同版本之間發生變化。當您動態導入模塊時,不能保證您會用dir() – 2012-04-24 16:56:19

8

有關編寫惡意醬菜是走得更遠比標準使用os.system()例子乾脆太多的信息,請參閱本presentation和其附帶的paper

+1

+1來查看它以挖掘豐富的資源 – gauden 2012-04-25 05:15:18

+0

awesome find- thanks – tMC 2012-04-25 13:30:52