From 1f7cc25af94da334cad35beb94ed3b1e4ff76b72 Mon Sep 17 00:00:00 2001 From: Python3pkg Date: Wed, 17 May 2017 23:15:33 -0700 Subject: [PATCH 1/2] Convert to python3 --- Bluto/modules/bluto_logging.py | 2 +- Bluto/modules/bluto_logging.py.bak | 29 + Bluto/modules/data_mine.py | 24 +- Bluto/modules/data_mine.py.bak | 268 ++++++++ Bluto/modules/general.py | 62 +- Bluto/modules/general.py.bak | 242 ++++++++ Bluto/modules/get_dns.py | 34 +- Bluto/modules/get_dns.py.bak | 234 +++++++ Bluto/modules/get_file.py | 2 +- Bluto/modules/get_file.py.bak | 59 ++ Bluto/modules/output.py | 316 +++++----- Bluto/modules/output.py.bak | 965 +++++++++++++++++++++++++++++ Bluto/modules/search.py | 32 +- Bluto/modules/search.py.bak | 383 ++++++++++++ 14 files changed, 2416 insertions(+), 236 deletions(-) create mode 100644 Bluto/modules/bluto_logging.py.bak create mode 100644 Bluto/modules/data_mine.py.bak create mode 100644 Bluto/modules/general.py.bak create mode 100644 Bluto/modules/get_dns.py.bak create mode 100644 Bluto/modules/get_file.py.bak create mode 100644 Bluto/modules/output.py.bak create mode 100644 Bluto/modules/search.py.bak diff --git a/Bluto/modules/bluto_logging.py b/Bluto/modules/bluto_logging.py index a11e8ad..2f9c119 100644 --- a/Bluto/modules/bluto_logging.py +++ b/Bluto/modules/bluto_logging.py @@ -9,7 +9,7 @@ if not os.path.exists(LOG_DIR): os.makedirs(LOG_DIR) - os.chmod(LOG_DIR, 0700) + os.chmod(LOG_DIR, 0o700) open(INFO_LOG_FILE,'a').close() # set up formatting diff --git a/Bluto/modules/bluto_logging.py.bak b/Bluto/modules/bluto_logging.py.bak new file mode 100644 index 0000000..a11e8ad --- /dev/null +++ b/Bluto/modules/bluto_logging.py.bak @@ -0,0 +1,29 @@ +#!/usr/bin/python + +import logging +import sys +import site +import os +LOG_DIR = os.path.expanduser('~/Bluto/log/') +INFO_LOG_FILE = os.path.expanduser(LOG_DIR + 'bluto-info.log') + +if not os.path.exists(LOG_DIR): + os.makedirs(LOG_DIR) + os.chmod(LOG_DIR, 0700) + open(INFO_LOG_FILE,'a').close() + +# set up formatting +formatter = logging.Formatter('[%(asctime)s] %(module)s: %(message)s') + +# set up logging to a file for all levels WARNING and higher +fh2 = logging.FileHandler(INFO_LOG_FILE) +fh2.setLevel(logging.INFO) +fh2.setFormatter(formatter) + +# create Logger object +mylogger = logging.getLogger('MyLogger') +mylogger.setLevel(logging.INFO) +mylogger.addHandler(fh2) + +# create shortcut functions +info = mylogger.info diff --git a/Bluto/modules/data_mine.py b/Bluto/modules/data_mine.py index f72efbe..cf33efc 100644 --- a/Bluto/modules/data_mine.py +++ b/Bluto/modules/data_mine.py @@ -1,6 +1,6 @@ import pdfminer import requests -import urllib2 +import urllib.request, urllib.error, urllib.parse import oletools.thirdparty.olefile as olefile import os import traceback @@ -9,7 +9,7 @@ import random import math import sys -import Queue +import queue import time import threading import cgi @@ -17,10 +17,10 @@ from pdfminer.pdfparser import PDFParser from pdfminer.pdfdocument import PDFDocument from bs4 import BeautifulSoup -from bluto_logging import info, INFO_LOG_FILE -from get_file import get_user_agents -from search import doc_bing, doc_exalead -from general import get_size +from .bluto_logging import info, INFO_LOG_FILE +from .get_file import get_user_agents +from .search import doc_bing, doc_exalead +from .general import get_size @@ -29,7 +29,7 @@ def action_download(doc_list, docs): i = 0 download_list = [] initial_count = 0 - print 'Gathering Live Documents For Metadata Mining\n' + print('Gathering Live Documents For Metadata Mining\n') headers = { 'User-Agent': 'Mozilla/5.0 (Windows; U; Windows NT 6.0; pl; rv:1.9.1.2) Gecko/20090729 Firefox/3.5.2 GTB7.1 ( .NET CLR 3.5.30729', 'Referer': 'https://www.google.co.uk/', @@ -52,7 +52,7 @@ def action_download(doc_list, docs): code.write(r.content) code.close() initial_count += 1 - print('\tDownload Count: {}\r'.format(str(initial_count))), + print(('\tDownload Count: {}\r'.format(str(initial_count))), end=' ') info(str(doc).replace('%20', ' ')) download_list.append(str(doc).replace('%20', ' ')) @@ -66,7 +66,7 @@ def action_download(doc_list, docs): code.write(r.content) code.close() initial_count += 1 - print('\tDownload Count: {}\r'.format(str(initial_count))), + print(('\tDownload Count: {}\r'.format(str(initial_count))), end=' ') download_list.append(str(doc).replace('%20', ' ')) info(str(doc).replace('%20', ' ')) continue @@ -96,14 +96,14 @@ def action_download(doc_list, docs): if i < 1: sys.exit() data_size = get_size(docs) - print '\tData Downloaded: {}MB'.format(str(math.floor(data_size))) + print('\tData Downloaded: {}MB'.format(str(math.floor(data_size)))) info('Documents Downloaded: {}'.format(initial_count)) return download_list def doc_search(domain, USERAGENT_F, prox): - q1 = Queue.Queue() - q2 = Queue.Queue() + q1 = queue.Queue() + q2 = queue.Queue() t1 = threading.Thread(target=doc_bing, args=(domain, USERAGENT_F, prox, q1)) t2 = threading.Thread(target=doc_exalead, args=(domain, USERAGENT_F, prox, q2)) t1.start() diff --git a/Bluto/modules/data_mine.py.bak b/Bluto/modules/data_mine.py.bak new file mode 100644 index 0000000..f72efbe --- /dev/null +++ b/Bluto/modules/data_mine.py.bak @@ -0,0 +1,268 @@ +import pdfminer +import requests +import urllib2 +import oletools.thirdparty.olefile as olefile +import os +import traceback +import time +import re +import random +import math +import sys +import Queue +import time +import threading +import cgi +from termcolor import colored +from pdfminer.pdfparser import PDFParser +from pdfminer.pdfdocument import PDFDocument +from bs4 import BeautifulSoup +from bluto_logging import info, INFO_LOG_FILE +from get_file import get_user_agents +from search import doc_bing, doc_exalead +from general import get_size + + + +def action_download(doc_list, docs): + info('Document Download Started') + i = 0 + download_list = [] + initial_count = 0 + print 'Gathering Live Documents For Metadata Mining\n' + headers = { + 'User-Agent': 'Mozilla/5.0 (Windows; U; Windows NT 6.0; pl; rv:1.9.1.2) Gecko/20090729 Firefox/3.5.2 GTB7.1 ( .NET CLR 3.5.30729', + 'Referer': 'https://www.google.co.uk/', + 'Accept-Language': 'en-US,en;q=0.5', + 'Cache-Control': 'no-cache' + } + for doc in doc_list: + doc = doc.replace(' ', '%20') + try: + r = requests.get(doc.encode('utf-8'), headers=headers) + if r.status_code == 404: + r.raise_for_status() + + if r.status_code == 200: + params = cgi.parse_header(r.headers.get('Content-Disposition', ''))[-1] + if 'filename' not in params: + filename = str(doc).replace('%20', ' ').split('/')[-1] + with open(docs + filename, "w") as code: + i += 1 + code.write(r.content) + code.close() + initial_count += 1 + print('\tDownload Count: {}\r'.format(str(initial_count))), + info(str(doc).replace('%20', ' ')) + download_list.append(str(doc).replace('%20', ' ')) + + continue + else: + filename_t = re.search('filename="(.*)"', r.headers['content-disposition']) + filename = filename_t.group(1) + + with open(docs + filename, "w") as code: + i += 1 + code.write(r.content) + code.close() + initial_count += 1 + print('\tDownload Count: {}\r'.format(str(initial_count))), + download_list.append(str(doc).replace('%20', ' ')) + info(str(doc).replace('%20', ' ')) + continue + + + except ValueError: + info('No Filename in header') + pass + except AttributeError: + pass + except IOError: + info('Not Found: {}'.format(str(doc).replace('%20', ' '))) + pass + except requests.exceptions.HTTPError: + info('Error: File Not Found Server Side: HTTPError') + pass + except requests.exceptions.ConnectionError: + info('Error: File Not Found Server Side: ConnectionError') + pass + except KeyError: + pass + except Exception: + info('An Unhandled Exception Has Occured, Please Check The Log For Details\n' + INFO_LOG_FILE) + info(str(doc).replace('%20', ' ')) + info(r.headers) + pass + if i < 1: + sys.exit() + data_size = get_size(docs) + print '\tData Downloaded: {}MB'.format(str(math.floor(data_size))) + info('Documents Downloaded: {}'.format(initial_count)) + return download_list + + +def doc_search(domain, USERAGENT_F, prox): + q1 = Queue.Queue() + q2 = Queue.Queue() + t1 = threading.Thread(target=doc_bing, args=(domain, USERAGENT_F, prox, q1)) + t2 = threading.Thread(target=doc_exalead, args=(domain, USERAGENT_F, prox, q2)) + t1.start() + t2.start() + t1.join() + t2.join() + bing = q1.get() + exalead = q2.get() + list_d = bing + exalead + return list_d + + +#Extract Author PDF +def pdf_read(pdf_file_list): + info('Extracting PDF MetaData') + software_list = [] + user_names = [] + for filename in pdf_file_list: + info(filename) + try: + + fp = open(filename, 'rb') + parser = PDFParser(fp) + doc = PDFDocument(parser) + software = re.sub('[^0-9a-zA-Z]+', ' ', doc.info[0]['Creator']) + person = re.sub('[^0-9a-zA-Z]+', ' ', doc.info[0]['Author']) + if person: + oddity = re.match('(\s\w\s+(\w\s+)+\w)', person) + if oddity: + oddity = str(oddity.group(1)).replace(' ', '') + user_names.append(str(oddity).title()) + else: + user_names.append(str(person).title()) + if software: + oddity2 = re.match('(\s\w\s+(\w\s+)+\w)', software) + if oddity2: + oddity2 = str(oddity2.group(1)).replace(' ', '') + software_list.append(oddity2) + else: + software_list.append(software) + except IndexError: + continue + except pdfminer.pdfparser.PDFSyntaxError: + continue + except KeyError: + continue + except TypeError: + continue + except Exception: + info('An Unhandled Exception Has Occured, Please Check The Log For Details' + INFO_LOG_FILE) + continue + info('Finished Extracting PDF MetaData') + return (user_names, software_list) + + + +#Extract Author MS FILES +def ms_doc(ms_file_list): + software_list = [] + user_names = [] + info('Extracting MSDOCS MetaData') + for filename in ms_file_list: + try: + data = olefile.OleFileIO(filename) + meta = data.get_metadata() + author = re.sub('[^0-9a-zA-Z]+', ' ', meta.author) + company = re.sub('[^0-9a-zA-Z]+', ' ', meta.company) + software = re.sub('[^0-9a-zA-Z]+', ' ', meta.creating_application) + save_by = re.sub('[^0-9a-zA-Z]+', ' ', meta.last_saved_by) + if author: + oddity = re.match('(\s\w\s+(\w\s+)+\w)', author) + if oddity: + oddity = str(oddity.group(1)).replace(' ', '') + user_names.append(str(oddity).title()) + else: + user_names.append(str(author).title()) + if software: + oddity2 = re.match('(\s\w\s+(\w\s+)+\w)', software) + if oddity2: + oddity2 = str(oddity2.group(1)).replace(' ', '') + software_list.append(oddity2) + else: + software_list.append(software) + + if save_by: + oddity3 = re.match('(\s\w\s+(\w\s+)+\w)', save_by) + if oddity3: + oddity3 = str(oddity3.group(1)).replace(' ', '') + user_names.append(str(oddity3).title()) + else: + user_names.append(str(save_by).title()) + + except Exception: + pass + info('Finished Extracting MSDOC MetaData') + return (user_names, software_list) + +#Modules takes in DOMAIN, PROX, USERAGENTS outputs user_names, software_list +def doc_start(domain, USERAGENT_F, prox, q): + ms_list_ext = ('.docx', '.pptx', '.xlsx', '.doc', '.xls', '.ppt') + ms_file_list = [] + pdf_file_list = [] + info('Let The Hunt Begin') + domain_r = domain.split('.') + if not os.path.exists(os.path.expanduser('~/Bluto/doc/{}'.format(domain_r[0]))): + os.makedirs(os.path.expanduser('~/Bluto/doc/{}'.format(domain_r[0]))) + + location = os.path.expanduser('~/Bluto/doc/{}/'.format(domain_r[0])) + info('Data Folder Created ' + location) + docs = os.path.expanduser(location) + doc_list = doc_search(domain, USERAGENT_F, prox) + + if doc_list == []: + q.put(None) + return + doc_list = set(sorted(doc_list)) + download_list = action_download(doc_list, docs) + download_count = len(download_list) + + for root, dirs, files in os.walk(docs): + for filename in files: + if str(filename).endswith(ms_list_ext): + ms_file_list.append(os.path.join(root, filename)) + if str(filename).endswith('.pdf'): + pdf_file_list.append(os.path.join(root, filename)) + + if ms_file_list and pdf_file_list: + user_names_ms, software_list_ms = ms_doc(ms_file_list) + user_names_pdf, software_list_pdf = pdf_read(pdf_file_list) + user_names_t = user_names_ms + user_names_pdf + software_list_t = software_list_ms + software_list_pdf + + elif ms_file_list: + user_names_ms, software_list_ms = ms_doc(ms_file_list) + user_names_t = user_names_ms + software_list_t = software_list_ms + + elif pdf_file_list: + user_names_pdf, software_list_pdf = pdf_read(pdf_file_list) + user_names_t = user_names_pdf + software_list_t = software_list_pdf + else: + user_names_t = [] + software_list_t = [] + + if user_names_t and software_list_t: + user_names = sorted(set(user_names_t)) + software_list = sorted(set(software_list_t)) + info('The Hunt Ended') + q.put((user_names, software_list, download_count, download_list)) + + elif software_list_t: + software_list = sorted(set(software_list_t)) + user_names = [] + info('The Hunt Ended') + q.put((user_names, software_list, download_count, download_list)) + + elif user_names_t: + user_names = sorted(set(user_names_t)) + software_list = [] + info('The Hunt Ended') + q.put((user_names, software_list, download_count, download_list)) diff --git a/Bluto/modules/general.py b/Bluto/modules/general.py index 20e8b02..dc5470f 100644 --- a/Bluto/modules/general.py +++ b/Bluto/modules/general.py @@ -14,7 +14,7 @@ import dns.zone import traceback import os -from bluto_logging import info, INFO_LOG_FILE +from .bluto_logging import info, INFO_LOG_FILE default_s = False @@ -38,7 +38,7 @@ def action_whois(domain): try: company = whois_things['contacts']['registrant']['name'] except Exception: - print '\nThere seems to be no Registrar for this domain.' + print('\nThere seems to be no Registrar for this domain.') company = domain pass splitup = company.lower().split() @@ -46,13 +46,13 @@ def action_whois(domain): while True: if patern.search(domain): info('Whois Results Are Good ' + company) - print '\nThe Whois Results Look Promising: ' + colored('{}','green').format(company) - accept = raw_input(colored('\nIs The Search Term sufficient?: ','green')).lower() + print('\nThe Whois Results Look Promising: ' + colored('{}','green').format(company)) + accept = input(colored('\nIs The Search Term sufficient?: ','green')).lower() if accept in ('y', 'yes'): company = company break elif accept in ('n', 'no'): - temp_company = raw_input(colored('\nRegistered Company Name: ','green')) + temp_company = input(colored('\nRegistered Company Name: ','green')) if temp_company == '': info('User Supplied Blank Company') company = domain @@ -62,13 +62,13 @@ def action_whois(domain): company = temp_company break else: - print '\nThe Options Are yes|no Or y|no Not {}'.format(accept) + print('\nThe Options Are yes|no Or y|no Not {}'.format(accept)) else: info('Whois Results Not Good ' + company) - print colored("\n\tThe Whois Results Don't Look Very Promissing: '{}'","red") .format(company) - print'\nPlease Supply The Company Name\n\n\tThis Will Be Used To Query LinkedIn' - temp_company = raw_input(colored('\nRegistered Company Name: ','green')) + print(colored("\n\tThe Whois Results Don't Look Very Promissing: '{}'","red") .format(company)) + print('\nPlease Supply The Company Name\n\n\tThis Will Be Used To Query LinkedIn') + temp_company = input(colored('\nRegistered Company Name: ','green')) if temp_company == '': info('User Supplied Blank Company') company = domain @@ -86,8 +86,8 @@ def action_whois(domain): except KeyError: pass except pythonwhois.net.socket.errno.ETIMEDOUT: - print colored('\nWhoisError: You may be behind a proxy or firewall preventing whois lookups. Please supply the registered company name, if left blank the domain name ' + '"' + domain + '"' +' will be used for the Linkedin search. The results may not be as accurate.','red') - temp_company = raw_input(colored('\nRegistered Company Name: ','green')) + print(colored('\nWhoisError: You may be behind a proxy or firewall preventing whois lookups. Please supply the registered company name, if left blank the domain name ' + '"' + domain + '"' +' will be used for the Linkedin search. The results may not be as accurate.','red')) + temp_company = input(colored('\nRegistered Company Name: ','green')) if temp_company == '': company = domain else: @@ -95,9 +95,9 @@ def action_whois(domain): except Exception: info('An Unhandled Exception Has Occured, Please Check The Log For Details' + INFO_LOG_FILE) if 'company' not in locals(): - print 'There is no Whois data for this domain.\n\nPlease supply a company name.' + print('There is no Whois data for this domain.\n\nPlease supply a company name.') while True: - temp_company = raw_input(colored('\nRegistered Company Name: ','green')) + temp_company = input(colored('\nRegistered Company Name: ','green')) if temp_company == '': info('User Supplied Blank Company') company = domain @@ -124,9 +124,9 @@ def action_country_id(countries_file, prox): key, value = line.strip().split(';') tcountries_dic.update({key: value}) - countries_dic = dict((k.lower(), v.lower()) for k,v in tcountries_dic.iteritems()) + countries_dic = dict((k.lower(), v.lower()) for k,v in tcountries_dic.items()) - for country, server in countries_dic.items(): + for country, server in list(countries_dic.items()): country_list.append(country) country_list = [item.capitalize() for item in country_list] @@ -147,9 +147,9 @@ def action_country_id(countries_file, prox): except ValueError as e: if o == 0: - print colored('\nUnable to connect to the CountryID, we will retry.', 'red') + print(colored('\nUnable to connect to the CountryID, we will retry.', 'red')) if o > 0: - print '\nThis is {} of 3 attempts' .format(o) + print('\nThis is {} of 3 attempts' .format(o)) time.sleep(2) o += 1 if o == 4: @@ -158,9 +158,9 @@ def action_country_id(countries_file, prox): break if o == 4: - print colored('\nWe have been unable to connect to the CountryID service.\n','red') - print '\nPlease let Bluto know what country you hale from.\n' - print colored('Available Countries:\n', 'green') + print(colored('\nWe have been unable to connect to the CountryID service.\n','red')) + print('\nPlease let Bluto know what country you hale from.\n') + print(colored('Available Countries:\n', 'green')) if len(country_list) % 2 != 0: country_list.append(" ") @@ -170,22 +170,22 @@ def action_country_id(countries_file, prox): l2 = country_list[split:] for key, value in zip(l1,l2): - print "{0:<20s} {1}".format(key, value) + print("{0:<20s} {1}".format(key, value)) country_list = [item.lower() for item in country_list] while True: - originCountry = raw_input('\nCountry: ').lower() + originCountry = input('\nCountry: ').lower() if originCountry in country_list: break if originCountry == '': - print '\nYou have not selected a country so the default server will be used' + print('\nYou have not selected a country so the default server will be used') originCountry = 'United Kingdom'.lower() break else: - print '\nCheck your spelling and try again' + print('\nCheck your spelling and try again') - for country, server in countries_dic.items(): + for country, server in list(countries_dic.items()): if country == originCountry: userCountry = country userServer = server @@ -193,7 +193,7 @@ def action_country_id(countries_file, prox): else: - for country, server in countries_dic.items(): + for country, server in list(countries_dic.items()): if country == originCountry.lower(): userCountry = country userServer = server @@ -203,11 +203,11 @@ def action_country_id(countries_file, prox): userCountry = 'DEAFULT' pass else: - print 'Bluto currently doesn\'t have your countries google server available.\nPlease navigate to "https://freegeoip.net/json/" and post an issue to "https://github.com/darryllane/Bluto/issues"\nincluding the country value as shown in the json output\nYou have been assigned to http://www.google.co.uk for now.' + print('Bluto currently doesn\'t have your countries google server available.\nPlease navigate to "https://freegeoip.net/json/" and post an issue to "https://github.com/darryllane/Bluto/issues"\nincluding the country value as shown in the json output\nYou have been assigned to http://www.google.co.uk for now.') userServer = 'http://www.google.co.uk' userCountry = 'United Kingdom' - print '\n\tSearching From: {0}\n\tGoogle Server: {1}\n' .format(userCountry.title(), userServer) + print('\n\tSearching From: {0}\n\tGoogle Server: {1}\n' .format(userCountry.title(), userServer)) info('Country Identified: {}'.format(userCountry)) return (userCountry, userServer) @@ -230,13 +230,13 @@ def check_dom(domain, myResolver): if dom: pass except dns.resolver.NoNameservers: - print '\nError: \nDomain Not Valid, Check You Have Entered It Correctly\n' + print('\nError: \nDomain Not Valid, Check You Have Entered It Correctly\n') sys.exit() except dns.resolver.NXDOMAIN: - print '\nError: \nDomain Not Valid, Check You Have Entered It Correctly\n' + print('\nError: \nDomain Not Valid, Check You Have Entered It Correctly\n') sys.exit() except dns.exception.Timeout: - print '\nThe connection hit a timeout. Are you connected to the internet?\n' + print('\nThe connection hit a timeout. Are you connected to the internet?\n') sys.exit() except Exception: info('An Unhandled Exception Has Occured, Please Check The Log For Details' + INFO_LOG_FILE) diff --git a/Bluto/modules/general.py.bak b/Bluto/modules/general.py.bak new file mode 100644 index 0000000..20e8b02 --- /dev/null +++ b/Bluto/modules/general.py.bak @@ -0,0 +1,242 @@ +#!/usr/local/bin/python +# -*- coding: utf-8 -*- + +from termcolor import colored +import pythonwhois +import traceback +import requests +import datetime +import re +import sys +import socket +import dns.resolver +import dns.query +import dns.zone +import traceback +import os +from bluto_logging import info, INFO_LOG_FILE + + +default_s = False + +def get_size(dir_location): + start_path = dir_location + total_size = 0 + for dirpath, dirnames, filenames in os.walk(start_path): + for f in filenames: + fp = os.path.join(dirpath, f) + total_size += os.path.getsize(fp) + total_size = total_size / 1024.0 + total_size = total_size / 1024.0 + return total_size + + +def action_whois(domain): + + try: + whois_things = pythonwhois.get_whois(domain) + try: + company = whois_things['contacts']['registrant']['name'] + except Exception: + print '\nThere seems to be no Registrar for this domain.' + company = domain + pass + splitup = company.lower().split() + patern = re.compile('|'.join(splitup)) + while True: + if patern.search(domain): + info('Whois Results Are Good ' + company) + print '\nThe Whois Results Look Promising: ' + colored('{}','green').format(company) + accept = raw_input(colored('\nIs The Search Term sufficient?: ','green')).lower() + if accept in ('y', 'yes'): + company = company + break + elif accept in ('n', 'no'): + temp_company = raw_input(colored('\nRegistered Company Name: ','green')) + if temp_company == '': + info('User Supplied Blank Company') + company = domain + break + else: + info('User Supplied Company ' + company) + company = temp_company + break + else: + print '\nThe Options Are yes|no Or y|no Not {}'.format(accept) + + else: + info('Whois Results Not Good ' + company) + print colored("\n\tThe Whois Results Don't Look Very Promissing: '{}'","red") .format(company) + print'\nPlease Supply The Company Name\n\n\tThis Will Be Used To Query LinkedIn' + temp_company = raw_input(colored('\nRegistered Company Name: ','green')) + if temp_company == '': + info('User Supplied Blank Company') + company = domain + break + else: + info('User Supplied Company ' + company) + company = temp_company + break + + + except pythonwhois.shared.WhoisException: + pass + except socket.error: + pass + except KeyError: + pass + except pythonwhois.net.socket.errno.ETIMEDOUT: + print colored('\nWhoisError: You may be behind a proxy or firewall preventing whois lookups. Please supply the registered company name, if left blank the domain name ' + '"' + domain + '"' +' will be used for the Linkedin search. The results may not be as accurate.','red') + temp_company = raw_input(colored('\nRegistered Company Name: ','green')) + if temp_company == '': + company = domain + else: + company = temp_company + except Exception: + info('An Unhandled Exception Has Occured, Please Check The Log For Details' + INFO_LOG_FILE) + if 'company' not in locals(): + print 'There is no Whois data for this domain.\n\nPlease supply a company name.' + while True: + temp_company = raw_input(colored('\nRegistered Company Name: ','green')) + if temp_company == '': + info('User Supplied Blank Company') + company = domain + break + else: + company = temp_company + info('User Supplied Company ' + company) + break + + return company + +def action_country_id(countries_file, prox): + info('Identifying Country') + userCountry = '' + userServer = '' + userIP = '' + userID = False + o = 0 + tcountries_dic = {} + country_list = [] + + with open(countries_file) as fin: + for line in fin: + key, value = line.strip().split(';') + tcountries_dic.update({key: value}) + + countries_dic = dict((k.lower(), v.lower()) for k,v in tcountries_dic.iteritems()) + + for country, server in countries_dic.items(): + country_list.append(country) + + country_list = [item.capitalize() for item in country_list] + country_list.sort() + + while True: + try: + if prox == True: + proxy = {'http' : 'http://127.0.0.1:8080'} + r = requests.get(r'https://freegeoip.net/json/', proxies=proxy, verify=False) + ip = r.json()['ip'] + originCountry = r.json()['country_name'] + + else: + r = requests.get(r'https://freegeoip.net/json/', verify=False) + ip = r.json()['ip'] + originCountry = r.json()['country_name'] + + except ValueError as e: + if o == 0: + print colored('\nUnable to connect to the CountryID, we will retry.', 'red') + if o > 0: + print '\nThis is {} of 3 attempts' .format(o) + time.sleep(2) + o += 1 + if o == 4: + break + continue + break + + if o == 4: + print colored('\nWe have been unable to connect to the CountryID service.\n','red') + print '\nPlease let Bluto know what country you hale from.\n' + print colored('Available Countries:\n', 'green') + + if len(country_list) % 2 != 0: + country_list.append(" ") + + split = len(country_list)/2 + l1 = country_list[0:split] + l2 = country_list[split:] + + for key, value in zip(l1,l2): + print "{0:<20s} {1}".format(key, value) + + country_list = [item.lower() for item in country_list] + + while True: + originCountry = raw_input('\nCountry: ').lower() + if originCountry in country_list: + break + if originCountry == '': + print '\nYou have not selected a country so the default server will be used' + originCountry = 'United Kingdom'.lower() + break + else: + print '\nCheck your spelling and try again' + + for country, server in countries_dic.items(): + if country == originCountry: + userCountry = country + userServer = server + userID = True + + else: + + for country, server in countries_dic.items(): + if country == originCountry.lower(): + userCountry = country + userServer = server + userID = True + if userID == False: + if default_s == True: + userCountry = 'DEAFULT' + pass + else: + print 'Bluto currently doesn\'t have your countries google server available.\nPlease navigate to "https://freegeoip.net/json/" and post an issue to "https://github.com/darryllane/Bluto/issues"\nincluding the country value as shown in the json output\nYou have been assigned to http://www.google.co.uk for now.' + userServer = 'http://www.google.co.uk' + userCountry = 'United Kingdom' + + print '\n\tSearching From: {0}\n\tGoogle Server: {1}\n' .format(userCountry.title(), userServer) + info('Country Identified: {}'.format(userCountry)) + return (userCountry, userServer) + + +def action_bluto_use(countryID): + now = datetime.datetime.now() + try: + link = "http://darryllane.co.uk/bluto/log_use.php" + payload = {'country': countryID, 'Date': now} + requests.post(link, data=payload) + except Exception: + info('An Unhandled Exception Has Occured, Please Check The Log For Details' + INFO_LOG_FILE) + pass + + +def check_dom(domain, myResolver): + try: + myAnswers = myResolver.query(domain, "NS") + dom = str(myAnswers.canonical_name).strip('.') + if dom: + pass + except dns.resolver.NoNameservers: + print '\nError: \nDomain Not Valid, Check You Have Entered It Correctly\n' + sys.exit() + except dns.resolver.NXDOMAIN: + print '\nError: \nDomain Not Valid, Check You Have Entered It Correctly\n' + sys.exit() + except dns.exception.Timeout: + print '\nThe connection hit a timeout. Are you connected to the internet?\n' + sys.exit() + except Exception: + info('An Unhandled Exception Has Occured, Please Check The Log For Details' + INFO_LOG_FILE) diff --git a/Bluto/modules/get_dns.py b/Bluto/modules/get_dns.py index f8d3556..c0bddc0 100644 --- a/Bluto/modules/get_dns.py +++ b/Bluto/modules/get_dns.py @@ -8,7 +8,7 @@ import dns.resolver import random import string -from bluto_logging import info, INFO_LOG_FILE +from .bluto_logging import info, INFO_LOG_FILE from multiprocessing.dummy import Pool as ThreadPool from termcolor import colored @@ -29,7 +29,7 @@ def get_dns_details(domain, myResolver): zn_list =[] mx_list = [] try: - print "\nName Server:\n" + print("\nName Server:\n") myAnswers = myResolver.query(domain, "NS") for data in myAnswers.rrset: data1 = str(data) @@ -40,12 +40,12 @@ def get_dns_details(domain, myResolver): list(set(ns_list)) ns_list.sort() for i in ns_list: - print colored(i, 'green') + print(colored(i, 'green')) except dns.resolver.NoNameservers: info('\tNo Name Servers\nConfirm The Domain Name Is Correct.' + INFO_LOG_FILE, exc_info=True) sys.exit() except dns.resolver.NoAnswer: - print "\tNo DNS Servers" + print("\tNo DNS Servers") except dns.resolver.NXDOMAIN: info("\tDomain Does Not Exist" + INFO_LOG_FILE, exc_info=True) sys.exit() @@ -56,7 +56,7 @@ def get_dns_details(domain, myResolver): info('An Unhandled Exception Has Occured, Please Check The Log For Details\n' + INFO_LOG_FILE, exc_info=True) try: - print "\nMail Server:\n" + print("\nMail Server:\n") myAnswers = myResolver.query(domain, "MX") for data in myAnswers: data1 = str(data) @@ -66,9 +66,9 @@ def get_dns_details(domain, myResolver): list(set(mx_list)) mx_list.sort() for i in mx_list: - print colored(i, 'green') + print(colored(i, 'green')) except dns.resolver.NoAnswer: - print "\tNo Mail Servers" + print("\tNo Mail Servers") except Exception: info('An Unhandled Exception Has Occured, Please Check The Log For Details' + INFO_LOG_FILE) @@ -125,7 +125,7 @@ def action_brute_start(subs, myResolver): global myResolverG myResolverG = myResolver info('Bruting SubDomains') - print '\nBrute Forcing Sub-Domains\n' + print('\nBrute Forcing Sub-Domains\n') pool = ThreadPool(8) pool.map(action_brute, subs) pool.close() @@ -169,7 +169,7 @@ def action_brute_wild(sub_list, domain, myResolver): def action_zone_transfer(zn_list, domain): info('Attempting Zone Transfers') global clean_dump - print "\nAttempting Zone Transfers" + print("\nAttempting Zone Transfers") zn_list.sort() vuln = True vulnerable_listT = [] @@ -178,7 +178,7 @@ def action_zone_transfer(zn_list, domain): for ns in zn_list: try: z = dns.zone.from_xfr(dns.query.xfr(ns, domain, timeout=3)) - names = z.nodes.keys() + names = list(z.nodes.keys()) names.sort() if vuln == True: info('Vuln: {}'.format(ns)) @@ -197,21 +197,21 @@ def action_zone_transfer(zn_list, domain): if vulnerable_listF: - print "\nNot Vulnerable:\n" + print("\nNot Vulnerable:\n") for ns in vulnerable_listF: - print colored(ns, 'green') + print(colored(ns, 'green')) if vulnerable_listT: info('Vulnerable To Zone Transfers') - print "\nVulnerable:\n" + print("\nVulnerable:\n") for ns in vulnerable_listT: - print colored(ns,'red'), colored("\t" + "TCP/53", 'red') + print(colored(ns,'red'), colored("\t" + "TCP/53", 'red')) z = dns.zone.from_xfr(dns.query.xfr(vulnerable_listT[0], domain)) - names = z.nodes.keys() + names = list(z.nodes.keys()) names.sort() - print "\nRaw Zone Dump\n" + print("\nRaw Zone Dump\n") for n in names: data1 = "{}.{}" .format(n,domain) try: @@ -227,7 +227,7 @@ def action_zone_transfer(zn_list, domain): else: info('An Unhandled Exception Has Occured, Please Check The Log For Details\n' + INFO_LOG_FILE, exc_info=True) - print z[n].to_text(n) + print(z[n].to_text(n)) info('Completed Attempting Zone Transfers') clean_dump = sorted(set(dump_list)) diff --git a/Bluto/modules/get_dns.py.bak b/Bluto/modules/get_dns.py.bak new file mode 100644 index 0000000..f8d3556 --- /dev/null +++ b/Bluto/modules/get_dns.py.bak @@ -0,0 +1,234 @@ +#!/usr/local/bin/python + +# -*- coding: utf-8 -*- + +import sys +import traceback +import socket +import dns.resolver +import random +import string +from bluto_logging import info, INFO_LOG_FILE +from multiprocessing.dummy import Pool as ThreadPool +from termcolor import colored + +targets = [] + +def set_resolver(timeout_value): + myResolver = dns.resolver.Resolver() + myResolver.timeout = timeout_value + myResolver.lifetime = timeout_value + myResolver.nameservers = ['8.8.8.8', '8.8.4.4'] + + return myResolver + + +def get_dns_details(domain, myResolver): + info('Gathering DNS Details') + ns_list = [] + zn_list =[] + mx_list = [] + try: + print "\nName Server:\n" + myAnswers = myResolver.query(domain, "NS") + for data in myAnswers.rrset: + data1 = str(data) + data2 = (data1.rstrip('.')) + addr = socket.gethostbyname(data2) + ns_list.append(data2 + '\t' + addr) + zn_list.append(data2) + list(set(ns_list)) + ns_list.sort() + for i in ns_list: + print colored(i, 'green') + except dns.resolver.NoNameservers: + info('\tNo Name Servers\nConfirm The Domain Name Is Correct.' + INFO_LOG_FILE, exc_info=True) + sys.exit() + except dns.resolver.NoAnswer: + print "\tNo DNS Servers" + except dns.resolver.NXDOMAIN: + info("\tDomain Does Not Exist" + INFO_LOG_FILE, exc_info=True) + sys.exit() + except dns.resolver.Timeout: + info('\tTimeouted\nConfirm The Domain Name Is Correct.' + INFO_LOG_FILE, exc_info=True) + sys.exit() + except Exception: + info('An Unhandled Exception Has Occured, Please Check The Log For Details\n' + INFO_LOG_FILE, exc_info=True) + + try: + print "\nMail Server:\n" + myAnswers = myResolver.query(domain, "MX") + for data in myAnswers: + data1 = str(data) + data2 = (data1.split(' ',1)[1].rstrip('.')) + addr = socket.gethostbyname(data2) + mx_list.append(data2 + '\t' + addr) + list(set(mx_list)) + mx_list.sort() + for i in mx_list: + print colored(i, 'green') + except dns.resolver.NoAnswer: + print "\tNo Mail Servers" + except Exception: + info('An Unhandled Exception Has Occured, Please Check The Log For Details' + INFO_LOG_FILE) + + info('Completed Gathering DNS Details') + return zn_list + + +def action_wild_cards(domain, myResolver): + info('Checking Wild Cards') + try: + one = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(15)) + myAnswers = myResolver.query(str(one) + '.' + str(domain)) + + except dns.resolver.NoNameservers: + pass + + except dns.resolver.NoAnswer: + pass + + except dns.resolver.NXDOMAIN: + info('Wild Cards False') + return False + else: + info('Wild Cards True') + return True + + +def action_brute(subdomain): + global myResolverG + try: + myAnswers = myResolverG.query(subdomain) + for data in myAnswers: + targets.append(subdomain + ' ' + str(data)) + + except dns.resolver.NoNameservers: + pass + except dns.resolver.NXDOMAIN: + pass + except dns.resolver.NoAnswer: + pass + except dns.exception.SyntaxError: + pass + except dns.exception.Timeout: + info('Timeout: {}'.format(subdomain)) + pass + except dns.resolver.Timeout: + pass + except Exception: + info('An Unhandled Exception Has Occured, Please Check The Log For Details' + INFO_LOG_FILE) + info(traceback.print_exc()) + + +def action_brute_start(subs, myResolver): + global myResolverG + myResolverG = myResolver + info('Bruting SubDomains') + print '\nBrute Forcing Sub-Domains\n' + pool = ThreadPool(8) + pool.map(action_brute, subs) + pool.close() + info('Completed Bruting SubDomains') + + return targets + + +def action_brute_wild(sub_list, domain, myResolver): + info('Bruting Wild Card SubDomains') + target_results = [] + random_addrs = [] + for i in range(0,10,1): + one = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(15)) + myAnswers = myResolver.query(str(one) + '.' + str(domain)) + name = myAnswers.canonical_name + random_addr = socket.gethostbyname(str(name)) + random_addrs.append(random_addr) + random_addrs = sorted(set(random_addrs)) + for host in sub_list: + try: + host_host, host_addr = host.split(' ') + if host_addr in random_addrs: + pass + else: + target_results.append(host) + except dns.resolver.NoNameservers: + pass + except dns.resolver.NoAnswer: + pass + except dns.resolver.NXDOMAIN: + pass + except dns.name.EmptyLabel: + pass + except Exception: + continue + info('Completed Bruting Wild Card SubDomains') + return target_results + + +def action_zone_transfer(zn_list, domain): + info('Attempting Zone Transfers') + global clean_dump + print "\nAttempting Zone Transfers" + zn_list.sort() + vuln = True + vulnerable_listT = [] + vulnerable_listF = [] + dump_list = [] + for ns in zn_list: + try: + z = dns.zone.from_xfr(dns.query.xfr(ns, domain, timeout=3)) + names = z.nodes.keys() + names.sort() + if vuln == True: + info('Vuln: {}'.format(ns)) + vulnerable_listT.append(ns) + + except Exception as e: + error = str(e) + if error == 'Errno -2] Name or service not known': + pass + if error == "[Errno 54] Connection reset by peer" or "No answer or RRset not for qname": + info('Not Vuln: {}'.format(ns)) + vuln = False + vulnerable_listF.append(ns) + else: + info('An Unhandled Exception Has Occured, Please Check The Log For Details\n' + INFO_LOG_FILE, exc_info=True) + + + if vulnerable_listF: + print "\nNot Vulnerable:\n" + for ns in vulnerable_listF: + print colored(ns, 'green') + + if vulnerable_listT: + info('Vulnerable To Zone Transfers') + print "\nVulnerable:\n" + for ns in vulnerable_listT: + print colored(ns,'red'), colored("\t" + "TCP/53", 'red') + + + z = dns.zone.from_xfr(dns.query.xfr(vulnerable_listT[0], domain)) + names = z.nodes.keys() + names.sort() + print "\nRaw Zone Dump\n" + for n in names: + data1 = "{}.{}" .format(n,domain) + try: + addr = socket.gethostbyname(data1) + dump_list.append("{}.{} {}" .format(n, domain, addr)) + + except Exception as e: + error = str(e) + if error == "[Errno -5] No address associated with hostname": + pass + if error == 'Errno -2] Name or service not known': + pass + else: + info('An Unhandled Exception Has Occured, Please Check The Log For Details\n' + INFO_LOG_FILE, exc_info=True) + + print z[n].to_text(n) + + info('Completed Attempting Zone Transfers') + clean_dump = sorted(set(dump_list)) + return ((vulnerable_listT, clean_dump)) diff --git a/Bluto/modules/get_file.py b/Bluto/modules/get_file.py index 9d6aa4c..1fdd23f 100644 --- a/Bluto/modules/get_file.py +++ b/Bluto/modules/get_file.py @@ -5,7 +5,7 @@ import sys import random from termcolor import colored -from bluto_logging import info, INFO_LOG_FILE +from .bluto_logging import info, INFO_LOG_FILE def get_user_agents(useragent_f): info('Gathering UserAgents') diff --git a/Bluto/modules/get_file.py.bak b/Bluto/modules/get_file.py.bak new file mode 100644 index 0000000..9d6aa4c --- /dev/null +++ b/Bluto/modules/get_file.py.bak @@ -0,0 +1,59 @@ +#!/usr/local/bin/python +# -*- coding: utf-8 -*- + +import traceback +import sys +import random +from termcolor import colored +from bluto_logging import info, INFO_LOG_FILE + +def get_user_agents(useragent_f): + info('Gathering UserAgents') + uas = [] + with open(useragent_f, 'rb') as uaf: + for ua in uaf.readlines(): + if ua: + uas.append(ua.strip()[1:-1-1]) + random.shuffle(uas) + info('Completed Gathering UserAgents') + return uas + + +def get_subs(filename, domain): + info('Gathering SubDomains') + full_list = [] + try: + subs = [line.rstrip('\n') for line in open(filename)] + for sub in subs: + full_list.append(str(sub.lower() + "." + domain)) + except Exception: + info('An Unhandled Exception Has Occured, Please Check The Log For Details' + INFO_LOG_FILE) + sys.exit() + + info('Completed Gathering SubDomains') + return full_list + +def get_sub_interest(filename, domain): + info('Gathering SubDomains Of Interest') + full_list = [] + try: + subs = [line.rstrip('\n') for line in open(filename)] + for sub in subs: + full_list.append(str(sub.lower() + "." + domain)) + + except Exception: + info('An Unhandled Exception Has Occured, Please Check The Log For Details' + INFO_LOG_FILE) + sys.exit() + + info('Completed Gathering SubDomains Of Interest') + return full_list + + +def get_line_count(filename): + info('Gathering SubDomains Count') + lines = 0 + for line in open(filename): + lines += 1 + + info('Completed Gathering SubDomains Count') + return lines diff --git a/Bluto/modules/output.py b/Bluto/modules/output.py index 14668fb..be5d3f8 100644 --- a/Bluto/modules/output.py +++ b/Bluto/modules/output.py @@ -8,8 +8,8 @@ import webbrowser import shutil import os -from search import action_pwned -from bluto_logging import info, INFO_LOG_FILE, LOG_DIR +from .search import action_pwned +from .bluto_logging import info, INFO_LOG_FILE, LOG_DIR def action_output_vuln_zone(google_results, bing_results, linkedin_results, time_spent_email, time_spent_total, clean_dump, sub_intrest, domain, report_location, company, data_mine): @@ -63,33 +63,33 @@ def action_output_vuln_zone(google_results, bing_results, linkedin_results, time pwned_results = action_pwned(f_emails) c_accounts = len(pwned_results) - print '\n\nEmail Addresses:\n' + print('\n\nEmail Addresses:\n') write_html(email_evidence_results, linkedin_evidence_results, pwned_results, report_location, company, data_mine) if f_emails: for email in f_emails: - print str(email).replace("u'","").replace("'","").replace('[','').replace(']','') + print(str(email).replace("u'","").replace("'","").replace('[','').replace(']','')) else: - print '\tNo Data To Be Found' + print('\tNo Data To Be Found') - print '\nCompromised Accounts:\n' + print('\nCompromised Accounts:\n') if pwned_results: sorted_pwned = sorted(pwned_results) for account in sorted_pwned: - print 'Account: \t{}'.format(account[0]) - print 'Domain: \t{}'.format(account[1]) - print 'Date: \t{}\n'.format(account[3]) + print('Account: \t{}'.format(account[0])) + print('Domain: \t{}'.format(account[1])) + print('Date: \t{}\n'.format(account[3])) else: - print '\tNo Data To Be Found' + print('\tNo Data To Be Found') - print '\nLinkedIn Results:\n' + print('\nLinkedIn Results:\n') sorted_person = sorted(person_seen) if sorted_person: for person in sorted_person: - print person + print(person) else: - print '\tNo Data To Be Found' + print('\tNo Data To Be Found') if data_mine is not None: user_names = data_mine[0] @@ -99,20 +99,20 @@ def action_output_vuln_zone(google_results, bing_results, linkedin_results, time username_count = len(user_names) software_count = len(software_list) - print '\nData Found In Document MetaData' - print '\nPotential Usernames:\n' + print('\nData Found In Document MetaData') + print('\nPotential Usernames:\n') if user_names: for user in user_names: - print '\t' + colored(user, 'red') + print('\t' + colored(user, 'red')) else: - print '\tNo Data To Be Found' + print('\tNo Data To Be Found') - print '\nSoftware And Versions Found:\n' + print('\nSoftware And Versions Found:\n') if software_list: for software in software_list: - print '\t' + colored(software, 'red') + print('\t' + colored(software, 'red')) else: - print '\tNo Data To Be Found' + print('\tNo Data To Be Found') else: user_names = [] software_list = [] @@ -122,27 +122,27 @@ def action_output_vuln_zone(google_results, bing_results, linkedin_results, time target_dict = dict((x.split(' ') for x in clean_dump)) clean_target = collections.OrderedDict(sorted(target_dict.items())) - print "\nProcessed Dump\n" + print("\nProcessed Dump\n") bruted_count = len(clean_target) for item in clean_target: if item in sub_intrest: - print colored(item, 'red'), colored("\t" + clean_target[item], 'red') + print(colored(item, 'red'), colored("\t" + clean_target[item], 'red')) else: - print item, "\t" + target_dict[item] + print(item, "\t" + target_dict[item]) time_spent_email_f = str(datetime.timedelta(seconds=(time_spent_email))).split('.')[0] time_spent_total_f = str(datetime.timedelta(seconds=(time_spent_total))).split('.')[0] - print '\nHosts Identified: {}' .format(str(bruted_count)) - print 'Potential Emails Found: {}' .format(str(email_count)) - print 'Potential Staff Members Found: {}' .format(str(staff_count)) - print 'Compromised Accounts: {}' .format(str(c_accounts)) - print 'Potential Usernames Found: {}'.format(username_count) - print 'Potential Software Found: {}'.format(software_count) - print 'Documents Downloaded: {}'.format(download_count) - print "Email Enumeration:", time_spent_email_f - print "Total Time:", time_spent_total_f + print('\nHosts Identified: {}' .format(str(bruted_count))) + print('Potential Emails Found: {}' .format(str(email_count))) + print('Potential Staff Members Found: {}' .format(str(staff_count))) + print('Compromised Accounts: {}' .format(str(c_accounts))) + print('Potential Usernames Found: {}'.format(username_count)) + print('Potential Software Found: {}'.format(software_count)) + print('Documents Downloaded: {}'.format(download_count)) + print("Email Enumeration:", time_spent_email_f) + print("Total Time:", time_spent_total_f) info('Hosts Identified: {}' .format(str(bruted_count))) info("Total Time:" .format(str(time_spent_total_f))) @@ -160,24 +160,24 @@ def action_output_vuln_zone(google_results, bing_results, linkedin_results, time docs = os.path.expanduser('~/Bluto/doc/{}/'.format(domain_r[0])) answers = ['no','n','y','yes'] while True: - answer = raw_input("\nWould you like to keep all local data?\n(Local Logs, Downloded Documents, HTML Evidence Report)\n\nYes|No:").lower() + answer = input("\nWould you like to keep all local data?\n(Local Logs, Downloded Documents, HTML Evidence Report)\n\nYes|No:").lower() if answer in answers: if answer == 'y' or answer == 'yes': domain - print '\nThe documents are located here: {}'.format(docs) - print 'The logs are located here: {}.'.format(LOG_DIR) - print "\nAn evidence report has been written to {}\n".format(report_location) + print('\nThe documents are located here: {}'.format(docs)) + print('The logs are located here: {}.'.format(LOG_DIR)) + print("\nAn evidence report has been written to {}\n".format(report_location)) while True: - answer = raw_input("Would you like to open this report now? ").lower() + answer = input("Would you like to open this report now? ").lower() if answer in answers: if answer == 'y' or answer == 'yes': - print '\nOpening {}' .format(report_location) + print('\nOpening {}' .format(report_location)) webbrowser.open('file://' + str(report_location)) break else: break else: - print 'Your answer needs to be either yes|y|no|n rather than, {}' .format(answer) + print('Your answer needs to be either yes|y|no|n rather than, {}' .format(answer)) break else: shutil.rmtree(docs) @@ -185,7 +185,7 @@ def action_output_vuln_zone(google_results, bing_results, linkedin_results, time os.remove(report_location) break else: - print '\tYour answer needs to be either yes|y|no|n rather than, {}' .format(answer) + print('\tYour answer needs to be either yes|y|no|n rather than, {}' .format(answer)) def action_output_vuln_zone_hunter(google_results, bing_results, linkedin_results, time_spent_email, time_spent_total, clean_dump, sub_intrest, domain, emailHunter_results, args, report_location, company, data_mine): @@ -244,32 +244,32 @@ def action_output_vuln_zone_hunter(google_results, bing_results, linkedin_result pwned_results = action_pwned(f_emails) c_accounts = len(pwned_results) - print '\n\nEmail Addresses:\n' + print('\n\nEmail Addresses:\n') write_html(email_evidence_results, linkedin_evidence_results, pwned_results, report_location, company, data_mine) if f_emails: for email in f_emails: - print str(email).replace("u'","").replace("'","").replace('[','').replace(']','') + print(str(email).replace("u'","").replace("'","").replace('[','').replace(']','')) else: - print '\tNo Data To Be Found' + print('\tNo Data To Be Found') - print '\nCompromised Accounts:\n' + print('\nCompromised Accounts:\n') if pwned_results: sorted_pwned = sorted(pwned_results) for account in sorted_pwned: - print 'Account: \t{}'.format(account[0]) - print 'Domain: \t{}'.format(account[1]) - print 'Date: \t{}\n'.format(account[3]) + print('Account: \t{}'.format(account[0])) + print('Domain: \t{}'.format(account[1])) + print('Date: \t{}\n'.format(account[3])) else: - print '\tNo Data To Be Found' + print('\tNo Data To Be Found') - print '\nLinkedIn Results:\n' + print('\nLinkedIn Results:\n') sorted_person = sorted(person_seen) if sorted_person: for person in sorted_person: - print person + print(person) else: - print '\tNo Data To Be Found' + print('\tNo Data To Be Found') if data_mine is not None: user_names = data_mine[0] @@ -279,20 +279,20 @@ def action_output_vuln_zone_hunter(google_results, bing_results, linkedin_result username_count = len(user_names) software_count = len(software_list) - print '\nData Found In Document MetaData' - print '\nPotential Usernames:\n' + print('\nData Found In Document MetaData') + print('\nPotential Usernames:\n') if user_names: for user in user_names: - print '\t' + colored(user, 'red') + print('\t' + colored(user, 'red')) else: - print '\tNo Data To Be Found' + print('\tNo Data To Be Found') - print '\nSoftware And Versions Found:\n' + print('\nSoftware And Versions Found:\n') if software_list: for software in software_list: - print '\t' + colored(software, 'red') + print('\t' + colored(software, 'red')) else: - print '\tNo Data To Be Found' + print('\tNo Data To Be Found') else: user_names = [] software_list = [] @@ -303,26 +303,26 @@ def action_output_vuln_zone_hunter(google_results, bing_results, linkedin_result target_dict = dict((x.split(' ') for x in clean_dump)) clean_target = collections.OrderedDict(sorted(target_dict.items())) - print "\nProcessed Dump\n" + print("\nProcessed Dump\n") bruted_count = len(clean_target) for item in clean_target: if item in sub_intrest: - print colored(item, 'red'), colored("\t" + clean_target[item], 'red') + print(colored(item, 'red'), colored("\t" + clean_target[item], 'red')) else: - print item, "\t" + target_dict[item] + print(item, "\t" + target_dict[item]) time_spent_email_f = str(datetime.timedelta(seconds=(time_spent_email))).split('.')[0] time_spent_total_f = str(datetime.timedelta(seconds=(time_spent_total))).split('.')[0] - print '\nHosts Identified: {}' .format(str(bruted_count)) - print 'Potential Emails Found: {}' .format(str(email_count)) - print 'Potential Staff Members Found: {}' .format(str(staff_count)) - print 'Compromised Accounts: {}' .format(str(c_accounts)) - print 'Potential Usernames Found: {}'.format(username_count) - print 'Potential Software Found: {}'.format(software_count) - print 'Documents Downloaded: {}'.format(download_count) - print "Email Enumeration:", time_spent_email_f - print "Total Time:", time_spent_total_f + print('\nHosts Identified: {}' .format(str(bruted_count))) + print('Potential Emails Found: {}' .format(str(email_count))) + print('Potential Staff Members Found: {}' .format(str(staff_count))) + print('Compromised Accounts: {}' .format(str(c_accounts))) + print('Potential Usernames Found: {}'.format(username_count)) + print('Potential Software Found: {}'.format(software_count)) + print('Documents Downloaded: {}'.format(download_count)) + print("Email Enumeration:", time_spent_email_f) + print("Total Time:", time_spent_total_f) info('Hosts Identified: {}' .format(str(bruted_count))) info("Total Time:" .format(str(time_spent_total_f))) @@ -340,24 +340,24 @@ def action_output_vuln_zone_hunter(google_results, bing_results, linkedin_result docs = os.path.expanduser('~/Bluto/doc/{}/'.format(domain_r[0])) answers = ['no','n','y','yes'] while True: - answer = raw_input("\nWould you like to keep all local data?\n(Local Logs, Downloded Documents, HTML Evidence Report)\n\nYes|No:").lower() + answer = input("\nWould you like to keep all local data?\n(Local Logs, Downloded Documents, HTML Evidence Report)\n\nYes|No:").lower() if answer in answers: if answer == 'y' or answer == 'yes': domain - print '\nThe documents are located here: {}'.format(docs) - print 'The logs are located here: {}.'.format(LOG_DIR) - print "\nAn evidence report has been written to {}\n".format(report_location) + print('\nThe documents are located here: {}'.format(docs)) + print('The logs are located here: {}.'.format(LOG_DIR)) + print("\nAn evidence report has been written to {}\n".format(report_location)) while True: - answer = raw_input("Would you like to open this report now? ").lower() + answer = input("Would you like to open this report now? ").lower() if answer in answers: if answer == 'y' or answer == 'yes': - print '\nOpening {}' .format(report_location) + print('\nOpening {}' .format(report_location)) webbrowser.open('file://' + str(report_location)) break else: break else: - print 'Your answer needs to be either yes|y|no|n rather than, {}' .format(answer) + print('Your answer needs to be either yes|y|no|n rather than, {}' .format(answer)) break else: shutil.rmtree(docs) @@ -365,7 +365,7 @@ def action_output_vuln_zone_hunter(google_results, bing_results, linkedin_result os.remove(report_location) break else: - print '\tYour answer needs to be either yes|y|no|n rather than, {}' .format(answer) + print('\tYour answer needs to be either yes|y|no|n rather than, {}' .format(answer)) def action_output_wild_false(brute_results_dict, sub_intrest, google_results, bing_true_results, linkedin_results, check_count, domain, time_spent_email, time_spent_brute, time_spent_total, report_location, company, data_mine): @@ -419,34 +419,34 @@ def action_output_wild_false(brute_results_dict, sub_intrest, google_results, bi pwned_results = action_pwned(f_emails) c_accounts = len(pwned_results) - print '\n\nEmail Addresses:\n' + print('\n\nEmail Addresses:\n') write_html(email_evidence_results, linkedin_evidence_results, pwned_results, report_location, company, data_mine) if f_emails: for email in f_emails: - print str(email).replace("u'","").replace("'","").replace('[','').replace(']','') + print(str(email).replace("u'","").replace("'","").replace('[','').replace(']','')) else: - print '\tNo Data To Be Found' + print('\tNo Data To Be Found') - print '\nCompromised Accounts:\n' + print('\nCompromised Accounts:\n') if pwned_results: sorted_pwned = sorted(pwned_results) for account in sorted_pwned: - print 'Account: \t{}'.format(account[0]) - print 'Domain: \t{}'.format(account[1]) - print 'Date: \t{}\n'.format(account[3]) + print('Account: \t{}'.format(account[0])) + print('Domain: \t{}'.format(account[1])) + print('Date: \t{}\n'.format(account[3])) else: - print '\tNo Data To Be Found' + print('\tNo Data To Be Found') - print '\nLinkedIn Results:\n' + print('\nLinkedIn Results:\n') sorted_person = sorted(person_seen) if sorted_person: for person in sorted_person: - print person + print(person) else: - print '\tNo Data To Be Found' + print('\tNo Data To Be Found') if data_mine is not None: user_names = data_mine[0] @@ -456,20 +456,20 @@ def action_output_wild_false(brute_results_dict, sub_intrest, google_results, bi username_count = len(user_names) software_count = len(software_list) - print '\nData Found In Document MetaData' - print '\nPotential Usernames:\n' + print('\nData Found In Document MetaData') + print('\nPotential Usernames:\n') if user_names: for user in user_names: - print '\t' + colored(user, 'red') + print('\t' + colored(user, 'red')) else: - print '\tNo Data To Be Found' + print('\tNo Data To Be Found') - print '\nSoftware And Versions Found:\n' + print('\nSoftware And Versions Found:\n') if software_list: for software in software_list: - print '\t' + colored(software, 'red') + print('\t' + colored(software, 'red')) else: - print '\tNo Data To Be Found' + print('\tNo Data To Be Found') else: user_names = [] software_list = [] @@ -479,28 +479,28 @@ def action_output_wild_false(brute_results_dict, sub_intrest, google_results, bi sorted_dict = collections.OrderedDict(sorted(brute_results_dict.items())) bruted_count = len(sorted_dict) - print "\nBluto Results: \n" + print("\nBluto Results: \n") for item in sorted_dict: if item in sub_intrest: - print colored(item + "\t", 'red'), colored(sorted_dict[item], 'red') + print(colored(item + "\t", 'red'), colored(sorted_dict[item], 'red')) else: - print item + "\t",sorted_dict[item] + print(item + "\t",sorted_dict[item]) time_spent_email_f = str(datetime.timedelta(seconds=(time_spent_email))).split('.')[0] time_spent_brute_f = str(datetime.timedelta(seconds=(time_spent_brute))).split('.')[0] time_spent_total_f = str(datetime.timedelta(seconds=(time_spent_total))).split('.')[0] - print '\nHosts Identified: {}' .format(str(bruted_count)) - print 'Potential Emails Found: {}' .format(str(email_count)) - print 'Potential Staff Members Found: {}' .format(str(staff_count)) - print 'Compromised Accounts: {}' .format(str(c_accounts)) - print 'Potential Usernames Found: {}'.format(username_count) - print 'Potential Software Found: {}'.format(software_count) - print 'Documents Downloaded: {}'.format(download_count) - print "Email Enumeration:", time_spent_email_f - print "Requests executed:", str(check_count) + " in ", time_spent_brute_f - print "Total Time:", time_spent_total_f + print('\nHosts Identified: {}' .format(str(bruted_count))) + print('Potential Emails Found: {}' .format(str(email_count))) + print('Potential Staff Members Found: {}' .format(str(staff_count))) + print('Compromised Accounts: {}' .format(str(c_accounts))) + print('Potential Usernames Found: {}'.format(username_count)) + print('Potential Software Found: {}'.format(software_count)) + print('Documents Downloaded: {}'.format(download_count)) + print("Email Enumeration:", time_spent_email_f) + print("Requests executed:", str(check_count) + " in ", time_spent_brute_f) + print("Total Time:", time_spent_total_f) info('Hosts Identified: {}' .format(str(bruted_count))) info("Email Enumeration: {}" .format(str(time_spent_email_f))) @@ -518,24 +518,24 @@ def action_output_wild_false(brute_results_dict, sub_intrest, google_results, bi docs = os.path.expanduser('~/Bluto/doc/{}/'.format(domain_r[0])) answers = ['no','n','y','yes'] while True: - answer = raw_input("\nWould you like to keep all local data?\n(Local Logs, Downloded Documents, HTML Evidence Report)\n\nYes|No:").lower() + answer = input("\nWould you like to keep all local data?\n(Local Logs, Downloded Documents, HTML Evidence Report)\n\nYes|No:").lower() if answer in answers: if answer == 'y' or answer == 'yes': domain - print '\nThe documents are located here: {}'.format(docs) - print 'The logs are located here: {}.'.format(LOG_DIR) - print "\nAn evidence report has been written to {}\n".format(report_location) + print('\nThe documents are located here: {}'.format(docs)) + print('The logs are located here: {}.'.format(LOG_DIR)) + print("\nAn evidence report has been written to {}\n".format(report_location)) while True: - answer = raw_input("Would you like to open this report now? ").lower() + answer = input("Would you like to open this report now? ").lower() if answer in answers: if answer == 'y' or answer == 'yes': - print '\nOpening {}' .format(report_location) + print('\nOpening {}' .format(report_location)) webbrowser.open('file://' + str(report_location)) break else: break else: - print 'Your answer needs to be either yes|y|no|n rather than, {}' .format(answer) + print('Your answer needs to be either yes|y|no|n rather than, {}' .format(answer)) break else: shutil.rmtree(docs) @@ -543,7 +543,7 @@ def action_output_wild_false(brute_results_dict, sub_intrest, google_results, bi os.remove(report_location) break else: - print '\tYour answer needs to be either yes|y|no|n rather than, {}' .format(answer) + print('\tYour answer needs to be either yes|y|no|n rather than, {}' .format(answer)) def action_output_wild_false_hunter(brute_results_dict, sub_intrest, google_results, bing_true_results, linkedin_results, check_count, domain, time_spent_email, time_spent_brute, time_spent_total, emailHunter_results, args, report_location, company, data_mine): @@ -602,34 +602,34 @@ def action_output_wild_false_hunter(brute_results_dict, sub_intrest, google_resu pwned_results = action_pwned(f_emails) c_accounts = len(pwned_results) - print '\n\nEmail Addresses:\n' + print('\n\nEmail Addresses:\n') write_html(email_evidence_results, linkedin_evidence_results, pwned_results, report_location, company, data_mine) if f_emails: for email in f_emails: - print '\t' + str(email).replace("u'","").replace("'","").replace('[','').replace(']','') + print('\t' + str(email).replace("u'","").replace("'","").replace('[','').replace(']','')) else: - print '\tNo Data To Be Found' + print('\tNo Data To Be Found') - print '\nCompromised Accounts:\n' + print('\nCompromised Accounts:\n') if pwned_results: sorted_pwned = sorted(pwned_results) for account in sorted_pwned: - print 'Account: \t{}'.format(account[0]) - print ' Domain: \t{}'.format(account[1]) - print ' Date: \t{}\n'.format(account[3]) + print('Account: \t{}'.format(account[0])) + print(' Domain: \t{}'.format(account[1])) + print(' Date: \t{}\n'.format(account[3])) else: - print '\tNo Data To Be Found' + print('\tNo Data To Be Found') - print '\nLinkedIn Results:\n' + print('\nLinkedIn Results:\n') sorted_person = sorted(person_seen) if sorted_person: for person in sorted_person: - print person + print(person) else: - print '\tNo Data To Be Found' + print('\tNo Data To Be Found') if data_mine is not None: user_names = data_mine[0] @@ -639,20 +639,20 @@ def action_output_wild_false_hunter(brute_results_dict, sub_intrest, google_resu username_count = len(user_names) software_count = len(software_list) - print '\nData Found In Document MetaData' - print '\nPotential Usernames:\n' + print('\nData Found In Document MetaData') + print('\nPotential Usernames:\n') if user_names: for user in user_names: - print '\t' + colored(user, 'red') + print('\t' + colored(user, 'red')) else: - print '\tNo Data To Be Found' + print('\tNo Data To Be Found') - print '\nSoftware And Versions Found:\n' + print('\nSoftware And Versions Found:\n') if software_list: for software in software_list: - print '\t' + colored(software, 'red') + print('\t' + colored(software, 'red')) else: - print '\tNo Data To Be Found' + print('\tNo Data To Be Found') else: user_names = [] software_list = [] @@ -662,29 +662,29 @@ def action_output_wild_false_hunter(brute_results_dict, sub_intrest, google_resu sorted_dict = collections.OrderedDict(sorted(brute_results_dict.items())) bruted_count = len(sorted_dict) - print "\nBluto Results: \n" + print("\nBluto Results: \n") for item in sorted_dict: if item is not '*.' + domain: if item is not '@.' + domain: if item in sub_intrest: - print colored(item + "\t", 'red'), colored(sorted_dict[item], 'red') + print(colored(item + "\t", 'red'), colored(sorted_dict[item], 'red')) else: - print item + "\t",sorted_dict[item] + print(item + "\t",sorted_dict[item]) time_spent_email_f = str(datetime.timedelta(seconds=(time_spent_email))).split('.')[0] time_spent_brute_f = str(datetime.timedelta(seconds=(time_spent_brute))).split('.')[0] time_spent_total_f = str(datetime.timedelta(seconds=(time_spent_total))).split('.')[0] - print '\nHosts Identified: {}' .format(str(bruted_count)) - print 'Potential Emails Found: {}' .format(str(email_count)) - print 'Potential Staff Members Found: {}' .format(str(staff_count)) - print 'Compromised Accounts: {}' .format(str(c_accounts)) - print 'Potential Usernames Found: {}'.format(username_count) - print 'Potential Software Found: {}'.format(software_count) - print 'Documents Downloaded: {}'.format(download_count) - print "Email Enumeration:", time_spent_email_f - print "Requests executed:", str(check_count) + " in ", time_spent_brute_f - print "Total Time:", time_spent_total_f + print('\nHosts Identified: {}' .format(str(bruted_count))) + print('Potential Emails Found: {}' .format(str(email_count))) + print('Potential Staff Members Found: {}' .format(str(staff_count))) + print('Compromised Accounts: {}' .format(str(c_accounts))) + print('Potential Usernames Found: {}'.format(username_count)) + print('Potential Software Found: {}'.format(software_count)) + print('Documents Downloaded: {}'.format(download_count)) + print("Email Enumeration:", time_spent_email_f) + print("Requests executed:", str(check_count) + " in ", time_spent_brute_f) + print("Total Time:", time_spent_total_f) info('Hosts Identified: {}' .format(str(bruted_count))) info("Email Enumeration: {}" .format(str(time_spent_email_f))) @@ -700,25 +700,25 @@ def action_output_wild_false_hunter(brute_results_dict, sub_intrest, google_resu docs = os.path.expanduser('~/Bluto/doc/{}/'.format(domain_r[0])) answers = ['no','n','y','yes'] while True: - print colored("\nWould you like to keep all local data?\n(Local Logs, Downloded Documents, HTML Evidence Report)\n\nYes|No:", "red") - answer = raw_input("").lower() + print(colored("\nWould you like to keep all local data?\n(Local Logs, Downloded Documents, HTML Evidence Report)\n\nYes|No:", "red")) + answer = input("").lower() if answer in answers: if answer == 'y' or answer == 'yes': domain - print '\nThe documents are located here: {}'.format(docs) - print 'The logs are located here: {}.'.format(LOG_DIR) - print "\nAn evidence report has been written to {}\n".format(report_location) + print('\nThe documents are located here: {}'.format(docs)) + print('The logs are located here: {}.'.format(LOG_DIR)) + print("\nAn evidence report has been written to {}\n".format(report_location)) while True: - answer = raw_input("Would you like to open this report now? ").lower() + answer = input("Would you like to open this report now? ").lower() if answer in answers: if answer == 'y' or answer == 'yes': - print '\nOpening {}' .format(report_location) + print('\nOpening {}' .format(report_location)) webbrowser.open('file://' + str(report_location)) break else: break else: - print 'Your answer needs to be either yes|y|no|n rather than, {}' .format(answer) + print('Your answer needs to be either yes|y|no|n rather than, {}' .format(answer)) break else: shutil.rmtree(docs) @@ -726,7 +726,7 @@ def action_output_wild_false_hunter(brute_results_dict, sub_intrest, google_resu os.remove(report_location) break else: - print '\tYour answer needs to be either yes|y|no|n rather than, {}' .format(answer) + print('\tYour answer needs to be either yes|y|no|n rather than, {}' .format(answer)) def write_html(email_evidence_results, linkedin_evidence_results, pwned_results, report_location, company, data_mine): @@ -959,7 +959,7 @@ def write_html(email_evidence_results, linkedin_evidence_results, pwned_results, myFile.write('') myFile.close() info('Completed HTML Report') - except IOError,e: + except IOError as e: info('IOError', exc_info=True) except Exception: info('An Unhandled Exception Occured', exc_info=True) diff --git a/Bluto/modules/output.py.bak b/Bluto/modules/output.py.bak new file mode 100644 index 0000000..14668fb --- /dev/null +++ b/Bluto/modules/output.py.bak @@ -0,0 +1,965 @@ +#!/usr/local/bin/python +# -*- coding: utf-8 -*- + +from termcolor import colored +import traceback +import collections +import datetime +import webbrowser +import shutil +import os +from search import action_pwned +from bluto_logging import info, INFO_LOG_FILE, LOG_DIR + + +def action_output_vuln_zone(google_results, bing_results, linkedin_results, time_spent_email, time_spent_total, clean_dump, sub_intrest, domain, report_location, company, data_mine): + info('Output action_output_vuln_zone: Start') + linkedin_evidence_results = [] + email_evidence_results = [] + email_results = [] + email_seen = [] + url_seen = [] + person_seen = [] + final_emails = [] + + for email, url in google_results: + try: + e1, e2 = email.split(',') + if url not in email_seen: + email_seen.append(url) + email_evidence_results.append((str(e2).replace(' ',''),url)) + email_evidence_results.append((str(e1).replace(' ',''),url)) + email_results.append((str(e2).replace(' ',''))) + email_results.append((str(e1).replace(' ',''))) + + except ValueError: + if url not in email_seen: + email_seen.append(url) + email_evidence_results.append((str(email).replace(' ',''),url)) + email_results.append(str(email).replace(' ','')) + + for e, u in bing_results: + email_results.append(e) + if u not in url_seen: + email_evidence_results.append((e, u)) + + for url, person, description in linkedin_results: + if person not in person_seen: + person_seen.append(person) + linkedin_evidence_results.append((url, person, description)) + + linkedin_evidence_results.sort(key=lambda tup: tup[1]) + sorted_email = set(sorted(email_results)) + for email in sorted_email: + if email == '[]': + pass + elif email == '@' + domain: + pass + else: + final_emails.append(email) + email_count = len(final_emails) + staff_count = len(person_seen) + f_emails = sorted(final_emails) + pwned_results = action_pwned(f_emails) + c_accounts = len(pwned_results) + + print '\n\nEmail Addresses:\n' + write_html(email_evidence_results, linkedin_evidence_results, pwned_results, report_location, company, data_mine) + if f_emails: + for email in f_emails: + + print str(email).replace("u'","").replace("'","").replace('[','').replace(']','') + else: + print '\tNo Data To Be Found' + + print '\nCompromised Accounts:\n' + if pwned_results: + sorted_pwned = sorted(pwned_results) + for account in sorted_pwned: + print 'Account: \t{}'.format(account[0]) + print 'Domain: \t{}'.format(account[1]) + print 'Date: \t{}\n'.format(account[3]) + else: + print '\tNo Data To Be Found' + + print '\nLinkedIn Results:\n' + + sorted_person = sorted(person_seen) + if sorted_person: + for person in sorted_person: + print person + else: + print '\tNo Data To Be Found' + + if data_mine is not None: + user_names = data_mine[0] + software_list = data_mine[1] + download_count = data_mine[2] + download_list = data_mine[3] + username_count = len(user_names) + software_count = len(software_list) + + print '\nData Found In Document MetaData' + print '\nPotential Usernames:\n' + if user_names: + for user in user_names: + print '\t' + colored(user, 'red') + else: + print '\tNo Data To Be Found' + + print '\nSoftware And Versions Found:\n' + if software_list: + for software in software_list: + print '\t' + colored(software, 'red') + else: + print '\tNo Data To Be Found' + else: + user_names = [] + software_list = [] + download_count = 0 + username_count = len(user_names) + software_count = len(software_list) + + target_dict = dict((x.split(' ') for x in clean_dump)) + clean_target = collections.OrderedDict(sorted(target_dict.items())) + print "\nProcessed Dump\n" + + bruted_count = len(clean_target) + for item in clean_target: + if item in sub_intrest: + print colored(item, 'red'), colored("\t" + clean_target[item], 'red') + else: + print item, "\t" + target_dict[item] + + time_spent_email_f = str(datetime.timedelta(seconds=(time_spent_email))).split('.')[0] + time_spent_total_f = str(datetime.timedelta(seconds=(time_spent_total))).split('.')[0] + + print '\nHosts Identified: {}' .format(str(bruted_count)) + print 'Potential Emails Found: {}' .format(str(email_count)) + print 'Potential Staff Members Found: {}' .format(str(staff_count)) + print 'Compromised Accounts: {}' .format(str(c_accounts)) + print 'Potential Usernames Found: {}'.format(username_count) + print 'Potential Software Found: {}'.format(software_count) + print 'Documents Downloaded: {}'.format(download_count) + print "Email Enumeration:", time_spent_email_f + print "Total Time:", time_spent_total_f + + info('Hosts Identified: {}' .format(str(bruted_count))) + info("Total Time:" .format(str(time_spent_total_f))) + info("Email Enumeration: {}" .format(str(time_spent_email_f))) + info('Compromised Accounts: {}' .format(str(c_accounts))) + info('Potential Usernames Found: {}'.format(username_count)) + info('Potential Software Found: {}'.format(software_count)) + info('Documents Downloaded: {}'.format(download_count)) + info('Potential Staff Members Found: {}' .format(str(staff_count))) + info('Potential Emails Found: {}' .format(str(email_count))) + info('DNS Vuln Run completed') + info('Output action_output_vuln_zone: Complete') + + domain_r = domain.split('.') + docs = os.path.expanduser('~/Bluto/doc/{}/'.format(domain_r[0])) + answers = ['no','n','y','yes'] + while True: + answer = raw_input("\nWould you like to keep all local data?\n(Local Logs, Downloded Documents, HTML Evidence Report)\n\nYes|No:").lower() + if answer in answers: + if answer == 'y' or answer == 'yes': + domain + print '\nThe documents are located here: {}'.format(docs) + print 'The logs are located here: {}.'.format(LOG_DIR) + print "\nAn evidence report has been written to {}\n".format(report_location) + while True: + answer = raw_input("Would you like to open this report now? ").lower() + if answer in answers: + if answer == 'y' or answer == 'yes': + print '\nOpening {}' .format(report_location) + webbrowser.open('file://' + str(report_location)) + break + else: + break + else: + print 'Your answer needs to be either yes|y|no|n rather than, {}' .format(answer) + break + else: + shutil.rmtree(docs) + shutil.rmtree(LOG_DIR) + os.remove(report_location) + break + else: + print '\tYour answer needs to be either yes|y|no|n rather than, {}' .format(answer) + + +def action_output_vuln_zone_hunter(google_results, bing_results, linkedin_results, time_spent_email, time_spent_total, clean_dump, sub_intrest, domain, emailHunter_results, args, report_location, company, data_mine): + info('Output action_output_vuln_zone_hunter: Start') + linkedin_evidence_results = [] + email_evidence_results = [] + email_results = [] + email_seen = [] + url_seen = [] + person_seen = [] + final_emails = [] + + if emailHunter_results is not None: + for email in emailHunter_results: + email_results.append(email[0]) + email_evidence_results.append((email[0],email[1])) + + for email, url in google_results: + try: + e1, e2 = email.split(',') + if url not in email_seen: + email_seen.append(url) + email_evidence_results.append((str(e2).replace(' ',''),url)) + email_evidence_results.append((str(e1).replace(' ',''),url)) + email_results.append((str(e2).replace(' ',''))) + email_results.append((str(e1).replace(' ',''))) + + except ValueError: + if url not in email_seen: + email_seen.append(url) + email_evidence_results.append((str(email).replace(' ',''),url)) + email_results.append(str(email).replace(' ','')) + + for e, u in bing_results: + email_results.append(e) + if u not in url_seen: + email_evidence_results.append((e, u)) + + for url, person, description in linkedin_results: + if person not in person_seen: + person_seen.append(person) + linkedin_evidence_results.append((url, person, description)) + + linkedin_evidence_results.sort(key=lambda tup: tup[1]) + sorted_email = set(sorted(email_results)) + for email in sorted_email: + if email == '[]': + pass + elif email == '@' + domain: + pass + else: + final_emails.append(email) + email_count = len(final_emails) + staff_count = len(person_seen) + f_emails = sorted(final_emails) + pwned_results = action_pwned(f_emails) + c_accounts = len(pwned_results) + + print '\n\nEmail Addresses:\n' + write_html(email_evidence_results, linkedin_evidence_results, pwned_results, report_location, company, data_mine) + if f_emails: + for email in f_emails: + print str(email).replace("u'","").replace("'","").replace('[','').replace(']','') + else: + print '\tNo Data To Be Found' + + print '\nCompromised Accounts:\n' + if pwned_results: + sorted_pwned = sorted(pwned_results) + for account in sorted_pwned: + print 'Account: \t{}'.format(account[0]) + print 'Domain: \t{}'.format(account[1]) + print 'Date: \t{}\n'.format(account[3]) + else: + print '\tNo Data To Be Found' + + print '\nLinkedIn Results:\n' + + sorted_person = sorted(person_seen) + if sorted_person: + for person in sorted_person: + print person + else: + print '\tNo Data To Be Found' + + if data_mine is not None: + user_names = data_mine[0] + software_list = data_mine[1] + download_count = data_mine[2] + download_list = data_mine[3] + username_count = len(user_names) + software_count = len(software_list) + + print '\nData Found In Document MetaData' + print '\nPotential Usernames:\n' + if user_names: + for user in user_names: + print '\t' + colored(user, 'red') + else: + print '\tNo Data To Be Found' + + print '\nSoftware And Versions Found:\n' + if software_list: + for software in software_list: + print '\t' + colored(software, 'red') + else: + print '\tNo Data To Be Found' + else: + user_names = [] + software_list = [] + download_count = 0 + username_count = len(user_names) + software_count = len(software_list) + + target_dict = dict((x.split(' ') for x in clean_dump)) + clean_target = collections.OrderedDict(sorted(target_dict.items())) + + print "\nProcessed Dump\n" + bruted_count = len(clean_target) + for item in clean_target: + if item in sub_intrest: + print colored(item, 'red'), colored("\t" + clean_target[item], 'red') + else: + print item, "\t" + target_dict[item] + + time_spent_email_f = str(datetime.timedelta(seconds=(time_spent_email))).split('.')[0] + time_spent_total_f = str(datetime.timedelta(seconds=(time_spent_total))).split('.')[0] + + print '\nHosts Identified: {}' .format(str(bruted_count)) + print 'Potential Emails Found: {}' .format(str(email_count)) + print 'Potential Staff Members Found: {}' .format(str(staff_count)) + print 'Compromised Accounts: {}' .format(str(c_accounts)) + print 'Potential Usernames Found: {}'.format(username_count) + print 'Potential Software Found: {}'.format(software_count) + print 'Documents Downloaded: {}'.format(download_count) + print "Email Enumeration:", time_spent_email_f + print "Total Time:", time_spent_total_f + + info('Hosts Identified: {}' .format(str(bruted_count))) + info("Total Time:" .format(str(time_spent_total_f))) + info("Email Enumeration: {}" .format(str(time_spent_email_f))) + info('Compromised Accounts: {}' .format(str(c_accounts))) + info('Potential Usernames Found: {}'.format(username_count)) + info('Potential Software Found: {}'.format(software_count)) + info('Documents Downloaded: {}'.format(download_count)) + info('Potential Staff Members Found: {}' .format(str(staff_count))) + info('Potential Emails Found: {}' .format(str(email_count))) + info('DNS Vuln Run completed') + info('Output action_output_vuln_zone_hunter: Completed') + + domain_r = domain.split('.') + docs = os.path.expanduser('~/Bluto/doc/{}/'.format(domain_r[0])) + answers = ['no','n','y','yes'] + while True: + answer = raw_input("\nWould you like to keep all local data?\n(Local Logs, Downloded Documents, HTML Evidence Report)\n\nYes|No:").lower() + if answer in answers: + if answer == 'y' or answer == 'yes': + domain + print '\nThe documents are located here: {}'.format(docs) + print 'The logs are located here: {}.'.format(LOG_DIR) + print "\nAn evidence report has been written to {}\n".format(report_location) + while True: + answer = raw_input("Would you like to open this report now? ").lower() + if answer in answers: + if answer == 'y' or answer == 'yes': + print '\nOpening {}' .format(report_location) + webbrowser.open('file://' + str(report_location)) + break + else: + break + else: + print 'Your answer needs to be either yes|y|no|n rather than, {}' .format(answer) + break + else: + shutil.rmtree(docs) + shutil.rmtree(LOG_DIR) + os.remove(report_location) + break + else: + print '\tYour answer needs to be either yes|y|no|n rather than, {}' .format(answer) + + +def action_output_wild_false(brute_results_dict, sub_intrest, google_results, bing_true_results, linkedin_results, check_count, domain, time_spent_email, time_spent_brute, time_spent_total, report_location, company, data_mine): + info('Output action_output_wild_false: Start') + linkedin_evidence_results = [] + email_evidence_results = [] + email_results = [] + email_seen = [] + url_seen = [] + person_seen = [] + final_emails = [] + + for email, url in google_results: + try: + e1, e2 = email.split(',') + if url not in email_seen: + email_seen.append(url) + email_evidence_results.append((str(e2).replace(' ',''),url)) + email_evidence_results.append((str(e1).replace(' ',''),url)) + email_results.append((str(e2).replace(' ',''))) + email_results.append((str(e1).replace(' ',''))) + + except ValueError: + if url not in email_seen: + email_seen.append(url) + email_evidence_results.append((str(email).replace(' ',''),url)) + email_results.append(str(email).replace(' ','')) + + for e, u in bing_true_results: + email_results.append(e) + if u not in url_seen: + email_evidence_results.append((e, u)) + + for url, person, description in linkedin_results: + if person not in person_seen: + person_seen.append(person) + linkedin_evidence_results.append((url, person, description)) + + linkedin_evidence_results.sort(key=lambda tup: tup[1]) + sorted_email = set(sorted(email_results)) + for email in sorted_email: + if email == '[]': + pass + elif email == '@' + domain: + pass + else: + final_emails.append(email) + email_count = len(final_emails) + staff_count = len(person_seen) + f_emails = sorted(final_emails) + pwned_results = action_pwned(f_emails) + c_accounts = len(pwned_results) + + print '\n\nEmail Addresses:\n' + write_html(email_evidence_results, linkedin_evidence_results, pwned_results, report_location, company, data_mine) + if f_emails: + + for email in f_emails: + + print str(email).replace("u'","").replace("'","").replace('[','').replace(']','') + else: + print '\tNo Data To Be Found' + + print '\nCompromised Accounts:\n' + if pwned_results: + sorted_pwned = sorted(pwned_results) + for account in sorted_pwned: + print 'Account: \t{}'.format(account[0]) + print 'Domain: \t{}'.format(account[1]) + print 'Date: \t{}\n'.format(account[3]) + else: + print '\tNo Data To Be Found' + + print '\nLinkedIn Results:\n' + + sorted_person = sorted(person_seen) + if sorted_person: + for person in sorted_person: + print person + else: + print '\tNo Data To Be Found' + + if data_mine is not None: + user_names = data_mine[0] + software_list = data_mine[1] + download_count = data_mine[2] + download_list = data_mine[3] + username_count = len(user_names) + software_count = len(software_list) + + print '\nData Found In Document MetaData' + print '\nPotential Usernames:\n' + if user_names: + for user in user_names: + print '\t' + colored(user, 'red') + else: + print '\tNo Data To Be Found' + + print '\nSoftware And Versions Found:\n' + if software_list: + for software in software_list: + print '\t' + colored(software, 'red') + else: + print '\tNo Data To Be Found' + else: + user_names = [] + software_list = [] + download_count = 0 + username_count = len(user_names) + software_count = len(software_list) + + sorted_dict = collections.OrderedDict(sorted(brute_results_dict.items())) + bruted_count = len(sorted_dict) + print "\nBluto Results: \n" + for item in sorted_dict: + if item in sub_intrest: + print colored(item + "\t", 'red'), colored(sorted_dict[item], 'red') + else: + print item + "\t",sorted_dict[item] + + + time_spent_email_f = str(datetime.timedelta(seconds=(time_spent_email))).split('.')[0] + time_spent_brute_f = str(datetime.timedelta(seconds=(time_spent_brute))).split('.')[0] + time_spent_total_f = str(datetime.timedelta(seconds=(time_spent_total))).split('.')[0] + + print '\nHosts Identified: {}' .format(str(bruted_count)) + print 'Potential Emails Found: {}' .format(str(email_count)) + print 'Potential Staff Members Found: {}' .format(str(staff_count)) + print 'Compromised Accounts: {}' .format(str(c_accounts)) + print 'Potential Usernames Found: {}'.format(username_count) + print 'Potential Software Found: {}'.format(software_count) + print 'Documents Downloaded: {}'.format(download_count) + print "Email Enumeration:", time_spent_email_f + print "Requests executed:", str(check_count) + " in ", time_spent_brute_f + print "Total Time:", time_spent_total_f + + info('Hosts Identified: {}' .format(str(bruted_count))) + info("Email Enumeration: {}" .format(str(time_spent_email_f))) + info('Compromised Accounts: {}' .format(str(c_accounts))) + info('Potential Staff Members Found: {}' .format(str(staff_count))) + info('Potential Emails Found: {}' .format(str(email_count))) + info('Potential Usernames Found: {}'.format(username_count)) + info('Potential Software Found: {}'.format(software_count)) + info('Documents Downloaded: {}'.format(download_count)) + info("Total Time:" .format(str(time_spent_total_f))) + info('DNS No Wild Cards + Email Hunter Run completed') + info('Output action_output_wild_false: Completed') + + domain_r = domain.split('.') + docs = os.path.expanduser('~/Bluto/doc/{}/'.format(domain_r[0])) + answers = ['no','n','y','yes'] + while True: + answer = raw_input("\nWould you like to keep all local data?\n(Local Logs, Downloded Documents, HTML Evidence Report)\n\nYes|No:").lower() + if answer in answers: + if answer == 'y' or answer == 'yes': + domain + print '\nThe documents are located here: {}'.format(docs) + print 'The logs are located here: {}.'.format(LOG_DIR) + print "\nAn evidence report has been written to {}\n".format(report_location) + while True: + answer = raw_input("Would you like to open this report now? ").lower() + if answer in answers: + if answer == 'y' or answer == 'yes': + print '\nOpening {}' .format(report_location) + webbrowser.open('file://' + str(report_location)) + break + else: + break + else: + print 'Your answer needs to be either yes|y|no|n rather than, {}' .format(answer) + break + else: + shutil.rmtree(docs) + shutil.rmtree(LOG_DIR) + os.remove(report_location) + break + else: + print '\tYour answer needs to be either yes|y|no|n rather than, {}' .format(answer) + + +def action_output_wild_false_hunter(brute_results_dict, sub_intrest, google_results, bing_true_results, linkedin_results, check_count, domain, time_spent_email, time_spent_brute, time_spent_total, emailHunter_results, args, report_location, company, data_mine): + info('Output action_output_wild_false_hunter: Start') + linkedin_evidence_results = [] + email_evidence_results = [] + email_results = [] + email_seen = [] + url_seen = [] + person_seen = [] + final_emails = [] + + if emailHunter_results is not None: + for email in emailHunter_results: + email_results.append(email[0]) + email_evidence_results.append((email[0],email[1])) + + for email, url in google_results: + try: + e1, e2 = email.split(',') + if url not in email_seen: + email_seen.append(url) + email_evidence_results.append((str(e2).replace(' ',''),url)) + email_evidence_results.append((str(e1).replace(' ',''),url)) + email_results.append((str(e2).replace(' ',''))) + email_results.append((str(e1).replace(' ',''))) + + except ValueError: + if url not in email_seen: + email_seen.append(url) + email_evidence_results.append((str(email).replace(' ',''),url)) + email_results.append(str(email).replace(' ','')) + + for e, u in bing_true_results: + email_results.append(e) + if u not in url_seen: + email_evidence_results.append((e, u)) + + for url, person, description in linkedin_results: + if person not in person_seen: + person_seen.append(person) + linkedin_evidence_results.append((url, person, description)) + + linkedin_evidence_results.sort(key=lambda tup: tup[1]) + sorted_email = set(sorted(email_results)) + for email in sorted_email: + if email == '[]': + pass + elif email == '@' + domain: + pass + else: + final_emails.append(email) + email_count = len(final_emails) + staff_count = len(person_seen) + f_emails = sorted(final_emails) + pwned_results = action_pwned(f_emails) + c_accounts = len(pwned_results) + + print '\n\nEmail Addresses:\n' + write_html(email_evidence_results, linkedin_evidence_results, pwned_results, report_location, company, data_mine) + if f_emails: + + for email in f_emails: + + print '\t' + str(email).replace("u'","").replace("'","").replace('[','').replace(']','') + else: + print '\tNo Data To Be Found' + + print '\nCompromised Accounts:\n' + if pwned_results: + sorted_pwned = sorted(pwned_results) + for account in sorted_pwned: + print 'Account: \t{}'.format(account[0]) + print ' Domain: \t{}'.format(account[1]) + print ' Date: \t{}\n'.format(account[3]) + else: + print '\tNo Data To Be Found' + + print '\nLinkedIn Results:\n' + + sorted_person = sorted(person_seen) + if sorted_person: + for person in sorted_person: + print person + else: + print '\tNo Data To Be Found' + + if data_mine is not None: + user_names = data_mine[0] + software_list = data_mine[1] + download_count = data_mine[2] + download_list = data_mine[3] + username_count = len(user_names) + software_count = len(software_list) + + print '\nData Found In Document MetaData' + print '\nPotential Usernames:\n' + if user_names: + for user in user_names: + print '\t' + colored(user, 'red') + else: + print '\tNo Data To Be Found' + + print '\nSoftware And Versions Found:\n' + if software_list: + for software in software_list: + print '\t' + colored(software, 'red') + else: + print '\tNo Data To Be Found' + else: + user_names = [] + software_list = [] + download_count = 0 + username_count = len(user_names) + software_count = len(software_list) + + sorted_dict = collections.OrderedDict(sorted(brute_results_dict.items())) + bruted_count = len(sorted_dict) + print "\nBluto Results: \n" + for item in sorted_dict: + if item is not '*.' + domain: + if item is not '@.' + domain: + if item in sub_intrest: + print colored(item + "\t", 'red'), colored(sorted_dict[item], 'red') + else: + print item + "\t",sorted_dict[item] + + time_spent_email_f = str(datetime.timedelta(seconds=(time_spent_email))).split('.')[0] + time_spent_brute_f = str(datetime.timedelta(seconds=(time_spent_brute))).split('.')[0] + time_spent_total_f = str(datetime.timedelta(seconds=(time_spent_total))).split('.')[0] + + print '\nHosts Identified: {}' .format(str(bruted_count)) + print 'Potential Emails Found: {}' .format(str(email_count)) + print 'Potential Staff Members Found: {}' .format(str(staff_count)) + print 'Compromised Accounts: {}' .format(str(c_accounts)) + print 'Potential Usernames Found: {}'.format(username_count) + print 'Potential Software Found: {}'.format(software_count) + print 'Documents Downloaded: {}'.format(download_count) + print "Email Enumeration:", time_spent_email_f + print "Requests executed:", str(check_count) + " in ", time_spent_brute_f + print "Total Time:", time_spent_total_f + + info('Hosts Identified: {}' .format(str(bruted_count))) + info("Email Enumeration: {}" .format(str(time_spent_email_f))) + info('Compromised Accounts: {}' .format(str(c_accounts))) + info('Potential Staff Members Found: {}' .format(str(staff_count))) + info('Potential Emails Found: {}' .format(str(email_count))) + info("Total Time:" .format(str(time_spent_total_f))) + info('Documents Downloaded: {}'.format(download_count)) + info('DNS No Wild Cards + Email Hunter Run completed') + info('Output action_output_wild_false_hunter: Completed') + + domain_r = domain.split('.') + docs = os.path.expanduser('~/Bluto/doc/{}/'.format(domain_r[0])) + answers = ['no','n','y','yes'] + while True: + print colored("\nWould you like to keep all local data?\n(Local Logs, Downloded Documents, HTML Evidence Report)\n\nYes|No:", "red") + answer = raw_input("").lower() + if answer in answers: + if answer == 'y' or answer == 'yes': + domain + print '\nThe documents are located here: {}'.format(docs) + print 'The logs are located here: {}.'.format(LOG_DIR) + print "\nAn evidence report has been written to {}\n".format(report_location) + while True: + answer = raw_input("Would you like to open this report now? ").lower() + if answer in answers: + if answer == 'y' or answer == 'yes': + print '\nOpening {}' .format(report_location) + webbrowser.open('file://' + str(report_location)) + break + else: + break + else: + print 'Your answer needs to be either yes|y|no|n rather than, {}' .format(answer) + break + else: + shutil.rmtree(docs) + shutil.rmtree(LOG_DIR) + os.remove(report_location) + break + else: + print '\tYour answer needs to be either yes|y|no|n rather than, {}' .format(answer) + + +def write_html(email_evidence_results, linkedin_evidence_results, pwned_results, report_location, company, data_mine): + info('Started HTML Report') + if data_mine is not None: + user_names = data_mine[0] + software_list = data_mine[1] + download_count = data_mine[2] + download_list = data_mine[3] + username_count = len(user_names) + software_count = len(software_list) + header = ''' + + + + + + + +
+

