2012-04-24 3 views
7

В документации Python указано, что pickle небезопасен и не должен анализировать недоверенный ввод пользователя. Если вы исследуете это; почти все примеры демонстрируют это с помощью звонка system() через os.system.Понимание Python Pickle Insecurity

Что мне непонятно, так это то, как 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) Обратите внимание на линии.

Эта функция вызывается, когда выполняется команда байт-кода .

Этот механизм необходим, чтобы иметь возможность разблокировать экземпляры классов, чьи модули не были явно импортированы в пространство имен вызывающего.

+1

+1 для нахождения кода модуля – tMC

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

+1

dir() пытается предоставить интересный набор имен больше, чем пытается обеспечить строго или последовательно определенный набор имен, а его подробное поведение может измениться в разных версиях. Когда вы импортируете модуль динамически, нет гарантии, что вы увидите его с dir() –

8

Для целом слишком много информации по написанию вредоносных соленья, которые идут гораздо дальше, чем на примере стандартной os.system(), см это presentation и его сопровождающий paper.

+1

+1 для выкапывания богатого ресурса – gauden

+0

awesome find- thanks – tMC