简介
SaltStack是一种基于C/S架构的服务器基础架构集中管理平台,它是一种全新的基础设施管理方式,部署轻松,在几分钟内可运行起来,扩展性好,很容易管理上万台服务器,速度够快,服务器之间秒级通讯。
Saltstack使用Python开发,是一个非常简单易用和轻量级的管理工具。由Master和Minion构成,通过ZeroMQ进行通信,master可以通过发布消息来管理多个minion。
Saltstack的master端监听4505与4506端口,4505为salt的消息发布系统,4506为salt客户端与服务端通信的端口;salt客户端程序不监听端口,客户端启动后,会主动连接master端注册,然后一直保持该TCP连接,master通过这条TCP连接对客户端控制,
2020年4月30日 F-Secure 安全团队披露了关于SaltStack两个安全漏洞:CVE-2020-11651 权限缺陷、CVE-2020-11652 任意文件读写漏洞。受影响的版本为:
- CVE-2020-11651 SaltStack Salt before 2019.2.4 and 3000 before 3000.2
- CVE-2020-11652 SaltStack Salt before 2019.2.4 and 3000 before 3000.2
本文来分析并复现下CVE-2020-11651这个漏洞。
SaltStack安装
SaltStack有多种安装方式,这个是官方的安装教程,涵盖了多个平台的安装。但是我推荐使用Salt bootstrap的快速安装方式,只需一个脚本即可完成安装,项目地址:https://github.com/saltstack/salt-bootstrap/tree/stable.
由于本次只是为了漏洞的演示,所以使用docker快速安装。
使用以下命令即可完成安装
docker pull vulfocus/saltstack-cve_2020_11651 |
其实VULFOCUS上也集成了这个靶场.
先试用exp进行下验证, 使用的exp是github上开源的一个,https://github.com/0xc0d/CVE-2020-11651:
漏洞分析
在漏洞分析之前需要先梳理下SaltStack的认证方式:
上图为SaltStack Master和Monion的一个简单架构,Master负责管理众多Monion.
Salt master 与 minion 通讯采用的是”订阅-发布“的模式。
通讯的连接由 Salt minion 发起,这意味着 minion 无须开启进向的端口(注意:此方式极大地简便了网络规则的设定)。
而 Salt master 的 4505 和 4506 端口(默认)必须开启,以接收外部的连接。其中端口功能如下表所示。
1.当 minion 启动时,其将搜索网络中的 master。当找到时, minion 将发送公钥给 Salt master,从而实现初次握手。
2.当初次握手后,Salt minion 的公钥将被保存在服务端,此时 master 需要使用过 salt-key 命令接收公钥(也可以采用自动机制)。注意:在 Salt minion 的公钥被接收前,Salt master 是不会将密钥发放给 minion 的,也就是说 minion 在此之前不会执行任何命令。
3.当 Salt minion 的公钥被接收后,Salt master 就会把公钥连同用于加解密 master 信息的可变动 AES 密钥发送至 Salt minion。其中,返回给 Salt minion 的 AES 密钥由 minion 的公钥加密,可由 Salt minion 解密。
当密钥交换完毕后,后续的通讯过程就可以使用AES进行加密。
本次漏洞发生的原因就出在了4506端口上,由于Master端的ClearFuncs类处理未经身份验证的请求,并且调用_send_pub()方法,此方法可以获取root key从而导致可以以root权限执行任意命令。
看一下POC的核心语句:
在看代码:/salt/transport/zeromq.py
|
salt.transport.client.ReqChannel.factory 最后被实例化为AsyncZeroMQReqChannel,而且带有clear参数,即发给master的命令是clear没有AES加密的.
salt-master普遍使用这两行代码进行认证,其中clearload是可控输入点。
authtype, errname, key, sensitiveloadkeys = self.prepauthinfo(clearload) |
prep_auth_info首先会识别clear__load输入的字段并选用其中之一作为认证方式,然后传参到checkauthentication方法检验认证是否有效。
def prepauthinfo(self, clearload): |
在第三种认证方式auth_type==’user’中,会由_prep_auth__info获取到系统opt的key,传递到checkauthentication中和API参数中携带的key进行==比对。_
理论上_prep_auth_info是不可被外部调用的,漏洞成因即是攻击者通过匿名API直接调用_prep_auth_info方法,在回显中拿到self.key,并在后续的请求中使用获取到的key过验证,以root权限执行高危指令。