Bluto Evidence Report

+

{a}

+
+ '''.format(a=company) + footer = ''' + + + + + ''' + + emailDescription =''' + +

Email Evidence:

+ +
+

+ Email evidence includes the email address and the location it was found, this allows for potential remediation. + If corporate emails are to be utilised in the public domain, it is recommended that they are generic in nature and are not able to + authenticate to any public corporate services such as VPN, or similare remote control services. + + This data can also be used in further attack vectors such as potential targets for Social Engineering and Phishing attacks. +

+
+ + ''' + metaDescription =''' + +

MetaData Evidence:

+ +
+

+ Various techniques were used to gather potentially useful information on the scoped domain. The consultant + identified multiple documents available for download from the scoped domains website/s. These documents could hold potentially + sensitive data such as usernames, email addresses, folder structures, printers, operating system version information and + software version information. This information can prove to be very useful to an attacker when targeting various vectors + such as Social Engineering, password attacks and to expose further attack vectors. + + It is recommended that all document metadata is sanitised before being published into the public domain. +

+
+ + ''' + + linkedinDescription =''' + +

LinkedIn Evidence:

+ +
+

+ Staff names, job roles and associations can be gathered from social media sites such as LinkedIn. This information can be used + to attempt futher information gathering via vectors such as Social Engineering techniques, phone attacks, and phishing attacks. This data can also be used to try determine more + information such as potential email addresses. +

