Python pickle - 它如何打破?

Pau*_*lan 12 python serialization escaping pickle

每个人都知道pickle不是一种存储用户数据的安全方式.它甚至在盒子上都这么说.

我正在寻找在当前支持的版本中破坏pickle解析的字符串或数据结构的示例cPython >= 2.4.有没有东西可以腌制而不是捣蛋?特定的unicode字符有问题吗?真的很大的数据结构?显然旧的ASCII协议有一些问题,但最新的二进制形式呢?

我对泡菜loads操作失败的方式特别好奇,特别是当给出由泡菜本身产生的字符串时.是否有任何情况下pickle将继续解析.

有什么样的边缘案例?

编辑:这里有一些我正在寻找的东西的例子:

Gor*_*ley 6

这是一个非常简化的例子,说明了pickle对我的数据结构不喜欢什么.

import cPickle as pickle

class Member(object):
    def __init__(self, key):
        self.key = key
        self.pool = None
    def __hash__(self):
        return self.key

class Pool(object):
    def __init__(self):
        self.members = set()
    def add_member(self, member):
        self.members.add(member)
        member.pool = self

member = Member(1)
pool = Pool()
pool.add_member(member)

with open("test.pkl", "w") as f:
    pickle.dump(member, f, pickle.HIGHEST_PROTOCOL)

with open("test.pkl", "r") as f:
    x = pickle.load(f)
Run Code Online (Sandbox Code Playgroud)

众所周知,Pickle对于圆形结构来说有点滑稽,但如果你把自定义散列函数和set/dicts混合成混合物,那么事情会变得非常毛茸茸.

在这个特定的例子中,它部分地取消了成员的角色,然后遇到了游泳池.所以它然后部分地解开池并遇到成员集.因此它创建了集合并尝试将部分未打开的成员添加到集合中.此时它会在自定义散列函数中死亡,因为该成员仅部分取消了作用.我担心如果你在哈希函数中有一个"if hasattr ..."会发生什么.

$ python --version
Python 2.6.5
$ python test.py
Traceback (most recent call last):
  File "test.py", line 25, in <module>
    x = pickle.load(f)
  File "test.py", line 8, in __hash__
    return self.key
AttributeError: ("'Member' object has no attribute 'key'", <type 'set'>, ([<__main__.Member object at 0xb76cdaac>],))
Run Code Online (Sandbox Code Playgroud)


Rob*_*sak 0

可以腌制类实例。如果我知道你的应用程序使用什么类,那么我就可以破坏它们。一个人为的例子:

import subprocess

class Command(object):
    def __init__(self, command):
        self._command = self._sanitize(command)

    @staticmethod
    def _sanitize(command):
        return filter(lambda c: c in string.letters, command)

    def run(self):
        subprocess.call('/usr/lib/myprog/%s' % self._command, shell=True)
Run Code Online (Sandbox Code Playgroud)

现在,如果您的程序创建Command实例并使用 pickle 保存它们,并且我可以颠覆或注入该存储,那么我可以通过self._command直接设置来运行我选择的任何命令。

实际上,我的示例无论如何都不应该被视为安全代码。但请注意,如果该sanitize函数是安全的,那么整个类也是安全的,除了可能使用来自不受信任的数据的 pickle 来破坏这一点。因此,存在一些安全的程序,但由于pickle 的不当使用而变得不安全。

危险在于,您使用 pickle 的代码可能会按照相同的原理被破坏,但在看似无辜的代码中,漏洞远不那么明显。最好的办法是始终避免使用 pickle 加载不受信任的数据。