攻击 Python 的泡菜
Posted
技术标签:
【中文标题】攻击 Python 的泡菜【英文标题】:Attacking Python's pickle 【发布时间】:2012-05-04 03:51:40 【问题描述】:我正在编写一个将用户输入存储在对象中的网络应用程序。该对象将被腌制。
用户是否有可能制作恶意输入,当对象被解封时可能会做一些令人震惊的事情?
这是一个非常基本的代码示例,它忽略了封装等奇妙的原则,但概括了我正在研究的内容:
import pickle
class X(object):
some_attribute = None
x = X()
x.some_attribute = 'insert some user input that could possibly be bad'
p = pickle.dumps(x)
# Can bad things happen here if the object, before being picked, contained
# potentially bad data in some_attribute?
x = pickle.loads(p)
【问题讨论】:
只是一个字符串吗?不,它是安全的。它是任意对象吗?你打赌,它可以做坏事。 +1 这是一个很好的问题 pickle.loads(p) 将字符串视为任意对象 @spinning_plate 我不太担心,因为我的代码只会解开之前腌制过的数据,只是关心对象中的数据是否已被恶意用户通过公共网络界面可以以某种方式欺骗pickle.loads()
,使其表现得像一个邪恶的eval()
,并执行任意代码或做其他一些坏事。
是的,我想说@Not_a_Golfer 是对的,但您在这里要非常小心。有很多欺骗的余地
【参考方案1】:
是,不是……
否 - 除非解释器或 pickle 模块存在错误,否则您不能通过 pickle 文本或类似的方式运行任意代码。除非腌制后的文本是eval
ed,或者您正在做一些事情,比如创建一个具有此数据中提到的类型的新对象。
是的 - 根据您稍后计划对对象中的信息执行的操作,用户可以执行各种操作。从 SQL 注入尝试到更改凭据、暴力破解密码或在验证用户输入时应考虑的任何事情。但您可能正在检查所有这些。
编辑:
python 文档说明了这一点:
警告 pickle 模块并非旨在防止错误或恶意构造的数据。永远不要取消从不受信任或未经身份验证的来源收到的数据。
但这不是你的情况 - 你接受输入,通过常规验证,然后腌制它。
【讨论】:
一个人可以写一个对象,当它被调用时,它会做一些愚蠢的事情,但是仅仅 unpickling 是否会做坏事的问题可能更复杂 这里是一个例子,但无论如何你都必须保护你的代码不受用户输入的影响,所以我几乎不认为这是一个真正的威胁,除非你真的让用户向你发送一个腌制对象@ 987654321@ 但是 p 在他的例子中是一个由 OP 从用户输入构造的对象,而不仅仅是如果我正确阅读的话,从用户发送的腌制数据。数据本身被转义了,所以除非对象的构造函数在不检查数据的情况下做一些奇怪的事情,否则应该没问题。 @Woot4Moo 即使他们有它,如果它只是输入(字符串/数字/布尔值)放在服务器端构造的对象中然后腌制,你将如何使用它运行任意代码? @Not_a_Golfer 下班回家后,我会查看所提供示例的漏洞利用代码。【参考方案2】:好吧照documentation
警告:
pickle
模块并非旨在防止错误或恶意构造的数据。永远不要解开从 不受信任或未经身份验证的来源。
这意味着如果数据结构存在于pickle算法将进入无法保证程序行为的状态的状态下,则可以通过调用它来攻击此功能。
据此site
import pickle
pickle.loads("cos\nsystem\n(S'ls ~'\ntR.") # This will run: ls ~
是执行任意代码所需的全部内容。那里还有其他示例,以及出于安全目的对酸洗进行“改进”。
【讨论】:
我看到了那个网站。只有被我的代码腌制的对象才会被取消腌制。问题是对象在被腌制之前是否可能包含一些字符串,这些字符串会欺骗pickle.loads()
函数以执行任意代码。
@Matty 在我看来,我可以给你一些字符串,即上面的那个,你会好好腌制它,然后把它解开为那个字符串。这会导致你执行我的声明。
@Matty 还假设攻击者知道您系统的所有内部工作原理以及文本将如何转义/未转义。
对示例中的字符串进行腌制,然后将其取消腌制将不会运行ls
。
@Woot4Moo 但是,您确实声称“您会很好地腌制它,然后将其作为字符串解开。这将导致您执行我的声明。”这不是真的。虽然您在回答中所说的一切都不正确,但我不确定它是否解决了这个问题,即您不是在处理不受信任的泡菜,而是在处理某种形式的不受信任数据的泡菜。也就是我们能不能构造一个字符串s
会导致pickle.loads(pickle.dumps(s))
出现问题?【参考方案3】:
我在the documentation of multiprocessing module 中找到了这个,我认为它回答了这个问题:
警告
Connection.recv() 方法自动解开它的数据 接收,这可能是一个安全风险,除非您可以信任 发送消息的进程。
因此,除非连接对象是使用 Pipe() 生成的,否则您 只应在执行某些操作后使用 recv() 和 send() 方法 一种身份验证。请参阅身份验证密钥。
(强调我的)
结论是,如果连接对象是使用受信任的管道生成的,即受信任的pickle,那么它可以安全地解开。
【讨论】:
以上是关于攻击 Python 的泡菜的主要内容,如果未能解决你的问题,请参考以下文章
Python网络编程8-实现SYN Flood攻击与图形化展示