+
+ + ''' + + compromisedDescription =''' + +

Compromised Account Evidence:

+ +
+

+ This data was made publicly available due to a breach, this means that these account passwords and any portals that are utilised by these accounts + could be compromised. It is recommedned that all account passwords are modified and made to adhere to company policy. +

+
+ + ''' + + try: + with open(report_location, 'w') as myFile: + myFile.write(header) + myFile.write('
') + if email_evidence_results: + myFile.write(emailDescription) + myFile.write('') + myFile.write('') + myFile.write('') + myFile.write('') + myFile.write('') + for email, url in email_evidence_results: + myFile.write('') + myFile.write(''.format(email)) + myFile.write(''.format(url)) + myFile.write('') + myFile.write('
Email AddressURL Address
{}{}
') + if linkedin_evidence_results: + myFile.write(linkedinDescription) + if linkedin_evidence_results: + for url, person, clean in linkedin_evidence_results: + myFile.write('') + myFile.write('

'.format(person)) + myFile.write('') + myFile.write(''.format(clean)) + myFile.write('') + myFile.write(''.format(url)) + myFile.write('

') + myFile.write('
Person: {}
Role: {}
Url: {}
') + if pwned_results: + myFile.write(compromisedDescription) + myFile.write('') + if pwned_results: + for result in pwned_results: + myFile.write('

'.format(result[0])) + myFile.write('') + myFile.write(''.format(result[1])) + myFile.write('') + myFile.write(''.format(result[2])) + myFile.write('') + myFile.write(''.format(result[3])) + myFile.write('') + myFile.write(''.format(result[4])) + myFile.write('') + myFile.write(''.format(result[5])) + myFile.write('

') + myFile.write('
Email: {}
Domain: {}
Data: {}
Compromise Date: {}
Date Added: {}
Description:

{}

') + if data_mine: + myFile.write(metaDescription) + myFile.write('') + if data_mine: + myFile.write('') + if software_count: + myFile.write('') + if username_count: + myFile.write('') + if download_count: + myFile.write('') + myFile.write('') + myFile.write('') + if software_count: + myFile.write(''.format(software_count)) + if username_count: + myFile.write(''.format(username_count)) + if download_count: + myFile.write(''.format(download_count)) + myFile.write('') + myFile.write('
Software CountUsername CountDownload Count
{}{}{}
') + myFile.write('') + myFile.write('
') + if user_names: + myFile.write('') + myFile.write('') + myFile.write('') + for username in user_names: + myFile.write('') + myFile.write(''.format(username)) + myFile.write('') + myFile.write('
Usernames
{}
') + myFile.write('') + myFile.write('
') + if software_list: + myFile.write('') + myFile.write('') + myFile.write('') + for software in software_list: + myFile.write('') + myFile.write(''.format(software)) + myFile.write('') + myFile.write('
Software
{}
') + myFile.write('') + if download_list: + myFile.write('') + myFile.write('') + myFile.write('') + for doc in download_list: + myFile.write('') + myFile.write(''.format(doc)) + myFile.write('') + myFile.write('
Document
{}
') + myFile.write('
') + myFile.write(footer) + myFile.write('') + myFile.write('') + myFile.close() + info('Completed HTML Report') + except IOError,e: + info('IOError', exc_info=True) + except Exception: + info('An Unhandled Exception Occured', exc_info=True) diff --git a/Bluto/modules/search.py b/Bluto/modules/search.py index c3cb949..e111b8b 100644 --- a/Bluto/modules/search.py +++ b/Bluto/modules/search.py @@ -9,11 +9,11 @@ import requests import random import time -import urllib2 +import urllib.request, urllib.error, urllib.parse import json from termcolor import colored from bs4 import BeautifulSoup -from bluto_logging import info, INFO_LOG_FILE +from .bluto_logging import info, INFO_LOG_FILE requests.packages.urllib3.disable_warnings() @@ -63,7 +63,7 @@ def action_google(domain, userCountry, userServer, q, user_agents, prox): url = div.find('cite').text email = str(match).replace("u'",'').replace('[','').replace(']','').replace("'",'') entries_tuples.append((email.lower(),str(url).replace("u'",'').replace("'",""))) - except Exception, e: + except Exception as e: pass time.sleep(3) for urls in entries_tuples: @@ -154,21 +154,21 @@ def action_emailHunter(domain, api, user_agents, q, prox): elif response.status_code == 401: json_data = response.json() if json_data['message'] =='Too many calls for this period.': - print colored("\tError:\tIt seems the Hunter API key being used has reached\n\t\tit's limit for this month.", 'red') - print colored('\tAPI Key: {}\n'.format(api),'red') + print(colored("\tError:\tIt seems the Hunter API key being used has reached\n\t\tit's limit for this month.", 'red')) + print(colored('\tAPI Key: {}\n'.format(api),'red')) q.put(None) return None if json_data['message'] == 'Invalid or missing api key.': - print colored("\tError:\tIt seems the Hunter API key being used is no longer valid,\nit was probably deleted.", 'red') - print colored('\tAPI Key: {}\n'.format(api),'red') - print colored('\tWhy don\'t you grab yourself a new one (they are free)','green') - print colored('\thttps://hunter.io/api_keys','green') + print(colored("\tError:\tIt seems the Hunter API key being used is no longer valid,\nit was probably deleted.", 'red')) + print(colored('\tAPI Key: {}\n'.format(api),'red')) + print(colored('\tWhy don\'t you grab yourself a new one (they are free)','green')) + print(colored('\thttps://hunter.io/api_keys','green')) q.put(None) return None else: raise ValueError('No Response From Hunter') - except UnboundLocalError,e: - print e + except UnboundLocalError as e: + print(e) except KeyError: pass except ValueError: @@ -245,7 +245,7 @@ def doc_exalead(domain, user_agents, prox, q): break for div in soup.findAll('li', {'class': 'media'}): document = div.find('a', href=True)['href'] - document = urllib2.unquote(document) + document = urllib.parse.unquote(document) document_list.append(document) except Exception: @@ -287,7 +287,7 @@ def doc_bing(domain, user_agents, prox, q): for div in divs: h2 = div.find('h2') document = h2.find('a', href=True)['href'] - document = urllib2.unquote(document) + document = urllib.parse.unquote(document) document_list.append(document) except requests.models.ChunkedEncodingError: continue @@ -351,7 +351,7 @@ def action_linkedin(domain, userCountry, q, company, user_agents, prox): def action_netcraft(domain, myResolver): info('NetCraft Search Started') netcraft_list = [] - print "\nPassive Gatherings From NetCraft\n" + print("\nPassive Gatherings From NetCraft\n") try: link = "http://searchdns.netcraft.com/?restriction=site+contains&host=*.{}&lookup=wait..&position=limited" .format (domain) response = requests.get(link) @@ -369,7 +369,7 @@ def action_netcraft(domain, myResolver): netcheck = myResolver.query(item + '.' + domain) for data in netcheck: netcraft_list.append(item + '.' + domain + ' ' + str(data)) - print colored(item + '.' + domain, 'red') + print(colored(item + '.' + domain, 'red')) except dns.exception.Timeout: pass except dns.resolver.NXDOMAIN: @@ -377,7 +377,7 @@ def action_netcraft(domain, myResolver): except Exception: info('An Unhandled Exception Has Occured, Please Check The Log For Details\n' + INFO_LOG_FILE, exc_info=True) else: - print '\tNo Results Found' + print('\tNo Results Found') info('NetCraft Completed') return netcraft_list diff --git a/Bluto/modules/search.py.bak b/Bluto/modules/search.py.bak new file mode 100644 index 0000000..c3cb949 --- /dev/null +++ b/Bluto/modules/search.py.bak @@ -0,0 +1,383 @@ +#!/usr/local/bin/python +# -*- coding: utf-8 -*- + +import dns.resolver +import unicodedata +import traceback +import sys +import re +import requests +import random +import time +import urllib2 +import json +from termcolor import colored +from bs4 import BeautifulSoup +from bluto_logging import info, INFO_LOG_FILE + +requests.packages.urllib3.disable_warnings() + +def action_google(domain, userCountry, userServer, q, user_agents, prox): + info('Google Search Started') + uas = user_agents + searchfor = '@' + '"' + domain + '"' + entries_tuples = [] + seen = set() + results = [] + for start in range(1,10,1): + ua = random.choice(uas) + try: + if prox == True: + proxy = {'http' : 'http://127.0.0.1:8080'} + else: + pass + headers = {"User-Agent" : ua, + 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', + 'Accept-Language': 'en-US,en;q=0.5', + 'Accept-Encoding': 'gzip, deflate', + 'Referer': 'https://www.google.com'} + payload = { 'nord':'1', 'q': searchfor, 'start': start*10} + + link = '{0}/search?num=200' .format(userServer) + if prox == True: + response = requests.get(link, headers=headers, params=payload, proxies=proxy) + else: + response = requests.get(link, headers=headers, params=payload) + + response.raise_for_status() + response.text.encode('ascii', 'ignore').decode('ascii') + soup = BeautifulSoup(response.text, "lxml") + + for div in soup.select("div.g"): + + for div in soup.select("div.g"): + + email_temp = div.find("span", class_="st") + clean = re.sub('', '', email_temp.text) + clean = re.sub('', '', email_temp.text) + match = re.findall('[a-zA-Z0-9.]*' + '@' + domain, clean) + try: + if match: + if match is not '@' + domain: + if match is not '@': + url = div.find('cite').text + email = str(match).replace("u'",'').replace('[','').replace(']','').replace("'",'') + entries_tuples.append((email.lower(),str(url).replace("u'",'').replace("'",""))) + except Exception, e: + pass + time.sleep(3) + for urls in entries_tuples: + if urls[1] not in seen: + results.append(urls) + seen.add(urls[1]) + except requests.exceptions.HTTPError as e: + if e.response.status_code == 503: + info('Google is responding with a Captcha, other searches will continue') + break + except AttributeError as f: + pass + except Exception: + info('An Unhandled Exception Has Occured, Please Check The Log For Details' + INFO_LOG_FILE) + + info('Google Search Completed') + q.put(sorted(results)) + + +#Takes [list[tuples]]email~url #Returns [list[tuples]]email_address, url_found, breach_domain, breach_data, breach_date, / +#breach_added, breach_description +def action_pwned(emails): + info('Compromised Account Enumeration Search Started') + pwend_data = [] + seen = set() + for email in emails: + link = 'https://haveibeenpwned.com/api/v2/breachedaccount/{}'.format(email) + try: + headers = {"Connection" : "close", + "User-Agent" : "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)", + 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', + 'Accept-Language': 'en-US,en;q=0.5', + 'Accept-Encoding': 'gzip, deflate'} + + response = requests.get(link, headers=headers) + json_data = response.json() + if json_data: + if email in seen: + pass + else: + for item in json_data: + seen.add(email) + email_address = email + breach_domain = str(item['Domain']).replace("u'","") + breach_data = str(item['DataClasses']).replace("u'","'").replace('"','').replace('[','').replace(']','') + breach_date = str(item['BreachDate']).replace("u'","") + breach_added = str(item['AddedDate']).replace("u'","").replace('T',' ').replace('Z','') + breach_description = str(item['Description']).replace("u'","") + pwend_data.append((email_address, breach_domain, breach_data, breach_date, breach_added, breach_description)) + + except ValueError: + pass + except Exception: + info('An Unhandled Exception Has Occured, Please Check The Log For Details\n' + INFO_LOG_FILE, exc_info=True) + + info('Compromised Account Enumeration Search Completed') + return pwend_data + + +#Takes domain[str], api[list], user_agents[list] #Returns email,url [list[tuples]] Queue[object], prox[str] +def action_emailHunter(domain, api, user_agents, q, prox): + info('Email Hunter Search Started') + emails = [] + uas = user_agents + ua = random.choice(uas) + link = 'https://api.emailhunter.co/v1/search?domain={0}&api_key={1}'.format(domain,api) + + if prox == True: + proxy = {'http' : 'http://127.0.0.1:8080'} + else: + pass + try: + headers = {"User-Agent" : ua, + 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', + 'Accept-Language': 'en-US,en;q=0.5', + 'Accept-Encoding': 'gzip, deflate'} + if prox == True: + response = requests.get(link, headers=headers, proxies=proxy) + else: + response = requests.get(link, headers=headers) + if response.status_code == 200: + json_data = response.json() + for value in json_data['emails']: + for domain in value['sources']: + url = str(domain['uri']).replace("u'","") + email = str(value['value']).replace("u'","") + emails.append((email,url)) + elif response.status_code == 401: + json_data = response.json() + if json_data['message'] =='Too many calls for this period.': + print colored("\tError:\tIt seems the Hunter API key being used has reached\n\t\tit's limit for this month.", 'red') + print colored('\tAPI Key: {}\n'.format(api),'red') + q.put(None) + return None + if json_data['message'] == 'Invalid or missing api key.': + print colored("\tError:\tIt seems the Hunter API key being used is no longer valid,\nit was probably deleted.", 'red') + print colored('\tAPI Key: {}\n'.format(api),'red') + print colored('\tWhy don\'t you grab yourself a new one (they are free)','green') + print colored('\thttps://hunter.io/api_keys','green') + q.put(None) + return None + else: + raise ValueError('No Response From Hunter') + except UnboundLocalError,e: + print e + except KeyError: + pass + except ValueError: + info(traceback.print_exc()) + pass + except Exception: + traceback.print_exc() + info('An Unhandled Exception Has Occured, Please Check The Log For Details\n' + INFO_LOG_FILE, exc_info=True) + + info('Email Hunter Search Completed') + q.put(sorted(emails)) + + +def action_bing_true(domain, q, user_agents, prox): + info('Bing Search Started') + emails = [] + uas = user_agents + searchfor = '@' + '"' + domain + '"' + for start in range(0,30): + ua = random.choice(uas) + if prox == True: + proxy = {'http' : 'http://127.0.0.1:8080'} + else: + pass + try: + headers = {"Connection" : "close", + "User-Agent" : ua, + 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', + 'Accept-Language': 'en-US,en;q=0.5', + 'Accept-Encoding': 'gzip, deflate'} + payload = { 'q': searchfor, 'first': start} + link = 'https://www.bing.com/search' + if prox == True: + response = requests.get(link, headers=headers, params=payload, proxies=proxy) + else: + response = requests.get(link, headers=headers, params=payload) + reg_emails = re.compile('[a-zA-Z0-9.-]*' + '@' + '') + temp = reg_emails.findall(response.text) + time.sleep(1) + for item in temp: + clean = item.replace("", "") + email.append(clean + domain) + + except Exception: + continue + info('Bing Search Completed') + q.put(sorted(emails)) + +def doc_exalead(domain, user_agents, prox, q): + document_list = [] + uas = user_agents + info('Exalead Document Search Started') + for start in range(0,80,10): + ua = random.choice(uas) + link = 'http://www.exalead.com/search/web/results/?search_language=&q=(filetype:xls+OR+filetype:doc+OR++filetype:pdf+OR+filetype:ppt)+site:{}&search_language=&elements_per_page=10&start_index={}'.format(domain, start) + if prox == True: + proxy = {'http' : 'http://127.0.0.1:8080'} + else: + pass + try: + headers = {"Connection" : "close", + "User-Agent" : ua, + 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', + 'Accept-Language': 'en-US,en;q=0.5', + 'Accept-Encoding': 'gzip, deflate'} + if prox == True: + response = requests.get(link, headers=headers, proxies=proxy) + else: + response = requests.get(link, headers=headers) + soup = BeautifulSoup(response.text, "lxml") + if soup.find('label', {'class': 'control-label', 'for': 'id_captcha'}): + info("So you don't like spinach?") + info("Captchas are preventing some document searches.") + break + for div in soup.findAll('li', {'class': 'media'}): + document = div.find('a', href=True)['href'] + document = urllib2.unquote(document) + document_list.append(document) + + except Exception: + info('An Unhandled Exception Has Occured, Please Check The Log For Details' + INFO_LOG_FILE) + continue + + time.sleep(10) + potential_docs = len(document_list) + info('Exalead Document Search Finished') + info('Potential Exalead Documents Found: {}'.format(potential_docs)) + q.put(document_list) + +def doc_bing(domain, user_agents, prox, q): + document_list = [] + uas = user_agents + info('Bing Document Search Started') + for start in range(1,300,10): + ua = random.choice(uas) + if prox == True: + proxy = {'http' : 'http://127.0.0.1:8080'} + else: + pass + try: + headers = {"Connection" : "close", + "User-Agent" : ua, + 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', + 'Accept-Language': 'en-US,en;q=0.5', + 'Accept-Encoding': 'gzip, deflate'} + payload = { 'q': 'filetype:(doc dot docx docm dotx dotm docb xls xlt xlm xlsx xlsm xltx xltm xlsb xla xlam xll xlw ppt pot pps pptx pptm potx potm ppam ppsx ppsm sldx sldm pub pdf) site:{}'.format(domain), 'first': start} + link = 'http://www.bing.com/search' + if prox == True: + response = requests.get(link, headers=headers, proxies=proxy, params=payload) + else: + response = requests.get(link, headers=headers, params=payload) + + soup = BeautifulSoup(response.text, "lxml") + + divs = soup.findAll('li', {'class': 'b_algo'}) + for div in divs: + h2 = div.find('h2') + document = h2.find('a', href=True)['href'] + document = urllib2.unquote(document) + document_list.append(document) + except requests.models.ChunkedEncodingError: + continue + except Exception: + traceback.print_exc() + continue + potential_docs = len(document_list) + info('Bing Document Search Finished') + q.put(document_list) + +def action_linkedin(domain, userCountry, q, company, user_agents, prox): + info('LinkedIn Search Started') + uas = user_agents + entries_tuples = [] + seen = set() + results = [] + who_error = False + searchfor = 'site:linkedin.com/in ' + '"' + company + '"' + ua = random.choice(uas) + for start in range(1,50,1): + if prox == True: + proxy = {'http' : 'http://127.0.0.1:8080'} + else: + pass + try: + headers = {"Connection" : "close", + "User-Agent" : ua, + 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', + 'Accept-Language': 'en-US,en;q=0.5', + 'Accept-Encoding': 'gzip, deflate'} + payload = { 'q': searchfor, 'first': start} + link = 'http://www.bing.com/search' + if prox == True: + response = requests.get(link, headers=headers, params=payload, proxies=proxy) + else: + response = requests.get(link, headers=headers, params=payload) + + response.text.encode('utf-8') + soup = BeautifulSoup(response.text, "lxml") + + for div in soup.findAll('li', {'class': 'b_algo'}): + title_temp = div.find('a').text + url = div.find('cite').text.encode('utf-8') + person = str((title_temp.split(' | ')[0])) + description_temp = div.find('div', {'class': 'b_caption'}) + description = description_temp.find('p').text.encode('utf-8').lstrip('View ').replace("’s","").replace("professional profile on LinkedIn. ... ","").replace(" professional profile on LinkedIn. LinkedIn is the world's largest business network, ...","").replace("’S","").replace("’","").replace("professional profile on LinkedIn.","").replace(person, '').lstrip(' ').lstrip('. ').replace("LinkedIn is the world's largest business network, helping professionals like discover ...","").replace("LinkedIn is the world's largest business network, helping professionals like discover inside ...","").replace("professional profile on ... • ","").replace("professional ... ","").replace("...","").lstrip('•').lstrip(' ') + entries_tuples.append((url, person.title(), description)) + + except Exception: + continue + + for urls in entries_tuples: + if urls[1] not in seen: + results.append(urls) + seen.add(urls[1]) + + info('LinkedIn Search Completed') + q.put(sorted(results)) + + +def action_netcraft(domain, myResolver): + info('NetCraft Search Started') + netcraft_list = [] + print "\nPassive Gatherings From NetCraft\n" + try: + link = "http://searchdns.netcraft.com/?restriction=site+contains&host=*.{}&lookup=wait..&position=limited" .format (domain) + response = requests.get(link) + soup = BeautifulSoup(response.content, 'lxml') + pattern = 'rel="nofollow">([a-z\.\-A-Z0-9]+)' + sub_results = re.findall(pattern, response.content) + except dns.exception.Timeout: + pass + except Exception: + info('An Unhandled Exception Has Occured, Please Check The Log For Details\n' + INFO_LOG_FILE, exc_info=True) + + if sub_results: + for item in sub_results: + try: + netcheck = myResolver.query(item + '.' + domain) + for data in netcheck: + netcraft_list.append(item + '.' + domain + ' ' + str(data)) + print colored(item + '.' + domain, 'red') + except dns.exception.Timeout: + pass + except dns.resolver.NXDOMAIN: + pass + except Exception: + info('An Unhandled Exception Has Occured, Please Check The Log For Details\n' + INFO_LOG_FILE, exc_info=True) + else: + print '\tNo Results Found' + + info('NetCraft Completed') + return netcraft_list From 417668cc64a81246b46f61a31c50758319ed8da9 Mon Sep 17 00:00:00 2001 From: Python3pkg Date: Thu, 18 May 2017 13:37:21 -0700 Subject: [PATCH 2/2] Remove .bak --- Bluto/modules/bluto_logging.py.bak | 29 - Bluto/modules/data_mine.py.bak | 268 -------- Bluto/modules/general.py.bak | 242 -------- Bluto/modules/get_dns.py.bak | 234 ------- Bluto/modules/get_file.py.bak | 59 -- Bluto/modules/output.py.bak | 965 ----------------------------- Bluto/modules/search.py.bak | 383 ------------ 7 files changed, 2180 deletions(-) delete mode 100644 Bluto/modules/bluto_logging.py.bak delete mode 100644 Bluto/modules/data_mine.py.bak delete mode 100644 Bluto/modules/general.py.bak delete mode 100644 Bluto/modules/get_dns.py.bak delete mode 100644 Bluto/modules/get_file.py.bak delete mode 100644 Bluto/modules/output.py.bak delete mode 100644 Bluto/modules/search.py.bak diff --git a/Bluto/modules/bluto_logging.py.bak b/Bluto/modules/bluto_logging.py.bak deleted file mode 100644 index a11e8ad..0000000 --- a/Bluto/modules/bluto_logging.py.bak +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/python - -import logging -import sys -import site -import os -LOG_DIR = os.path.expanduser('~/Bluto/log/') -INFO_LOG_FILE = os.path.expanduser(LOG_DIR + 'bluto-info.log') - -if not os.path.exists(LOG_DIR): - os.makedirs(LOG_DIR) - os.chmod(LOG_DIR, 0700) - open(INFO_LOG_FILE,'a').close() - -# set up formatting -formatter = logging.Formatter('[%(asctime)s] %(module)s: %(message)s') - -# set up logging to a file for all levels WARNING and higher -fh2 = logging.FileHandler(INFO_LOG_FILE) -fh2.setLevel(logging.INFO) -fh2.setFormatter(formatter) - -# create Logger object -mylogger = logging.getLogger('MyLogger') -mylogger.setLevel(logging.INFO) -mylogger.addHandler(fh2) - -# create shortcut functions -info = mylogger.info diff --git a/Bluto/modules/data_mine.py.bak b/Bluto/modules/data_mine.py.bak deleted file mode 100644 index f72efbe..0000000 --- a/Bluto/modules/data_mine.py.bak +++ /dev/null @@ -1,268 +0,0 @@ -import pdfminer -import requests -import urllib2 -import oletools.thirdparty.olefile as olefile -import os -import traceback -import time -import re -import random -import math -import sys -import Queue -import time -import threading -import cgi -from termcolor import colored -from pdfminer.pdfparser import PDFParser -from pdfminer.pdfdocument import PDFDocument -from bs4 import BeautifulSoup -from bluto_logging import info, INFO_LOG_FILE -from get_file import get_user_agents -from search import doc_bing, doc_exalead -from general import get_size - - - -def action_download(doc_list, docs): - info('Document Download Started') - i = 0 - download_list = [] - initial_count = 0 - print 'Gathering Live Documents For Metadata Mining\n' - headers = { - 'User-Agent': 'Mozilla/5.0 (Windows; U; Windows NT 6.0; pl; rv:1.9.1.2) Gecko/20090729 Firefox/3.5.2 GTB7.1 ( .NET CLR 3.5.30729', - 'Referer': 'https://www.google.co.uk/', - 'Accept-Language': 'en-US,en;q=0.5', - 'Cache-Control': 'no-cache' - } - for doc in doc_list: - doc = doc.replace(' ', '%20') - try: - r = requests.get(doc.encode('utf-8'), headers=headers) - if r.status_code == 404: - r.raise_for_status() - - if r.status_code == 200: - params = cgi.parse_header(r.headers.get('Content-Disposition', ''))[-1] - if 'filename' not in params: - filename = str(doc).replace('%20', ' ').split('/')[-1] - with open(docs + filename, "w") as code: - i += 1 - code.write(r.content) - code.close() - initial_count += 1 - print('\tDownload Count: {}\r'.format(str(initial_count))), - info(str(doc).replace('%20', ' ')) - download_list.append(str(doc).replace('%20', ' ')) - - continue - else: - filename_t = re.search('filename="(.*)"', r.headers['content-disposition']) - filename = filename_t.group(1) - - with open(docs + filename, "w") as code: - i += 1 - code.write(r.content) - code.close() - initial_count += 1 - print('\tDownload Count: {}\r'.format(str(initial_count))), - download_list.append(str(doc).replace('%20', ' ')) - info(str(doc).replace('%20', ' ')) - continue - - - except ValueError: - info('No Filename in header') - pass - except AttributeError: - pass - except IOError: - info('Not Found: {}'.format(str(doc).replace('%20', ' '))) - pass - except requests.exceptions.HTTPError: - info('Error: File Not Found Server Side: HTTPError') - pass - except requests.exceptions.ConnectionError: - info('Error: File Not Found Server Side: ConnectionError') - pass - except KeyError: - pass - except Exception: - info('An Unhandled Exception Has Occured, Please Check The Log For Details\n' + INFO_LOG_FILE) - info(str(doc).replace('%20', ' ')) - info(r.headers) - pass - if i < 1: - sys.exit() - data_size = get_size(docs) - print '\tData Downloaded: {}MB'.format(str(math.floor(data_size))) - info('Documents Downloaded: {}'.format(initial_count)) - return download_list - - -def doc_search(domain, USERAGENT_F, prox): - q1 = Queue.Queue() - q2 = Queue.Queue() - t1 = threading.Thread(target=doc_bing, args=(domain, USERAGENT_F, prox, q1)) - t2 = threading.Thread(target=doc_exalead, args=(domain, USERAGENT_F, prox, q2)) - t1.start() - t2.start() - t1.join() - t2.join() - bing = q1.get() - exalead = q2.get() - list_d = bing + exalead - return list_d - - -#Extract Author PDF -def pdf_read(pdf_file_list): - info('Extracting PDF MetaData') - software_list = [] - user_names = [] - for filename in pdf_file_list: - info(filename) - try: - - fp = open(filename, 'rb') - parser = PDFParser(fp) - doc = PDFDocument(parser) - software = re.sub('[^0-9a-zA-Z]+', ' ', doc.info[0]['Creator']) - person = re.sub('[^0-9a-zA-Z]+', ' ', doc.info[0]['Author']) - if person: - oddity = re.match('(\s\w\s+(\w\s+)+\w)', person) - if oddity: - oddity = str(oddity.group(1)).replace(' ', '') - user_names.append(str(oddity).title()) - else: - user_names.append(str(person).title()) - if software: - oddity2 = re.match('(\s\w\s+(\w\s+)+\w)', software) - if oddity2: - oddity2 = str(oddity2.group(1)).replace(' ', '') - software_list.append(oddity2) - else: - software_list.append(software) - except IndexError: - continue - except pdfminer.pdfparser.PDFSyntaxError: - continue - except KeyError: - continue - except TypeError: - continue - except Exception: - info('An Unhandled Exception Has Occured, Please Check The Log For Details' + INFO_LOG_FILE) - continue - info('Finished Extracting PDF MetaData') - return (user_names, software_list) - - - -#Extract Author MS FILES -def ms_doc(ms_file_list): - software_list = [] - user_names = [] - info('Extracting MSDOCS MetaData') - for filename in ms_file_list: - try: - data = olefile.OleFileIO(filename) - meta = data.get_metadata() - author = re.sub('[^0-9a-zA-Z]+', ' ', meta.author) - company = re.sub('[^0-9a-zA-Z]+', ' ', meta.company) - software = re.sub('[^0-9a-zA-Z]+', ' ', meta.creating_application) - save_by = re.sub('[^0-9a-zA-Z]+', ' ', meta.last_saved_by) - if author: - oddity = re.match('(\s\w\s+(\w\s+)+\w)', author) - if oddity: - oddity = str(oddity.group(1)).replace(' ', '') - user_names.append(str(oddity).title()) - else: - user_names.append(str(author).title()) - if software: - oddity2 = re.match('(\s\w\s+(\w\s+)+\w)', software) - if oddity2: - oddity2 = str(oddity2.group(1)).replace(' ', '') - software_list.append(oddity2) - else: - software_list.append(software) - - if save_by: - oddity3 = re.match('(\s\w\s+(\w\s+)+\w)', save_by) - if oddity3: - oddity3 = str(oddity3.group(1)).replace(' ', '') - user_names.append(str(oddity3).title()) - else: - user_names.append(str(save_by).title()) - - except Exception: - pass - info('Finished Extracting MSDOC MetaData') - return (user_names, software_list) - -#Modules takes in DOMAIN, PROX, USERAGENTS outputs user_names, software_list -def doc_start(domain, USERAGENT_F, prox, q): - ms_list_ext = ('.docx', '.pptx', '.xlsx', '.doc', '.xls', '.ppt') - ms_file_list = [] - pdf_file_list = [] - info('Let The Hunt Begin') - domain_r = domain.split('.') - if not os.path.exists(os.path.expanduser('~/Bluto/doc/{}'.format(domain_r[0]))): - os.makedirs(os.path.expanduser('~/Bluto/doc/{}'.format(domain_r[0]))) - - location = os.path.expanduser('~/Bluto/doc/{}/'.format(domain_r[0])) - info('Data Folder Created ' + location) - docs = os.path.expanduser(location) - doc_list = doc_search(domain, USERAGENT_F, prox) - - if doc_list == []: - q.put(None) - return - doc_list = set(sorted(doc_list)) - download_list = action_download(doc_list, docs) - download_count = len(download_list) - - for root, dirs, files in os.walk(docs): - for filename in files: - if str(filename).endswith(ms_list_ext): - ms_file_list.append(os.path.join(root, filename)) - if str(filename).endswith('.pdf'): - pdf_file_list.append(os.path.join(root, filename)) - - if ms_file_list and pdf_file_list: - user_names_ms, software_list_ms = ms_doc(ms_file_list) - user_names_pdf, software_list_pdf = pdf_read(pdf_file_list) - user_names_t = user_names_ms + user_names_pdf - software_list_t = software_list_ms + software_list_pdf - - elif ms_file_list: - user_names_ms, software_list_ms = ms_doc(ms_file_list) - user_names_t = user_names_ms - software_list_t = software_list_ms - - elif pdf_file_list: - user_names_pdf, software_list_pdf = pdf_read(pdf_file_list) - user_names_t = user_names_pdf - software_list_t = software_list_pdf - else: - user_names_t = [] - software_list_t = [] - - if user_names_t and software_list_t: - user_names = sorted(set(user_names_t)) - software_list = sorted(set(software_list_t)) - info('The Hunt Ended') - q.put((user_names, software_list, download_count, download_list)) - - elif software_list_t: - software_list = sorted(set(software_list_t)) - user_names = [] - info('The Hunt Ended') - q.put((user_names, software_list, download_count, download_list)) - - elif user_names_t: - user_names = sorted(set(user_names_t)) - software_list = [] - info('The Hunt Ended') - q.put((user_names, software_list, download_count, download_list)) diff --git a/Bluto/modules/general.py.bak b/Bluto/modules/general.py.bak deleted file mode 100644 index 20e8b02..0000000 --- a/Bluto/modules/general.py.bak +++ /dev/null @@ -1,242 +0,0 @@ -#!/usr/local/bin/python -# -*- coding: utf-8 -*- - -from termcolor import colored -import pythonwhois -import traceback -import requests -import datetime -import re -import sys -import socket -import dns.resolver -import dns.query -import dns.zone -import traceback -import os -from bluto_logging import info, INFO_LOG_FILE - - -default_s = False - -def get_size(dir_location): - start_path = dir_location - total_size = 0 - for dirpath, dirnames, filenames in os.walk(start_path): - for f in filenames: - fp = os.path.join(dirpath, f) - total_size += os.path.getsize(fp) - total_size = total_size / 1024.0 - total_size = total_size / 1024.0 - return total_size - - -def action_whois(domain): - - try: - whois_things = pythonwhois.get_whois(domain) - try: - company = whois_things['contacts']['registrant']['name'] - except Exception: - print '\nThere seems to be no Registrar for this domain.' - company = domain - pass - splitup = company.lower().split() - patern = re.compile('|'.join(splitup)) - while True: - if patern.search(domain): - info('Whois Results Are Good ' + company) - print '\nThe Whois Results Look Promising: ' + colored('{}','green').format(company) - accept = raw_input(colored('\nIs The Search Term sufficient?: ','green')).lower() - if accept in ('y', 'yes'): - company = company - break - elif accept in ('n', 'no'): - temp_company = raw_input(colored('\nRegistered Company Name: ','green')) - if temp_company == '': - info('User Supplied Blank Company') - company = domain - break - else: - info('User Supplied Company ' + company) - company = temp_company - break - else: - print '\nThe Options Are yes|no Or y|no Not {}'.format(accept) - - else: - info('Whois Results Not Good ' + company) - print colored("\n\tThe Whois Results Don't Look Very Promissing: '{}'","red") .format(company) - print'\nPlease Supply The Company Name\n\n\tThis Will Be Used To Query LinkedIn' - temp_company = raw_input(colored('\nRegistered Company Name: ','green')) - if temp_company == '': - info('User Supplied Blank Company') - company = domain - break - else: - info('User Supplied Company ' + company) - company = temp_company - break - - - except pythonwhois.shared.WhoisException: - pass - except socket.error: - pass - except KeyError: - pass - except pythonwhois.net.socket.errno.ETIMEDOUT: - print colored('\nWhoisError: You may be behind a proxy or firewall preventing whois lookups. Please supply the registered company name, if left blank the domain name ' + '"' + domain + '"' +' will be used for the Linkedin search. The results may not be as accurate.','red') - temp_company = raw_input(colored('\nRegistered Company Name: ','green')) - if temp_company == '': - company = domain - else: - company = temp_company - except Exception: - info('An Unhandled Exception Has Occured, Please Check The Log For Details' + INFO_LOG_FILE) - if 'company' not in locals(): - print 'There is no Whois data for this domain.\n\nPlease supply a company name.' - while True: - temp_company = raw_input(colored('\nRegistered Company Name: ','green')) - if temp_company == '': - info('User Supplied Blank Company') - company = domain - break - else: - company = temp_company - info('User Supplied Company ' + company) - break - - return company - -def action_country_id(countries_file, prox): - info('Identifying Country') - userCountry = '' - userServer = '' - userIP = '' - userID = False - o = 0 - tcountries_dic = {} - country_list = [] - - with open(countries_file) as fin: - for line in fin: - key, value = line.strip().split(';') - tcountries_dic.update({key: value}) - - countries_dic = dict((k.lower(), v.lower()) for k,v in tcountries_dic.iteritems()) - - for country, server in countries_dic.items(): - country_list.append(country) - - country_list = [item.capitalize() for item in country_list] - country_list.sort() - - while True: - try: - if prox == True: - proxy = {'http' : 'http://127.0.0.1:8080'} - r = requests.get(r'https://freegeoip.net/json/', proxies=proxy, verify=False) - ip = r.json()['ip'] - originCountry = r.json()['country_name'] - - else: - r = requests.get(r'https://freegeoip.net/json/', verify=False) - ip = r.json()['ip'] - originCountry = r.json()['country_name'] - - except ValueError as e: - if o == 0: - print colored('\nUnable to connect to the CountryID, we will retry.', 'red') - if o > 0: - print '\nThis is {} of 3 attempts' .format(o) - time.sleep(2) - o += 1 - if o == 4: - break - continue - break - - if o == 4: - print colored('\nWe have been unable to connect to the CountryID service.\n','red') - print '\nPlease let Bluto know what country you hale from.\n' - print colored('Available Countries:\n', 'green') - - if len(country_list) % 2 != 0: - country_list.append(" ") - - split = len(country_list)/2 - l1 = country_list[0:split] - l2 = country_list[split:] - - for key, value in zip(l1,l2): - print "{0:<20s} {1}".format(key, value) - - country_list = [item.lower() for item in country_list] - - while True: - originCountry = raw_input('\nCountry: ').lower() - if originCountry in country_list: - break - if originCountry == '': - print '\nYou have not selected a country so the default server will be used' - originCountry = 'United Kingdom'.lower() - break - else: - print '\nCheck your spelling and try again' - - for country, server in countries_dic.items(): - if country == originCountry: - userCountry = country - userServer = server - userID = True - - else: - - for country, server in countries_dic.items(): - if country == originCountry.lower(): - userCountry = country - userServer = server - userID = True - if userID == False: - if default_s == True: - userCountry = 'DEAFULT' - pass - else: - print 'Bluto currently doesn\'t have your countries google server available.\nPlease navigate to "https://freegeoip.net/json/" and post an issue to "https://github.com/darryllane/Bluto/issues"\nincluding the country value as shown in the json output\nYou have been assigned to http://www.google.co.uk for now.' - userServer = 'http://www.google.co.uk' - userCountry = 'United Kingdom' - - print '\n\tSearching From: {0}\n\tGoogle Server: {1}\n' .format(userCountry.title(), userServer) - info('Country Identified: {}'.format(userCountry)) - return (userCountry, userServer) - - -def action_bluto_use(countryID): - now = datetime.datetime.now() - try: - link = "http://darryllane.co.uk/bluto/log_use.php" - payload = {'country': countryID, 'Date': now} - requests.post(link, data=payload) - except Exception: - info('An Unhandled Exception Has Occured, Please Check The Log For Details' + INFO_LOG_FILE) - pass - - -def check_dom(domain, myResolver): - try: - myAnswers = myResolver.query(domain, "NS") - dom = str(myAnswers.canonical_name).strip('.') - if dom: - pass - except dns.resolver.NoNameservers: - print '\nError: \nDomain Not Valid, Check You Have Entered It Correctly\n' - sys.exit() - except dns.resolver.NXDOMAIN: - print '\nError: \nDomain Not Valid, Check You Have Entered It Correctly\n' - sys.exit() - except dns.exception.Timeout: - print '\nThe connection hit a timeout. Are you connected to the internet?\n' - sys.exit() - except Exception: - info('An Unhandled Exception Has Occured, Please Check The Log For Details' + INFO_LOG_FILE) diff --git a/Bluto/modules/get_dns.py.bak b/Bluto/modules/get_dns.py.bak deleted file mode 100644 index f8d3556..0000000 --- a/Bluto/modules/get_dns.py.bak +++ /dev/null @@ -1,234 +0,0 @@ -#!/usr/local/bin/python - -# -*- coding: utf-8 -*- - -import sys -import traceback -import socket -import dns.resolver -import random -import string -from bluto_logging import info, INFO_LOG_FILE -from multiprocessing.dummy import Pool as ThreadPool -from termcolor import colored - -targets = [] - -def set_resolver(timeout_value): - myResolver = dns.resolver.Resolver() - myResolver.timeout = timeout_value - myResolver.lifetime = timeout_value - myResolver.nameservers = ['8.8.8.8', '8.8.4.4'] - - return myResolver - - -def get_dns_details(domain, myResolver): - info('Gathering DNS Details') - ns_list = [] - zn_list =[] - mx_list = [] - try: - print "\nName Server:\n" - myAnswers = myResolver.query(domain, "NS") - for data in myAnswers.rrset: - data1 = str(data) - data2 = (data1.rstrip('.')) - addr = socket.gethostbyname(data2) - ns_list.append(data2 + '\t' + addr) - zn_list.append(data2) - list(set(ns_list)) - ns_list.sort() - for i in ns_list: - print colored(i, 'green') - except dns.resolver.NoNameservers: - info('\tNo Name Servers\nConfirm The Domain Name Is Correct.' + INFO_LOG_FILE, exc_info=True) - sys.exit() - except dns.resolver.NoAnswer: - print "\tNo DNS Servers" - except dns.resolver.NXDOMAIN: - info("\tDomain Does Not Exist" + INFO_LOG_FILE, exc_info=True) - sys.exit() - except dns.resolver.Timeout: - info('\tTimeouted\nConfirm The Domain Name Is Correct.' + INFO_LOG_FILE, exc_info=True) - sys.exit() - except Exception: - info('An Unhandled Exception Has Occured, Please Check The Log For Details\n' + INFO_LOG_FILE, exc_info=True) - - try: - print "\nMail Server:\n" - myAnswers = myResolver.query(domain, "MX") - for data in myAnswers: - data1 = str(data) - data2 = (data1.split(' ',1)[1].rstrip('.')) - addr = socket.gethostbyname(data2) - mx_list.append(data2 + '\t' + addr) - list(set(mx_list)) - mx_list.sort() - for i in mx_list: - print colored(i, 'green') - except dns.resolver.NoAnswer: - print "\tNo Mail Servers" - except Exception: - info('An Unhandled Exception Has Occured, Please Check The Log For Details' + INFO_LOG_FILE) - - info('Completed Gathering DNS Details') - return zn_list - - -def action_wild_cards(domain, myResolver): - info('Checking Wild Cards') - try: - one = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(15)) - myAnswers = myResolver.query(str(one) + '.' + str(domain)) - - except dns.resolver.NoNameservers: - pass - - except dns.resolver.NoAnswer: - pass - - except dns.resolver.NXDOMAIN: - info('Wild Cards False') - return False - else: - info('Wild Cards True') - return True - - -def action_brute(subdomain): - global myResolverG - try: - myAnswers = myResolverG.query(subdomain) - for data in myAnswers: - targets.append(subdomain + ' ' + str(data)) - - except dns.resolver.NoNameservers: - pass - except dns.resolver.NXDOMAIN: - pass - except dns.resolver.NoAnswer: - pass - except dns.exception.SyntaxError: - pass - except dns.exception.Timeout: - info('Timeout: {}'.format(subdomain)) - pass - except dns.resolver.Timeout: - pass - except Exception: - info('An Unhandled Exception Has Occured, Please Check The Log For Details' + INFO_LOG_FILE) - info(traceback.print_exc()) - - -def action_brute_start(subs, myResolver): - global myResolverG - myResolverG = myResolver - info('Bruting SubDomains') - print '\nBrute Forcing Sub-Domains\n' - pool = ThreadPool(8) - pool.map(action_brute, subs) - pool.close() - info('Completed Bruting SubDomains') - - return targets - - -def action_brute_wild(sub_list, domain, myResolver): - info('Bruting Wild Card SubDomains') - target_results = [] - random_addrs = [] - for i in range(0,10,1): - one = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(15)) - myAnswers = myResolver.query(str(one) + '.' + str(domain)) - name = myAnswers.canonical_name - random_addr = socket.gethostbyname(str(name)) - random_addrs.append(random_addr) - random_addrs = sorted(set(random_addrs)) - for host in sub_list: - try: - host_host, host_addr = host.split(' ') - if host_addr in random_addrs: - pass - else: - target_results.append(host) - except dns.resolver.NoNameservers: - pass - except dns.resolver.NoAnswer: - pass - except dns.resolver.NXDOMAIN: - pass - except dns.name.EmptyLabel: - pass - except Exception: - continue - info('Completed Bruting Wild Card SubDomains') - return target_results - - -def action_zone_transfer(zn_list, domain): - info('Attempting Zone Transfers') - global clean_dump - print "\nAttempting Zone Transfers" - zn_list.sort() - vuln = True - vulnerable_listT = [] - vulnerable_listF = [] - dump_list = [] - for ns in zn_list: - try: - z = dns.zone.from_xfr(dns.query.xfr(ns, domain, timeout=3)) - names = z.nodes.keys() - names.sort() - if vuln == True: - info('Vuln: {}'.format(ns)) - vulnerable_listT.append(ns) - - except Exception as e: - error = str(e) - if error == 'Errno -2] Name or service not known': - pass - if error == "[Errno 54] Connection reset by peer" or "No answer or RRset not for qname": - info('Not Vuln: {}'.format(ns)) - vuln = False - vulnerable_listF.append(ns) - else: - info('An Unhandled Exception Has Occured, Please Check The Log For Details\n' + INFO_LOG_FILE, exc_info=True) - - - if vulnerable_listF: - print "\nNot Vulnerable:\n" - for ns in vulnerable_listF: - print colored(ns, 'green') - - if vulnerable_listT: - info('Vulnerable To Zone Transfers') - print "\nVulnerable:\n" - for ns in vulnerable_listT: - print colored(ns,'red'), colored("\t" + "TCP/53", 'red') - - - z = dns.zone.from_xfr(dns.query.xfr(vulnerable_listT[0], domain)) - names = z.nodes.keys() - names.sort() - print "\nRaw Zone Dump\n" - for n in names: - data1 = "{}.{}" .format(n,domain) - try: - addr = socket.gethostbyname(data1) - dump_list.append("{}.{} {}" .format(n, domain, addr)) - - except Exception as e: - error = str(e) - if error == "[Errno -5] No address associated with hostname": - pass - if error == 'Errno -2] Name or service not known': - pass - else: - info('An Unhandled Exception Has Occured, Please Check The Log For Details\n' + INFO_LOG_FILE, exc_info=True) - - print z[n].to_text(n) - - info('Completed Attempting Zone Transfers') - clean_dump = sorted(set(dump_list)) - return ((vulnerable_listT, clean_dump)) diff --git a/Bluto/modules/get_file.py.bak b/Bluto/modules/get_file.py.bak deleted file mode 100644 index 9d6aa4c..0000000 --- a/Bluto/modules/get_file.py.bak +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/local/bin/python -# -*- coding: utf-8 -*- - -import traceback -import sys -import random -from termcolor import colored -from bluto_logging import info, INFO_LOG_FILE - -def get_user_agents(useragent_f): - info('Gathering UserAgents') - uas = [] - with open(useragent_f, 'rb') as uaf: - for ua in uaf.readlines(): - if ua: - uas.append(ua.strip()[1:-1-1]) - random.shuffle(uas) - info('Completed Gathering UserAgents') - return uas - - -def get_subs(filename, domain): - info('Gathering SubDomains') - full_list = [] - try: - subs = [line.rstrip('\n') for line in open(filename)] - for sub in subs: - full_list.append(str(sub.lower() + "." + domain)) - except Exception: - info('An Unhandled Exception Has Occured, Please Check The Log For Details' + INFO_LOG_FILE) - sys.exit() - - info('Completed Gathering SubDomains') - return full_list - -def get_sub_interest(filename, domain): - info('Gathering SubDomains Of Interest') - full_list = [] - try: - subs = [line.rstrip('\n') for line in open(filename)] - for sub in subs: - full_list.append(str(sub.lower() + "." + domain)) - - except Exception: - info('An Unhandled Exception Has Occured, Please Check The Log For Details' + INFO_LOG_FILE) - sys.exit() - - info('Completed Gathering SubDomains Of Interest') - return full_list - - -def get_line_count(filename): - info('Gathering SubDomains Count') - lines = 0 - for line in open(filename): - lines += 1 - - info('Completed Gathering SubDomains Count') - return lines diff --git a/Bluto/modules/output.py.bak b/Bluto/modules/output.py.bak deleted file mode 100644 index 14668fb..0000000 --- a/Bluto/modules/output.py.bak +++ /dev/null @@ -1,965 +0,0 @@ -#!/usr/local/bin/python -# -*- coding: utf-8 -*- - -from termcolor import colored -import traceback -import collections -import datetime -import webbrowser -import shutil -import os -from search import action_pwned -from bluto_logging import info, INFO_LOG_FILE, LOG_DIR - - -def action_output_vuln_zone(google_results, bing_results, linkedin_results, time_spent_email, time_spent_total, clean_dump, sub_intrest, domain, report_location, company, data_mine): - info('Output action_output_vuln_zone: Start') - linkedin_evidence_results = [] - email_evidence_results = [] - email_results = [] - email_seen = [] - url_seen = [] - person_seen = [] - final_emails = [] - - for email, url in google_results: - try: - e1, e2 = email.split(',') - if url not in email_seen: - email_seen.append(url) - email_evidence_results.append((str(e2).replace(' ',''),url)) - email_evidence_results.append((str(e1).replace(' ',''),url)) - email_results.append((str(e2).replace(' ',''))) - email_results.append((str(e1).replace(' ',''))) - - except ValueError: - if url not in email_seen: - email_seen.append(url) - email_evidence_results.append((str(email).replace(' ',''),url)) - email_results.append(str(email).replace(' ','')) - - for e, u in bing_results: - email_results.append(e) - if u not in url_seen: - email_evidence_results.append((e, u)) - - for url, person, description in linkedin_results: - if person not in person_seen: - person_seen.append(person) - linkedin_evidence_results.append((url, person, description)) - - linkedin_evidence_results.sort(key=lambda tup: tup[1]) - sorted_email = set(sorted(email_results)) - for email in sorted_email: - if email == '[]': - pass - elif email == '@' + domain: - pass - else: - final_emails.append(email) - email_count = len(final_emails) - staff_count = len(person_seen) - f_emails = sorted(final_emails) - pwned_results = action_pwned(f_emails) - c_accounts = len(pwned_results) - - print '\n\nEmail Addresses:\n' - write_html(email_evidence_results, linkedin_evidence_results, pwned_results, report_location, company, data_mine) - if f_emails: - for email in f_emails: - - print str(email).replace("u'","").replace("'","").replace('[','').replace(']','') - else: - print '\tNo Data To Be Found' - - print '\nCompromised Accounts:\n' - if pwned_results: - sorted_pwned = sorted(pwned_results) - for account in sorted_pwned: - print 'Account: \t{}'.format(account[0]) - print 'Domain: \t{}'.format(account[1]) - print 'Date: \t{}\n'.format(account[3]) - else: - print '\tNo Data To Be Found' - - print '\nLinkedIn Results:\n' - - sorted_person = sorted(person_seen) - if sorted_person: - for person in sorted_person: - print person - else: - print '\tNo Data To Be Found' - - if data_mine is not None: - user_names = data_mine[0] - software_list = data_mine[1] - download_count = data_mine[2] - download_list = data_mine[3] - username_count = len(user_names) - software_count = len(software_list) - - print '\nData Found In Document MetaData' - print '\nPotential Usernames:\n' - if user_names: - for user in user_names: - print '\t' + colored(user, 'red') - else: - print '\tNo Data To Be Found' - - print '\nSoftware And Versions Found:\n' - if software_list: - for software in software_list: - print '\t' + colored(software, 'red') - else: - print '\tNo Data To Be Found' - else: - user_names = [] - software_list = [] - download_count = 0 - username_count = len(user_names) - software_count = len(software_list) - - target_dict = dict((x.split(' ') for x in clean_dump)) - clean_target = collections.OrderedDict(sorted(target_dict.items())) - print "\nProcessed Dump\n" - - bruted_count = len(clean_target) - for item in clean_target: - if item in sub_intrest: - print colored(item, 'red'), colored("\t" + clean_target[item], 'red') - else: - print item, "\t" + target_dict[item] - - time_spent_email_f = str(datetime.timedelta(seconds=(time_spent_email))).split('.')[0] - time_spent_total_f = str(datetime.timedelta(seconds=(time_spent_total))).split('.')[0] - - print '\nHosts Identified: {}' .format(str(bruted_count)) - print 'Potential Emails Found: {}' .format(str(email_count)) - print 'Potential Staff Members Found: {}' .format(str(staff_count)) - print 'Compromised Accounts: {}' .format(str(c_accounts)) - print 'Potential Usernames Found: {}'.format(username_count) - print 'Potential Software Found: {}'.format(software_count) - print 'Documents Downloaded: {}'.format(download_count) - print "Email Enumeration:", time_spent_email_f - print "Total Time:", time_spent_total_f - - info('Hosts Identified: {}' .format(str(bruted_count))) - info("Total Time:" .format(str(time_spent_total_f))) - info("Email Enumeration: {}" .format(str(time_spent_email_f))) - info('Compromised Accounts: {}' .format(str(c_accounts))) - info('Potential Usernames Found: {}'.format(username_count)) - info('Potential Software Found: {}'.format(software_count)) - info('Documents Downloaded: {}'.format(download_count)) - info('Potential Staff Members Found: {}' .format(str(staff_count))) - info('Potential Emails Found: {}' .format(str(email_count))) - info('DNS Vuln Run completed') - info('Output action_output_vuln_zone: Complete') - - domain_r = domain.split('.') - docs = os.path.expanduser('~/Bluto/doc/{}/'.format(domain_r[0])) - answers = ['no','n','y','yes'] - while True: - answer = raw_input("\nWould you like to keep all local data?\n(Local Logs, Downloded Documents, HTML Evidence Report)\n\nYes|No:").lower() - if answer in answers: - if answer == 'y' or answer == 'yes': - domain - print '\nThe documents are located here: {}'.format(docs) - print 'The logs are located here: {}.'.format(LOG_DIR) - print "\nAn evidence report has been written to {}\n".format(report_location) - while True: - answer = raw_input("Would you like to open this report now? ").lower() - if answer in answers: - if answer == 'y' or answer == 'yes': - print '\nOpening {}' .format(report_location) - webbrowser.open('file://' + str(report_location)) - break - else: - break - else: - print 'Your answer needs to be either yes|y|no|n rather than, {}' .format(answer) - break - else: - shutil.rmtree(docs) - shutil.rmtree(LOG_DIR) - os.remove(report_location) - break - else: - print '\tYour answer needs to be either yes|y|no|n rather than, {}' .format(answer) - - -def action_output_vuln_zone_hunter(google_results, bing_results, linkedin_results, time_spent_email, time_spent_total, clean_dump, sub_intrest, domain, emailHunter_results, args, report_location, company, data_mine): - info('Output action_output_vuln_zone_hunter: Start') - linkedin_evidence_results = [] - email_evidence_results = [] - email_results = [] - email_seen = [] - url_seen = [] - person_seen = [] - final_emails = [] - - if emailHunter_results is not None: - for email in emailHunter_results: - email_results.append(email[0]) - email_evidence_results.append((email[0],email[1])) - - for email, url in google_results: - try: - e1, e2 = email.split(',') - if url not in email_seen: - email_seen.append(url) - email_evidence_results.append((str(e2).replace(' ',''),url)) - email_evidence_results.append((str(e1).replace(' ',''),url)) - email_results.append((str(e2).replace(' ',''))) - email_results.append((str(e1).replace(' ',''))) - - except ValueError: - if url not in email_seen: - email_seen.append(url) - email_evidence_results.append((str(email).replace(' ',''),url)) - email_results.append(str(email).replace(' ','')) - - for e, u in bing_results: - email_results.append(e) - if u not in url_seen: - email_evidence_results.append((e, u)) - - for url, person, description in linkedin_results: - if person not in person_seen: - person_seen.append(person) - linkedin_evidence_results.append((url, person, description)) - - linkedin_evidence_results.sort(key=lambda tup: tup[1]) - sorted_email = set(sorted(email_results)) - for email in sorted_email: - if email == '[]': - pass - elif email == '@' + domain: - pass - else: - final_emails.append(email) - email_count = len(final_emails) - staff_count = len(person_seen) - f_emails = sorted(final_emails) - pwned_results = action_pwned(f_emails) - c_accounts = len(pwned_results) - - print '\n\nEmail Addresses:\n' - write_html(email_evidence_results, linkedin_evidence_results, pwned_results, report_location, company, data_mine) - if f_emails: - for email in f_emails: - print str(email).replace("u'","").replace("'","").replace('[','').replace(']','') - else: - print '\tNo Data To Be Found' - - print '\nCompromised Accounts:\n' - if pwned_results: - sorted_pwned = sorted(pwned_results) - for account in sorted_pwned: - print 'Account: \t{}'.format(account[0]) - print 'Domain: \t{}'.format(account[1]) - print 'Date: \t{}\n'.format(account[3]) - else: - print '\tNo Data To Be Found' - - print '\nLinkedIn Results:\n' - - sorted_person = sorted(person_seen) - if sorted_person: - for person in sorted_person: - print person - else: - print '\tNo Data To Be Found' - - if data_mine is not None: - user_names = data_mine[0] - software_list = data_mine[1] - download_count = data_mine[2] - download_list = data_mine[3] - username_count = len(user_names) - software_count = len(software_list) - - print '\nData Found In Document MetaData' - print '\nPotential Usernames:\n' - if user_names: - for user in user_names: - print '\t' + colored(user, 'red') - else: - print '\tNo Data To Be Found' - - print '\nSoftware And Versions Found:\n' - if software_list: - for software in software_list: - print '\t' + colored(software, 'red') - else: - print '\tNo Data To Be Found' - else: - user_names = [] - software_list = [] - download_count = 0 - username_count = len(user_names) - software_count = len(software_list) - - target_dict = dict((x.split(' ') for x in clean_dump)) - clean_target = collections.OrderedDict(sorted(target_dict.items())) - - print "\nProcessed Dump\n" - bruted_count = len(clean_target) - for item in clean_target: - if item in sub_intrest: - print colored(item, 'red'), colored("\t" + clean_target[item], 'red') - else: - print item, "\t" + target_dict[item] - - time_spent_email_f = str(datetime.timedelta(seconds=(time_spent_email))).split('.')[0] - time_spent_total_f = str(datetime.timedelta(seconds=(time_spent_total))).split('.')[0] - - print '\nHosts Identified: {}' .format(str(bruted_count)) - print 'Potential Emails Found: {}' .format(str(email_count)) - print 'Potential Staff Members Found: {}' .format(str(staff_count)) - print 'Compromised Accounts: {}' .format(str(c_accounts)) - print 'Potential Usernames Found: {}'.format(username_count) - print 'Potential Software Found: {}'.format(software_count) - print 'Documents Downloaded: {}'.format(download_count) - print "Email Enumeration:", time_spent_email_f - print "Total Time:", time_spent_total_f - - info('Hosts Identified: {}' .format(str(bruted_count))) - info("Total Time:" .format(str(time_spent_total_f))) - info("Email Enumeration: {}" .format(str(time_spent_email_f))) - info('Compromised Accounts: {}' .format(str(c_accounts))) - info('Potential Usernames Found: {}'.format(username_count)) - info('Potential Software Found: {}'.format(software_count)) - info('Documents Downloaded: {}'.format(download_count)) - info('Potential Staff Members Found: {}' .format(str(staff_count))) - info('Potential Emails Found: {}' .format(str(email_count))) - info('DNS Vuln Run completed') - info('Output action_output_vuln_zone_hunter: Completed') - - domain_r = domain.split('.') - docs = os.path.expanduser('~/Bluto/doc/{}/'.format(domain_r[0])) - answers = ['no','n','y','yes'] - while True: - answer = raw_input("\nWould you like to keep all local data?\n(Local Logs, Downloded Documents, HTML Evidence Report)\n\nYes|No:").lower() - if answer in answers: - if answer == 'y' or answer == 'yes': - domain - print '\nThe documents are located here: {}'.format(docs) - print 'The logs are located here: {}.'.format(LOG_DIR) - print "\nAn evidence report has been written to {}\n".format(report_location) - while True: - answer = raw_input("Would you like to open this report now? ").lower() - if answer in answers: - if answer == 'y' or answer == 'yes': - print '\nOpening {}' .format(report_location) - webbrowser.open('file://' + str(report_location)) - break - else: - break - else: - print 'Your answer needs to be either yes|y|no|n rather than, {}' .format(answer) - break - else: - shutil.rmtree(docs) - shutil.rmtree(LOG_DIR) - os.remove(report_location) - break - else: - print '\tYour answer needs to be either yes|y|no|n rather than, {}' .format(answer) - - -def action_output_wild_false(brute_results_dict, sub_intrest, google_results, bing_true_results, linkedin_results, check_count, domain, time_spent_email, time_spent_brute, time_spent_total, report_location, company, data_mine): - info('Output action_output_wild_false: Start') - linkedin_evidence_results = [] - email_evidence_results = [] - email_results = [] - email_seen = [] - url_seen = [] - person_seen = [] - final_emails = [] - - for email, url in google_results: - try: - e1, e2 = email.split(',') - if url not in email_seen: - email_seen.append(url) - email_evidence_results.append((str(e2).replace(' ',''),url)) - email_evidence_results.append((str(e1).replace(' ',''),url)) - email_results.append((str(e2).replace(' ',''))) - email_results.append((str(e1).replace(' ',''))) - - except ValueError: - if url not in email_seen: - email_seen.append(url) - email_evidence_results.append((str(email).replace(' ',''),url)) - email_results.append(str(email).replace(' ','')) - - for e, u in bing_true_results: - email_results.append(e) - if u not in url_seen: - email_evidence_results.append((e, u)) - - for url, person, description in linkedin_results: - if person not in person_seen: - person_seen.append(person) - linkedin_evidence_results.append((url, person, description)) - - linkedin_evidence_results.sort(key=lambda tup: tup[1]) - sorted_email = set(sorted(email_results)) - for email in sorted_email: - if email == '[]': - pass - elif email == '@' + domain: - pass - else: - final_emails.append(email) - email_count = len(final_emails) - staff_count = len(person_seen) - f_emails = sorted(final_emails) - pwned_results = action_pwned(f_emails) - c_accounts = len(pwned_results) - - print '\n\nEmail Addresses:\n' - write_html(email_evidence_results, linkedin_evidence_results, pwned_results, report_location, company, data_mine) - if f_emails: - - for email in f_emails: - - print str(email).replace("u'","").replace("'","").replace('[','').replace(']','') - else: - print '\tNo Data To Be Found' - - print '\nCompromised Accounts:\n' - if pwned_results: - sorted_pwned = sorted(pwned_results) - for account in sorted_pwned: - print 'Account: \t{}'.format(account[0]) - print 'Domain: \t{}'.format(account[1]) - print 'Date: \t{}\n'.format(account[3]) - else: - print '\tNo Data To Be Found' - - print '\nLinkedIn Results:\n' - - sorted_person = sorted(person_seen) - if sorted_person: - for person in sorted_person: - print person - else: - print '\tNo Data To Be Found' - - if data_mine is not None: - user_names = data_mine[0] - software_list = data_mine[1] - download_count = data_mine[2] - download_list = data_mine[3] - username_count = len(user_names) - software_count = len(software_list) - - print '\nData Found In Document MetaData' - print '\nPotential Usernames:\n' - if user_names: - for user in user_names: - print '\t' + colored(user, 'red') - else: - print '\tNo Data To Be Found' - - print '\nSoftware And Versions Found:\n' - if software_list: - for software in software_list: - print '\t' + colored(software, 'red') - else: - print '\tNo Data To Be Found' - else: - user_names = [] - software_list = [] - download_count = 0 - username_count = len(user_names) - software_count = len(software_list) - - sorted_dict = collections.OrderedDict(sorted(brute_results_dict.items())) - bruted_count = len(sorted_dict) - print "\nBluto Results: \n" - for item in sorted_dict: - if item in sub_intrest: - print colored(item + "\t", 'red'), colored(sorted_dict[item], 'red') - else: - print item + "\t",sorted_dict[item] - - - time_spent_email_f = str(datetime.timedelta(seconds=(time_spent_email))).split('.')[0] - time_spent_brute_f = str(datetime.timedelta(seconds=(time_spent_brute))).split('.')[0] - time_spent_total_f = str(datetime.timedelta(seconds=(time_spent_total))).split('.')[0] - - print '\nHosts Identified: {}' .format(str(bruted_count)) - print 'Potential Emails Found: {}' .format(str(email_count)) - print 'Potential Staff Members Found: {}' .format(str(staff_count)) - print 'Compromised Accounts: {}' .format(str(c_accounts)) - print 'Potential Usernames Found: {}'.format(username_count) - print 'Potential Software Found: {}'.format(software_count) - print 'Documents Downloaded: {}'.format(download_count) - print "Email Enumeration:", time_spent_email_f - print "Requests executed:", str(check_count) + " in ", time_spent_brute_f - print "Total Time:", time_spent_total_f - - info('Hosts Identified: {}' .format(str(bruted_count))) - info("Email Enumeration: {}" .format(str(time_spent_email_f))) - info('Compromised Accounts: {}' .format(str(c_accounts))) - info('Potential Staff Members Found: {}' .format(str(staff_count))) - info('Potential Emails Found: {}' .format(str(email_count))) - info('Potential Usernames Found: {}'.format(username_count)) - info('Potential Software Found: {}'.format(software_count)) - info('Documents Downloaded: {}'.format(download_count)) - info("Total Time:" .format(str(time_spent_total_f))) - info('DNS No Wild Cards + Email Hunter Run completed') - info('Output action_output_wild_false: Completed') - - domain_r = domain.split('.') - docs = os.path.expanduser('~/Bluto/doc/{}/'.format(domain_r[0])) - answers = ['no','n','y','yes'] - while True: - answer = raw_input("\nWould you like to keep all local data?\n(Local Logs, Downloded Documents, HTML Evidence Report)\n\nYes|No:").lower() - if answer in answers: - if answer == 'y' or answer == 'yes': - domain - print '\nThe documents are located here: {}'.format(docs) - print 'The logs are located here: {}.'.format(LOG_DIR) - print "\nAn evidence report has been written to {}\n".format(report_location) - while True: - answer = raw_input("Would you like to open this report now? ").lower() - if answer in answers: - if answer == 'y' or answer == 'yes': - print '\nOpening {}' .format(report_location) - webbrowser.open('file://' + str(report_location)) - break - else: - break - else: - print 'Your answer needs to be either yes|y|no|n rather than, {}' .format(answer) - break - else: - shutil.rmtree(docs) - shutil.rmtree(LOG_DIR) - os.remove(report_location) - break - else: - print '\tYour answer needs to be either yes|y|no|n rather than, {}' .format(answer) - - -def action_output_wild_false_hunter(brute_results_dict, sub_intrest, google_results, bing_true_results, linkedin_results, check_count, domain, time_spent_email, time_spent_brute, time_spent_total, emailHunter_results, args, report_location, company, data_mine): - info('Output action_output_wild_false_hunter: Start') - linkedin_evidence_results = [] - email_evidence_results = [] - email_results = [] - email_seen = [] - url_seen = [] - person_seen = [] - final_emails = [] - - if emailHunter_results is not None: - for email in emailHunter_results: - email_results.append(email[0]) - email_evidence_results.append((email[0],email[1])) - - for email, url in google_results: - try: - e1, e2 = email.split(',') - if url not in email_seen: - email_seen.append(url) - email_evidence_results.append((str(e2).replace(' ',''),url)) - email_evidence_results.append((str(e1).replace(' ',''),url)) - email_results.append((str(e2).replace(' ',''))) - email_results.append((str(e1).replace(' ',''))) - - except ValueError: - if url not in email_seen: - email_seen.append(url) - email_evidence_results.append((str(email).replace(' ',''),url)) - email_results.append(str(email).replace(' ','')) - - for e, u in bing_true_results: - email_results.append(e) - if u not in url_seen: - email_evidence_results.append((e, u)) - - for url, person, description in linkedin_results: - if person not in person_seen: - person_seen.append(person) - linkedin_evidence_results.append((url, person, description)) - - linkedin_evidence_results.sort(key=lambda tup: tup[1]) - sorted_email = set(sorted(email_results)) - for email in sorted_email: - if email == '[]': - pass - elif email == '@' + domain: - pass - else: - final_emails.append(email) - email_count = len(final_emails) - staff_count = len(person_seen) - f_emails = sorted(final_emails) - pwned_results = action_pwned(f_emails) - c_accounts = len(pwned_results) - - print '\n\nEmail Addresses:\n' - write_html(email_evidence_results, linkedin_evidence_results, pwned_results, report_location, company, data_mine) - if f_emails: - - for email in f_emails: - - print '\t' + str(email).replace("u'","").replace("'","").replace('[','').replace(']','') - else: - print '\tNo Data To Be Found' - - print '\nCompromised Accounts:\n' - if pwned_results: - sorted_pwned = sorted(pwned_results) - for account in sorted_pwned: - print 'Account: \t{}'.format(account[0]) - print ' Domain: \t{}'.format(account[1]) - print ' Date: \t{}\n'.format(account[3]) - else: - print '\tNo Data To Be Found' - - print '\nLinkedIn Results:\n' - - sorted_person = sorted(person_seen) - if sorted_person: - for person in sorted_person: - print person - else: - print '\tNo Data To Be Found' - - if data_mine is not None: - user_names = data_mine[0] - software_list = data_mine[1] - download_count = data_mine[2] - download_list = data_mine[3] - username_count = len(user_names) - software_count = len(software_list) - - print '\nData Found In Document MetaData' - print '\nPotential Usernames:\n' - if user_names: - for user in user_names: - print '\t' + colored(user, 'red') - else: - print '\tNo Data To Be Found' - - print '\nSoftware And Versions Found:\n' - if software_list: - for software in software_list: - print '\t' + colored(software, 'red') - else: - print '\tNo Data To Be Found' - else: - user_names = [] - software_list = [] - download_count = 0 - username_count = len(user_names) - software_count = len(software_list) - - sorted_dict = collections.OrderedDict(sorted(brute_results_dict.items())) - bruted_count = len(sorted_dict) - print "\nBluto Results: \n" - for item in sorted_dict: - if item is not '*.' + domain: - if item is not '@.' + domain: - if item in sub_intrest: - print colored(item + "\t", 'red'), colored(sorted_dict[item], 'red') - else: - print item + "\t",sorted_dict[item] - - time_spent_email_f = str(datetime.timedelta(seconds=(time_spent_email))).split('.')[0] - time_spent_brute_f = str(datetime.timedelta(seconds=(time_spent_brute))).split('.')[0] - time_spent_total_f = str(datetime.timedelta(seconds=(time_spent_total))).split('.')[0] - - print '\nHosts Identified: {}' .format(str(bruted_count)) - print 'Potential Emails Found: {}' .format(str(email_count)) - print 'Potential Staff Members Found: {}' .format(str(staff_count)) - print 'Compromised Accounts: {}' .format(str(c_accounts)) - print 'Potential Usernames Found: {}'.format(username_count) - print 'Potential Software Found: {}'.format(software_count) - print 'Documents Downloaded: {}'.format(download_count) - print "Email Enumeration:", time_spent_email_f - print "Requests executed:", str(check_count) + " in ", time_spent_brute_f - print "Total Time:", time_spent_total_f - - info('Hosts Identified: {}' .format(str(bruted_count))) - info("Email Enumeration: {}" .format(str(time_spent_email_f))) - info('Compromised Accounts: {}' .format(str(c_accounts))) - info('Potential Staff Members Found: {}' .format(str(staff_count))) - info('Potential Emails Found: {}' .format(str(email_count))) - info("Total Time:" .format(str(time_spent_total_f))) - info('Documents Downloaded: {}'.format(download_count)) - info('DNS No Wild Cards + Email Hunter Run completed') - info('Output action_output_wild_false_hunter: Completed') - - domain_r = domain.split('.') - docs = os.path.expanduser('~/Bluto/doc/{}/'.format(domain_r[0])) - answers = ['no','n','y','yes'] - while True: - print colored("\nWould you like to keep all local data?\n(Local Logs, Downloded Documents, HTML Evidence Report)\n\nYes|No:", "red") - answer = raw_input("").lower() - if answer in answers: - if answer == 'y' or answer == 'yes': - domain - print '\nThe documents are located here: {}'.format(docs) - print 'The logs are located here: {}.'.format(LOG_DIR) - print "\nAn evidence report has been written to {}\n".format(report_location) - while True: - answer = raw_input("Would you like to open this report now? ").lower() - if answer in answers: - if answer == 'y' or answer == 'yes': - print '\nOpening {}' .format(report_location) - webbrowser.open('file://' + str(report_location)) - break - else: - break - else: - print 'Your answer needs to be either yes|y|no|n rather than, {}' .format(answer) - break - else: - shutil.rmtree(docs) - shutil.rmtree(LOG_DIR) - os.remove(report_location) - break - else: - print '\tYour answer needs to be either yes|y|no|n rather than, {}' .format(answer) - - -def write_html(email_evidence_results, linkedin_evidence_results, pwned_results, report_location, company, data_mine): - info('Started HTML Report') - if data_mine is not None: - user_names = data_mine[0] - software_list = data_mine[1] - download_count = data_mine[2] - download_list = data_mine[3] - username_count = len(user_names) - software_count = len(software_list) - header = ''' - - - - - - - -
-

Bluto Evidence Report

-

{a}

-
- '''.format(a=company) - footer = ''' - -
-

Bluto

-

Author: Darryl Lane

-

Twitter: @darryllane101

-
- - - ''' - - emailDescription =''' - -

Email Evidence:

- -
-

- Email evidence includes the email address and the location it was found, this allows for potential remediation. - If corporate emails are to be utilised in the public domain, it is recommended that they are generic in nature and are not able to - authenticate to any public corporate services such as VPN, or similare remote control services. - - This data can also be used in further attack vectors such as potential targets for Social Engineering and Phishing attacks. -

-
- - ''' - metaDescription =''' - -

MetaData Evidence:

- -
-

- Various techniques were used to gather potentially useful information on the scoped domain. The consultant - identified multiple documents available for download from the scoped domains website/s. These documents could hold potentially - sensitive data such as usernames, email addresses, folder structures, printers, operating system version information and - software version information. This information can prove to be very useful to an attacker when targeting various vectors - such as Social Engineering, password attacks and to expose further attack vectors. - - It is recommended that all document metadata is sanitised before being published into the public domain. -

-
- - ''' - - linkedinDescription =''' - -

LinkedIn Evidence:

- -
-

- Staff names, job roles and associations can be gathered from social media sites such as LinkedIn. This information can be used - to attempt futher information gathering via vectors such as Social Engineering techniques, phone attacks, and phishing attacks. This data can also be used to try determine more - information such as potential email addresses. -

-
- - ''' - - compromisedDescription =''' - -

Compromised Account Evidence:

- -
-

- This data was made publicly available due to a breach, this means that these account passwords and any portals that are utilised by these accounts - could be compromised. It is recommedned that all account passwords are modified and made to adhere to company policy. -

-
- - ''' - - try: - with open(report_location, 'w') as myFile: - myFile.write(header) - myFile.write('
') - if email_evidence_results: - myFile.write(emailDescription) - myFile.write('') - myFile.write('') - myFile.write('') - myFile.write('') - myFile.write('') - for email, url in email_evidence_results: - myFile.write('') - myFile.write(''.format(email)) - myFile.write(''.format(url)) - myFile.write('') - myFile.write('
Email AddressURL Address
{}{}
') - if linkedin_evidence_results: - myFile.write(linkedinDescription) - if linkedin_evidence_results: - for url, person, clean in linkedin_evidence_results: - myFile.write('') - myFile.write('

'.format(person)) - myFile.write('') - myFile.write(''.format(clean)) - myFile.write('') - myFile.write(''.format(url)) - myFile.write('

') - myFile.write('
Person: {}
Role: {}
Url: {}
') - if pwned_results: - myFile.write(compromisedDescription) - myFile.write('') - if pwned_results: - for result in pwned_results: - myFile.write('

'.format(result[0])) - myFile.write('') - myFile.write(''.format(result[1])) - myFile.write('') - myFile.write(''.format(result[2])) - myFile.write('') - myFile.write(''.format(result[3])) - myFile.write('') - myFile.write(''.format(result[4])) - myFile.write('') - myFile.write(''.format(result[5])) - myFile.write('

') - myFile.write('
Email: {}
Domain: {}
Data: {}
Compromise Date: {}
Date Added: {}
Description:

{}

') - if data_mine: - myFile.write(metaDescription) - myFile.write('') - if data_mine: - myFile.write('') - if software_count: - myFile.write('') - if username_count: - myFile.write('') - if download_count: - myFile.write('') - myFile.write('') - myFile.write('') - if software_count: - myFile.write(''.format(software_count)) - if username_count: - myFile.write(''.format(username_count)) - if download_count: - myFile.write(''.format(download_count)) - myFile.write('') - myFile.write('
Software CountUsername CountDownload Count
{}{}{}
') - myFile.write('') - myFile.write('
') - if user_names: - myFile.write('') - myFile.write('') - myFile.write('') - for username in user_names: - myFile.write('') - myFile.write(''.format(username)) - myFile.write('') - myFile.write('
Usernames
{}
') - myFile.write('') - myFile.write('
') - if software_list: - myFile.write('') - myFile.write('') - myFile.write('') - for software in software_list: - myFile.write('') - myFile.write(''.format(software)) - myFile.write('') - myFile.write('
Software
{}
') - myFile.write('') - if download_list: - myFile.write('') - myFile.write('') - myFile.write('') - for doc in download_list: - myFile.write('') - myFile.write(''.format(doc)) - myFile.write('') - myFile.write('
Document
{}
') - myFile.write('
') - myFile.write(footer) - myFile.write('') - myFile.write('') - myFile.close() - info('Completed HTML Report') - except IOError,e: - info('IOError', exc_info=True) - except Exception: - info('An Unhandled Exception Occured', exc_info=True) diff --git a/Bluto/modules/search.py.bak b/Bluto/modules/search.py.bak deleted file mode 100644 index c3cb949..0000000 --- a/Bluto/modules/search.py.bak +++ /dev/null @@ -1,383 +0,0 @@ -#!/usr/local/bin/python -# -*- coding: utf-8 -*- - -import dns.resolver -import unicodedata -import traceback -import sys -import re -import requests -import random -import time -import urllib2 -import json -from termcolor import colored -from bs4 import BeautifulSoup -from bluto_logging import info, INFO_LOG_FILE - -requests.packages.urllib3.disable_warnings() - -def action_google(domain, userCountry, userServer, q, user_agents, prox): - info('Google Search Started') - uas = user_agents - searchfor = '@' + '"' + domain + '"' - entries_tuples = [] - seen = set() - results = [] - for start in range(1,10,1): - ua = random.choice(uas) - try: - if prox == True: - proxy = {'http' : 'http://127.0.0.1:8080'} - else: - pass - headers = {"User-Agent" : ua, - 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', - 'Accept-Language': 'en-US,en;q=0.5', - 'Accept-Encoding': 'gzip, deflate', - 'Referer': 'https://www.google.com'} - payload = { 'nord':'1', 'q': searchfor, 'start': start*10} - - link = '{0}/search?num=200' .format(userServer) - if prox == True: - response = requests.get(link, headers=headers, params=payload, proxies=proxy) - else: - response = requests.get(link, headers=headers, params=payload) - - response.raise_for_status() - response.text.encode('ascii', 'ignore').decode('ascii') - soup = BeautifulSoup(response.text, "lxml") - - for div in soup.select("div.g"): - - for div in soup.select("div.g"): - - email_temp = div.find("span", class_="st") - clean = re.sub('', '', email_temp.text) - clean = re.sub('', '', email_temp.text) - match = re.findall('[a-zA-Z0-9.]*' + '@' + domain, clean) - try: - if match: - if match is not '@' + domain: - if match is not '@': - url = div.find('cite').text - email = str(match).replace("u'",'').replace('[','').replace(']','').replace("'",'') - entries_tuples.append((email.lower(),str(url).replace("u'",'').replace("'",""))) - except Exception, e: - pass - time.sleep(3) - for urls in entries_tuples: - if urls[1] not in seen: - results.append(urls) - seen.add(urls[1]) - except requests.exceptions.HTTPError as e: - if e.response.status_code == 503: - info('Google is responding with a Captcha, other searches will continue') - break - except AttributeError as f: - pass - except Exception: - info('An Unhandled Exception Has Occured, Please Check The Log For Details' + INFO_LOG_FILE) - - info('Google Search Completed') - q.put(sorted(results)) - - -#Takes [list[tuples]]email~url #Returns [list[tuples]]email_address, url_found, breach_domain, breach_data, breach_date, / -#breach_added, breach_description -def action_pwned(emails): - info('Compromised Account Enumeration Search Started') - pwend_data = [] - seen = set() - for email in emails: - link = 'https://haveibeenpwned.com/api/v2/breachedaccount/{}'.format(email) - try: - headers = {"Connection" : "close", - "User-Agent" : "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)", - 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', - 'Accept-Language': 'en-US,en;q=0.5', - 'Accept-Encoding': 'gzip, deflate'} - - response = requests.get(link, headers=headers) - json_data = response.json() - if json_data: - if email in seen: - pass - else: - for item in json_data: - seen.add(email) - email_address = email - breach_domain = str(item['Domain']).replace("u'","") - breach_data = str(item['DataClasses']).replace("u'","'").replace('"','').replace('[','').replace(']','') - breach_date = str(item['BreachDate']).replace("u'","") - breach_added = str(item['AddedDate']).replace("u'","").replace('T',' ').replace('Z','') - breach_description = str(item['Description']).replace("u'","") - pwend_data.append((email_address, breach_domain, breach_data, breach_date, breach_added, breach_description)) - - except ValueError: - pass - except Exception: - info('An Unhandled Exception Has Occured, Please Check The Log For Details\n' + INFO_LOG_FILE, exc_info=True) - - info('Compromised Account Enumeration Search Completed') - return pwend_data - - -#Takes domain[str], api[list], user_agents[list] #Returns email,url [list[tuples]] Queue[object], prox[str] -def action_emailHunter(domain, api, user_agents, q, prox): - info('Email Hunter Search Started') - emails = [] - uas = user_agents - ua = random.choice(uas) - link = 'https://api.emailhunter.co/v1/search?domain={0}&api_key={1}'.format(domain,api) - - if prox == True: - proxy = {'http' : 'http://127.0.0.1:8080'} - else: - pass - try: - headers = {"User-Agent" : ua, - 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', - 'Accept-Language': 'en-US,en;q=0.5', - 'Accept-Encoding': 'gzip, deflate'} - if prox == True: - response = requests.get(link, headers=headers, proxies=proxy) - else: - response = requests.get(link, headers=headers) - if response.status_code == 200: - json_data = response.json() - for value in json_data['emails']: - for domain in value['sources']: - url = str(domain['uri']).replace("u'","") - email = str(value['value']).replace("u'","") - emails.append((email,url)) - elif response.status_code == 401: - json_data = response.json() - if json_data['message'] =='Too many calls for this period.': - print colored("\tError:\tIt seems the Hunter API key being used has reached\n\t\tit's limit for this month.", 'red') - print colored('\tAPI Key: {}\n'.format(api),'red') - q.put(None) - return None - if json_data['message'] == 'Invalid or missing api key.': - print colored("\tError:\tIt seems the Hunter API key being used is no longer valid,\nit was probably deleted.", 'red') - print colored('\tAPI Key: {}\n'.format(api),'red') - print colored('\tWhy don\'t you grab yourself a new one (they are free)','green') - print colored('\thttps://hunter.io/api_keys','green') - q.put(None) - return None - else: - raise ValueError('No Response From Hunter') - except UnboundLocalError,e: - print e - except KeyError: - pass - except ValueError: - info(traceback.print_exc()) - pass - except Exception: - traceback.print_exc() - info('An Unhandled Exception Has Occured, Please Check The Log For Details\n' + INFO_LOG_FILE, exc_info=True) - - info('Email Hunter Search Completed') - q.put(sorted(emails)) - - -def action_bing_true(domain, q, user_agents, prox): - info('Bing Search Started') - emails = [] - uas = user_agents - searchfor = '@' + '"' + domain + '"' - for start in range(0,30): - ua = random.choice(uas) - if prox == True: - proxy = {'http' : 'http://127.0.0.1:8080'} - else: - pass - try: - headers = {"Connection" : "close", - "User-Agent" : ua, - 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', - 'Accept-Language': 'en-US,en;q=0.5', - 'Accept-Encoding': 'gzip, deflate'} - payload = { 'q': searchfor, 'first': start} - link = 'https://www.bing.com/search' - if prox == True: - response = requests.get(link, headers=headers, params=payload, proxies=proxy) - else: - response = requests.get(link, headers=headers, params=payload) - reg_emails = re.compile('[a-zA-Z0-9.-]*' + '@' + '') - temp = reg_emails.findall(response.text) - time.sleep(1) - for item in temp: - clean = item.replace("", "") - email.append(clean + domain) - - except Exception: - continue - info('Bing Search Completed') - q.put(sorted(emails)) - -def doc_exalead(domain, user_agents, prox, q): - document_list = [] - uas = user_agents - info('Exalead Document Search Started') - for start in range(0,80,10): - ua = random.choice(uas) - link = 'http://www.exalead.com/search/web/results/?search_language=&q=(filetype:xls+OR+filetype:doc+OR++filetype:pdf+OR+filetype:ppt)+site:{}&search_language=&elements_per_page=10&start_index={}'.format(domain, start) - if prox == True: - proxy = {'http' : 'http://127.0.0.1:8080'} - else: - pass - try: - headers = {"Connection" : "close", - "User-Agent" : ua, - 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', - 'Accept-Language': 'en-US,en;q=0.5', - 'Accept-Encoding': 'gzip, deflate'} - if prox == True: - response = requests.get(link, headers=headers, proxies=proxy) - else: - response = requests.get(link, headers=headers) - soup = BeautifulSoup(response.text, "lxml") - if soup.find('label', {'class': 'control-label', 'for': 'id_captcha'}): - info("So you don't like spinach?") - info("Captchas are preventing some document searches.") - break - for div in soup.findAll('li', {'class': 'media'}): - document = div.find('a', href=True)['href'] - document = urllib2.unquote(document) - document_list.append(document) - - except Exception: - info('An Unhandled Exception Has Occured, Please Check The Log For Details' + INFO_LOG_FILE) - continue - - time.sleep(10) - potential_docs = len(document_list) - info('Exalead Document Search Finished') - info('Potential Exalead Documents Found: {}'.format(potential_docs)) - q.put(document_list) - -def doc_bing(domain, user_agents, prox, q): - document_list = [] - uas = user_agents - info('Bing Document Search Started') - for start in range(1,300,10): - ua = random.choice(uas) - if prox == True: - proxy = {'http' : 'http://127.0.0.1:8080'} - else: - pass - try: - headers = {"Connection" : "close", - "User-Agent" : ua, - 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', - 'Accept-Language': 'en-US,en;q=0.5', - 'Accept-Encoding': 'gzip, deflate'} - payload = { 'q': 'filetype:(doc dot docx docm dotx dotm docb xls xlt xlm xlsx xlsm xltx xltm xlsb xla xlam xll xlw ppt pot pps pptx pptm potx potm ppam ppsx ppsm sldx sldm pub pdf) site:{}'.format(domain), 'first': start} - link = 'http://www.bing.com/search' - if prox == True: - response = requests.get(link, headers=headers, proxies=proxy, params=payload) - else: - response = requests.get(link, headers=headers, params=payload) - - soup = BeautifulSoup(response.text, "lxml") - - divs = soup.findAll('li', {'class': 'b_algo'}) - for div in divs: - h2 = div.find('h2') - document = h2.find('a', href=True)['href'] - document = urllib2.unquote(document) - document_list.append(document) - except requests.models.ChunkedEncodingError: - continue - except Exception: - traceback.print_exc() - continue - potential_docs = len(document_list) - info('Bing Document Search Finished') - q.put(document_list) - -def action_linkedin(domain, userCountry, q, company, user_agents, prox): - info('LinkedIn Search Started') - uas = user_agents - entries_tuples = [] - seen = set() - results = [] - who_error = False - searchfor = 'site:linkedin.com/in ' + '"' + company + '"' - ua = random.choice(uas) - for start in range(1,50,1): - if prox == True: - proxy = {'http' : 'http://127.0.0.1:8080'} - else: - pass - try: - headers = {"Connection" : "close", - "User-Agent" : ua, - 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', - 'Accept-Language': 'en-US,en;q=0.5', - 'Accept-Encoding': 'gzip, deflate'} - payload = { 'q': searchfor, 'first': start} - link = 'http://www.bing.com/search' - if prox == True: - response = requests.get(link, headers=headers, params=payload, proxies=proxy) - else: - response = requests.get(link, headers=headers, params=payload) - - response.text.encode('utf-8') - soup = BeautifulSoup(response.text, "lxml") - - for div in soup.findAll('li', {'class': 'b_algo'}): - title_temp = div.find('a').text - url = div.find('cite').text.encode('utf-8') - person = str((title_temp.split(' | ')[0])) - description_temp = div.find('div', {'class': 'b_caption'}) - description = description_temp.find('p').text.encode('utf-8').lstrip('View ').replace("’s","").replace("professional profile on LinkedIn. ... ","").replace(" professional profile on LinkedIn. LinkedIn is the world's largest business network, ...","").replace("’S","").replace("’","").replace("professional profile on LinkedIn.","").replace(person, '').lstrip(' ').lstrip('. ').replace("LinkedIn is the world's largest business network, helping professionals like discover ...","").replace("LinkedIn is the world's largest business network, helping professionals like discover inside ...","").replace("professional profile on ... • ","").replace("professional ... ","").replace("...","").lstrip('•').lstrip(' ') - entries_tuples.append((url, person.title(), description)) - - except Exception: - continue - - for urls in entries_tuples: - if urls[1] not in seen: - results.append(urls) - seen.add(urls[1]) - - info('LinkedIn Search Completed') - q.put(sorted(results)) - - -def action_netcraft(domain, myResolver): - info('NetCraft Search Started') - netcraft_list = [] - print "\nPassive Gatherings From NetCraft\n" - try: - link = "http://searchdns.netcraft.com/?restriction=site+contains&host=*.{}&lookup=wait..&position=limited" .format (domain) - response = requests.get(link) - soup = BeautifulSoup(response.content, 'lxml') - pattern = 'rel="nofollow">([a-z\.\-A-Z0-9]+)' - sub_results = re.findall(pattern, response.content) - except dns.exception.Timeout: - pass - except Exception: - info('An Unhandled Exception Has Occured, Please Check The Log For Details\n' + INFO_LOG_FILE, exc_info=True) - - if sub_results: - for item in sub_results: - try: - netcheck = myResolver.query(item + '.' + domain) - for data in netcheck: - netcraft_list.append(item + '.' + domain + ' ' + str(data)) - print colored(item + '.' + domain, 'red') - except dns.exception.Timeout: - pass - except dns.resolver.NXDOMAIN: - pass - except Exception: - info('An Unhandled Exception Has Occured, Please Check The Log For Details\n' + INFO_LOG_FILE, exc_info=True) - else: - print '\tNo Results Found' - - info('NetCraft Completed') - return netcraft_list