690 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			690 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			Python
		
	
	
	
| #!/usr/bin/env python3
 | |
| 
 | |
| __version__ = 'v1.0.2'
 | |
| 
 | |
| try:
 | |
|     import sys
 | |
|     import signal
 | |
|     from colorama import Fore, Style
 | |
|     import atexit
 | |
|     import argparse
 | |
|     import random
 | |
|     import time
 | |
|     import hashlib
 | |
|     import json
 | |
|     import re
 | |
|     import requests
 | |
|     import urllib3
 | |
|     from bs4 import BeautifulSoup
 | |
|     import html5lib
 | |
|     import phonenumbers
 | |
|     from phonenumbers import carrier
 | |
|     from phonenumbers import geocoder
 | |
|     from phonenumbers import timezone
 | |
|     from urllib.parse import urlencode
 | |
| except Exception as e:
 | |
|     print('[!] Missing requirements. Try running python3 -m pip install -r requirements.txt')
 | |
|     sys.exit()
 | |
| 
 | |
| parser = argparse.ArgumentParser(description="Advanced information gathering tool for phone numbers (https://github.com/sundowndev/PhoneInfoga) version {}".format(__version__),
 | |
|                                  usage='%(prog)s -n <number> [options]')
 | |
| 
 | |
| parser.add_argument('-n', '--number', metavar='number', type=str,
 | |
|                     help='The phone number to scan (E164 or international format)')
 | |
| 
 | |
| parser.add_argument('-i', '--input', metavar="input_file", type=argparse.FileType('r'),
 | |
|                     help='Phone number list to scan (one per line)')
 | |
| 
 | |
| parser.add_argument('-o', '--output', metavar="output_file", type=argparse.FileType('w'),
 | |
|                     help='Output to save scan results')
 | |
| 
 | |
| parser.add_argument('-s', '--scanner', metavar="scanner", default="all", type=str,
 | |
|                     help='The scanner to use')
 | |
| 
 | |
| parser.add_argument('--osint', action='store_true',
 | |
|                     help='Use OSINT reconnaissance')
 | |
| 
 | |
| parser.add_argument('-u', '--update', action='store_true',
 | |
|                     help='Update the project')
 | |
| 
 | |
| parser.add_argument('--no-ansi', action='store_true',
 | |
|                     help='Disable colored output')
 | |
| 
 | |
| parser.add_argument('-v', '--version', action='store_true',
 | |
|                     help='Show tool version')
 | |
| 
 | |
| args = parser.parse_args()
 | |
| 
 | |
| uagent = []
 | |
| uagent.append(
 | |
|     "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.0) Opera 12.14")
 | |
| uagent.append(
 | |
|     "Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:26.0) Gecko/20100101 Firefox/26.0")
 | |
| uagent.append(
 | |
|     "Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.1.3) Gecko/20090913 Firefox/3.5.3")
 | |
| uagent.append(
 | |
|     "Mozilla/5.0 (Windows; U; Windows NT 6.1; en; rv:1.9.1.3) Gecko/20090824 Firefox/3.5.3 (.NET CLR 3.5.30729)")
 | |
| uagent.append(
 | |
|     "Mozilla/5.0 (Windows NT 6.2) AppleWebKit/535.7 (KHTML, like Gecko) Comodo_Dragon/16.1.1.0 Chrome/16.0.912.63 Safari/535.7")
 | |
| uagent.append(
 | |
|     "Mozilla/5.0 (Windows; U; Windows NT 5.2; en-US; rv:1.9.1.3) Gecko/20090824 Firefox/3.5.3 (.NET CLR 3.5.30729)")
 | |
| uagent.append(
 | |
|     "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.1) Gecko/20090718 Firefox/3.5.1")
 | |
| uagent.append(
 | |
|     "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:63.0) Gecko/20100101 Firefox/63.0")
 | |
| 
 | |
| number = ''  # Full number format; e.g: 3312345678
 | |
| localNumber = ''  # Local number format; e.g: 06 12 34 56 78
 | |
| internationalNumber = ''  # International number format; e.g: +33 6 12 34 56 78
 | |
| numberCountryCode = ''  # Dial code; e.g: 33
 | |
| numberCountry = ''  # Country; e.g: fr
 | |
| 
 | |
| googleAbuseToken = ''
 | |
| customFormatting = ''
 | |
| 
 | |
| if args.no_ansi or args.output:
 | |
|     code_info = '[-] '
 | |
|     code_warning = '(!) '
 | |
|     code_result = '[+] '
 | |
|     code_error = '[!] '
 | |
|     code_title = ''
 | |
| else:
 | |
|     code_info = Fore.RESET + Style.BRIGHT + '[-] '
 | |
|     code_warning = Fore.YELLOW + Style.BRIGHT + '(!) '
 | |
|     code_result = Fore.GREEN + Style.BRIGHT + '[+] '
 | |
|     code_error = Fore.RED + Style.BRIGHT + '[!] '
 | |
|     code_title = Fore.YELLOW + Style.BRIGHT
 | |
| 
 | |
| 
 | |
| def banner():
 | |
|     print("    ___ _                       _____        __                   ")
 | |
|     print("   / _ \ |__   ___  _ __   ___  \_   \_ __  / _| ___   __ _  __ _ ")
 | |
|     print("  / /_)/ '_ \ / _ \| '_ \ / _ \  / /\/ '_ \| |_ / _ \ / _` |/ _` |")
 | |
|     print(" / ___/| | | | (_) | | | |  __/\/ /_ | | | |  _| (_) | (_| | (_| |")
 | |
|     print(" \/    |_| |_|\___/|_| |_|\___\____/ |_| |_|_|  \___/ \__, |\__,_|")
 | |
|     print("                                                      |___/       ")
 | |
|     print(" PhoneInfoga Ver. {}".format(__version__))
 | |
|     print(" Coded by Sundowndev")
 | |
|     print("\n")
 | |
| 
 | |
| 
 | |
| def resetColors():
 | |
|     if not args.output:
 | |
|         print(Style.RESET_ALL)
 | |
| 
 | |
| 
 | |
| def search(req, stop):
 | |
|     global googleAbuseToken
 | |
|     global uagent
 | |
| 
 | |
|     chosenUserAgent = random.choice(uagent)
 | |
| 
 | |
|     reqSession = requests.Session()
 | |
|     headers = {
 | |
|         'User-Agent': chosenUserAgent,
 | |
|         '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',
 | |
|         'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.7',
 | |
|         'Keep-Alive': '115',
 | |
|         'Connection': 'keep-alive',
 | |
|         'Cache-Control': 'no-cache',
 | |
|         'Cookie': 'Cookie: CGIC=Ij90ZXh0L2h0bWwsYXBwbGljYXRpb24veGh0bWwreG1sLGFwcGxpY2F0aW9uL3htbDtxPTAuOSwqLyo7cT0wLjg; CONSENT=YES+RE.fr+20150809-08-0; 1P_JAR=2018-11-28-14; NID=148=aSdSHJz71rufCokaUC93nH3H7lOb8E7BNezDWV-PyyiHTXqWK5Y5hsvj7IAzhZAK04-QNTXjYoLXVu_eiAJkiE46DlNn6JjjgCtY-7Fr0I4JaH-PZRb7WFgSTjiFqh0fw2cCWyN69DeP92dzMd572tQW2Z1gPwno3xuPrYC1T64wOud1DjZDhVAZkpk6UkBrU0PBcnLWL7YdL6IbEaCQlAI9BwaxoH_eywPVyS9V; SID=uAYeu3gT23GCz-ktdGInQuOSf-5SSzl3Plw11-CwsEYY0mqJLSiv7tFKeRpB_5iz8SH5lg.; HSID=AZmH_ctAfs0XbWOCJ; SSID=A0PcRJSylWIxJYTq_; APISID=HHB2bKfJ-2ZUL5-R/Ac0GK3qtM8EHkloNw; SAPISID=wQoxetHBpyo4pJKE/A2P6DUM9zGnStpIVt; SIDCC=ABtHo-EhFAa2AJrJIUgRGtRooWyVK0bAwiQ4UgDmKamfe88xOYBXM47FoL5oZaTxR3H-eOp7-rE; OTZ=4671861_52_52_123900_48_436380; OGPC=873035776-8:; OGP=-873035776:;'
 | |
|     }
 | |
| 
 | |
|     try:
 | |
|         REQ = urlencode({'q': req})
 | |
|         URL = 'https://www.google.com/search?tbs=li:1&{}&gws_rd=ssl&gl=us '.format(
 | |
|             REQ)
 | |
|         r = reqSession.get(URL + googleAbuseToken, headers=headers)
 | |
| 
 | |
|         while r.status_code != 200:
 | |
|             print(code_warning + 'You are temporary blacklisted from Google search. Complete the captcha at the following URL and copy/paste the content of GOOGLE_ABUSE_EXEMPTION cookie : {}'.format(URL))
 | |
|             print('\n' + code_info +
 | |
|                   'Need help ? Read https://github.com/sundowndev/PhoneInfoga/wiki')
 | |
|             token = input('\nGOOGLE_ABUSE_EXEMPTION=')
 | |
|             googleAbuseToken = '&google_abuse=' + token
 | |
|             r = reqSession.get(URL + googleAbuseToken, headers=headers)
 | |
| 
 | |
|         soup = BeautifulSoup(r.text, 'html5lib')
 | |
| 
 | |
|         results = soup.find("div", id="search").find_all("div", class_="g")
 | |
| 
 | |
|         links = []
 | |
|         counter = 0
 | |
| 
 | |
|         for result in results:
 | |
|             counter += 1
 | |
| 
 | |
|             if int(counter) > int(stop):
 | |
|                 break
 | |
| 
 | |
|             url = result.find("a").get('href')
 | |
|             url = re.sub(r'(?:\/url\?q\=)', '', url)
 | |
|             url = re.sub(r'(?:\/url\?url\=)', '', url)
 | |
|             url = re.sub(r'(?:\&sa\=)(?:.*)', '', url)
 | |
|             url = re.sub(r'(?:\&rct\=)(?:.*)', '', url)
 | |
| 
 | |
|             if re.match(r"^(?:\/search\?q\=)", url) is not None:
 | |
|                 url = 'https://google.com' + url
 | |
| 
 | |
|             if url is not None:
 | |
|                 links.append(url)
 | |
| 
 | |
|         return links
 | |
|     except Exception as e:
 | |
|         print(code_error + 'Request failed. Please retry or open an issue on https://github.com/sundowndev/PhoneInfoga.')
 | |
|         print(e)
 | |
|         return []
 | |
| 
 | |
| 
 | |
| def formatNumber(InputNumber):
 | |
|     return re.sub("(?:\+)?(?:[^[0-9]*)", "", InputNumber)
 | |
| 
 | |
| 
 | |
| def localScan(InputNumber):
 | |
|     global number
 | |
|     global localNumber
 | |
|     global internationalNumber
 | |
|     global numberCountryCode
 | |
|     global numberCountry
 | |
| 
 | |
|     print(code_info + 'Running local scan...')
 | |
| 
 | |
|     FormattedPhoneNumber = "+" + formatNumber(InputNumber)
 | |
| 
 | |
|     try:
 | |
|         PhoneNumberObject = phonenumbers.parse(FormattedPhoneNumber, None)
 | |
|     except Exception as e:
 | |
|         return False
 | |
|     else:
 | |
|         if not phonenumbers.is_valid_number(PhoneNumberObject):
 | |
|             return False
 | |
| 
 | |
|         number = phonenumbers.format_number(
 | |
|             PhoneNumberObject, phonenumbers.PhoneNumberFormat.E164).replace('+', '')
 | |
|         numberCountryCode = phonenumbers.format_number(
 | |
|             PhoneNumberObject, phonenumbers.PhoneNumberFormat.INTERNATIONAL).split(' ')[0]
 | |
|         numberCountry = phonenumbers.region_code_for_country_code(
 | |
|             int(numberCountryCode))
 | |
| 
 | |
|         localNumber = phonenumbers.format_number(
 | |
|             PhoneNumberObject, phonenumbers.PhoneNumberFormat.E164).replace(numberCountryCode, '')
 | |
|         internationalNumber = phonenumbers.format_number(
 | |
|             PhoneNumberObject, phonenumbers.PhoneNumberFormat.INTERNATIONAL)
 | |
| 
 | |
|         country = geocoder.country_name_for_number(PhoneNumberObject, "en")
 | |
|         location = geocoder.description_for_number(PhoneNumberObject, "en")
 | |
|         carrierName = carrier.name_for_number(PhoneNumberObject, 'en')
 | |
| 
 | |
|         print(code_result + 'International format: {}'.format(internationalNumber))
 | |
|         print(code_result + 'Local format: 0{}'.format(localNumber))
 | |
|         print(code_result + 'Country found: {} ({})'.format(country, numberCountryCode))
 | |
|         print(code_result + 'City/Area: {}'.format(location))
 | |
|         print(code_result + 'Carrier: {}'.format(carrierName))
 | |
|         for timezoneResult in timezone.time_zones_for_number(PhoneNumberObject):
 | |
|             print(code_result + 'Timezone: {}'.format(timezoneResult))
 | |
| 
 | |
|         if phonenumbers.is_possible_number(PhoneNumberObject):
 | |
|             print(code_info + 'The number is valid and possible.')
 | |
|         else:
 | |
|             print(code_warning + 'The number is valid but might not be possible.')
 | |
| 
 | |
| 
 | |
| def numverifyScan():
 | |
|     global number
 | |
| 
 | |
|     if not args.scanner == 'numverify' and not args.scanner == 'all':
 | |
|         return -1
 | |
| 
 | |
|     print(code_info + 'Running Numverify.com scan...')
 | |
| 
 | |
|     try:
 | |
|         requestSecret = ''
 | |
|         resp = requests.get('https://numverify.com/')
 | |
|         soup = BeautifulSoup(resp.text, "html5lib")
 | |
|     except Exception as e:
 | |
|         print(code_error + 'Numverify.com is not available')
 | |
|         return -1
 | |
| 
 | |
|     for tag in soup.find_all("input", type="hidden"):
 | |
|         if tag['name'] == "scl_request_secret":
 | |
|             requestSecret = tag['value']
 | |
|             break
 | |
| 
 | |
|     apiKey = hashlib.md5((number + requestSecret).encode('utf-8')).hexdigest()
 | |
| 
 | |
|     headers = {
 | |
|         'Host': 'numverify.com',
 | |
|         'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:64.0) Gecko/20100101 Firefox/64.0',
 | |
|         'Accept': 'application/json, text/javascript, */*; q=0.01',
 | |
|         'Accept-Language': 'fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3',
 | |
|         'Accept-Encoding': 'gzip, deflate, br',
 | |
|         'Referer': 'https://numverify.com/',
 | |
|         'X-Requested-With': 'XMLHttpRequest',
 | |
|         'DNT': '1',
 | |
|         'Connection': 'keep-alive',
 | |
|         'Pragma': 'no-cache',
 | |
|         'Cache-Control': 'no-cache'
 | |
|     }
 | |
| 
 | |
|     try:
 | |
|         response = requests.request(
 | |
|             "GET", "https://numverify.com/php_helper_scripts/phone_api.php?secret_key={}&number={}".format(apiKey, number), data="", headers=headers)
 | |
| 
 | |
|         data = json.loads(response.content.decode('utf-8'))
 | |
|     except Exception as e:
 | |
|         print(code_error + 'Numverify.com is not available')
 | |
|         return -1
 | |
| 
 | |
|     if response.content == "Unauthorized" or response.status_code != 200:
 | |
|         print((code_error + "An error occured while calling the API (bad request or wrong api key)."))
 | |
|         return -1
 | |
| 
 | |
|     if data["valid"] == False:
 | |
|         print((code_error + "Error: Please specify a valid phone number. Example: +6464806649"))
 | |
|         sys.exit()
 | |
| 
 | |
|     InternationalNumber = '({}){}'.format(
 | |
|         data["country_prefix"], data["local_format"])
 | |
| 
 | |
|     print((code_result +
 | |
|            "Number: ({}) {}").format(data["country_prefix"], data["local_format"]))
 | |
|     print((code_result +
 | |
|            "Country: {} ({})").format(data["country_name"], data["country_code"]))
 | |
|     print((code_result + "Location: {}").format(data["location"]))
 | |
|     print((code_result + "Carrier: {}").format(data["carrier"]))
 | |
|     print((code_result + "Line type: {}").format(data["line_type"]))
 | |
| 
 | |
|     if data["line_type"] == 'landline':
 | |
|         print((code_warning + "This is most likely a landline, but it can still be a fixed VoIP number."))
 | |
|     elif data["line_type"] == 'mobile':
 | |
|         print((code_warning + "This is most likely a mobile number, but it can still be a VoIP number."))
 | |
| 
 | |
| 
 | |
| def ovhScan():
 | |
|     global localNumber
 | |
|     global numberCountry
 | |
| 
 | |
|     if not args.scanner == 'ovh' and not args.scanner == 'all':
 | |
|         return -1
 | |
| 
 | |
|     print(code_info + 'Running OVH scan...')
 | |
| 
 | |
|     querystring = {"country": numberCountry.lower()}
 | |
| 
 | |
|     headers = {
 | |
|         'accept': "application/json",
 | |
|         'cache-control': "no-cache"
 | |
|     }
 | |
| 
 | |
|     try:
 | |
|         response = requests.request(
 | |
|             "GET", "https://api.ovh.com/1.0/telephony/number/detailedZones", data="", headers=headers, params=querystring)
 | |
|         data = json.loads(response.content.decode('utf-8'))
 | |
|     except Exception as e:
 | |
|         print(code_error + 'OVH API is unreachable. Maybe retry later.')
 | |
|         return -1
 | |
| 
 | |
|     if isinstance(data, list):
 | |
|         askedNumber = "0" + localNumber.replace(localNumber[-4:], 'xxxx')
 | |
| 
 | |
|         for voip_number in data:
 | |
|             if voip_number['number'] == askedNumber:
 | |
|                 print((code_info + "1 result found in OVH database"))
 | |
|                 print(
 | |
|                     (code_result + "Number range: {}".format(voip_number['number'])))
 | |
|                 print((code_result + "City: {}".format(voip_number['city'])))
 | |
|                 print((code_result + "Zip code: {}".format(
 | |
|                     voip_number['zipCode'] if voip_number['zipCode'] is not None else '')))
 | |
|                 askForExit()
 | |
| 
 | |
| 
 | |
| def replaceVariables(string):
 | |
|     global number
 | |
|     global internationalNumber
 | |
|     global localNumber
 | |
| 
 | |
|     string = string.replace('$n', number)
 | |
|     string = string.replace('$i', internationalNumber)
 | |
|     string = string.replace('$l', localNumber)
 | |
| 
 | |
|     return string
 | |
| 
 | |
| 
 | |
| def osintIndividualScan():
 | |
|     global number
 | |
|     global internationalNumber
 | |
|     global numberCountryCode
 | |
|     global customFormatting
 | |
| 
 | |
|     dorks = json.load(open('osint/individuals.json'))
 | |
| 
 | |
|     for dork in dorks:
 | |
|         if dork['dialCode'] is None or dork['dialCode'] == numberCountryCode:
 | |
|             if customFormatting:
 | |
|                 dorkRequest = replaceVariables(
 | |
|                     dork['request']) + ' | intext:"{}"'.format(customFormatting)
 | |
|             else:
 | |
|                 dorkRequest = replaceVariables(dork['request'])
 | |
| 
 | |
|             print(
 | |
|                 (code_info + "Searching for footprints on {}...".format(dork['site'])))
 | |
| 
 | |
|             for result in search(dorkRequest, stop=dork['stop']):
 | |
|                 print((code_result + "URL: " + result))
 | |
|         else:
 | |
|             return -1
 | |
| 
 | |
| 
 | |
| def osintReputationScan():
 | |
|     global number
 | |
|     global internationalNumber
 | |
|     global customFormatting
 | |
| 
 | |
|     dorks = json.load(open('osint/reputation.json'))
 | |
| 
 | |
|     for dork in dorks:
 | |
|         if customFormatting:
 | |
|             dorkRequest = replaceVariables(
 | |
|                 dork['request']) + ' | intext:"{}"'.format(customFormatting)
 | |
|         else:
 | |
|             dorkRequest = replaceVariables(dork['request'])
 | |
| 
 | |
|         print((code_info + "Searching for {}...".format(dork['title'])))
 | |
|         for result in search(dorkRequest, stop=dork['stop']):
 | |
|             print((code_result + "URL: " + result))
 | |
| 
 | |
| 
 | |
| def osintSocialMediaScan():
 | |
|     global number
 | |
|     global internationalNumber
 | |
|     global customFormatting
 | |
| 
 | |
|     dorks = json.load(open('osint/social_medias.json'))
 | |
| 
 | |
|     for dork in dorks:
 | |
|         if customFormatting:
 | |
|             dorkRequest = replaceVariables(
 | |
|                 dork['request']) + ' | intext:"{}"'.format(customFormatting)
 | |
|         else:
 | |
|             dorkRequest = replaceVariables(dork['request'])
 | |
| 
 | |
|         print(
 | |
|             (code_info + "Searching for footprints on {}...".format(dork['site'])))
 | |
| 
 | |
|         for result in search(dorkRequest, stop=dork['stop']):
 | |
|             print((code_result + "URL: " + result))
 | |
| 
 | |
| 
 | |
| def osintDisposableNumScan():
 | |
|     global number
 | |
| 
 | |
|     dorks = json.load(open('osint/disposable_num_providers.json'))
 | |
| 
 | |
|     for dork in dorks:
 | |
|         dorkRequest = replaceVariables(dork['request'])
 | |
| 
 | |
|         print(
 | |
|             (code_info + "Searching for footprints on {}...".format(dork['site'])))
 | |
| 
 | |
|         for result in search(dorkRequest, stop=dork['stop']):
 | |
|             print((code_result + "Result found: {}".format(dork['site'])))
 | |
|             print((code_result + "URL: " + result))
 | |
|             askForExit()
 | |
| 
 | |
| 
 | |
| def osintScan(rerun=False):
 | |
|     global number
 | |
|     global localNumber
 | |
|     global internationalNumber
 | |
|     global numberCountryCode
 | |
|     global customFormatting
 | |
| 
 | |
|     if not args.osint:
 | |
|         return -1
 | |
| 
 | |
|     print(code_info + 'Running OSINT footprint reconnaissance...')
 | |
| 
 | |
|     if not rerun:
 | |
|         # Whitepages
 | |
|         print((code_info + "Generating scan URL on 411.com..."))
 | |
|         print(code_result + "Scan URL: https://www.411.com/phone/{}".format(
 | |
|             internationalNumber.replace('+', '').replace(' ', '-')))
 | |
| 
 | |
|         askingCustomPayload = input(
 | |
|             code_info + 'Would you like to use an additional format for this number ? (y/N) ')
 | |
| 
 | |
|     if rerun or askingCustomPayload == 'y' or askingCustomPayload == 'yes':
 | |
|         print(code_info + 'We recommand: {} or {}'.format(internationalNumber,
 | |
|                                                           internationalNumber.replace(numberCountryCode + ' ', '')))
 | |
|         customFormatting = input(code_info + 'Custom format: ')
 | |
| 
 | |
|     print((code_info + '---- Web pages footprints ----'))
 | |
| 
 | |
|     print((code_info + "Searching for footprints on web pages... (limit=10)"))
 | |
|     if customFormatting:
 | |
|         req = '{} | intext:"{}" | intext:"{}" | intext:"{}"'.format(
 | |
|             number, number, internationalNumber, customFormatting)
 | |
|     else:
 | |
|         req = '{} | intext:"{}" | intext:"{}"'.format(
 | |
|             number, number, internationalNumber)
 | |
| 
 | |
|     for result in search(req, stop=10):
 | |
|         print((code_result + "Result found: " + result))
 | |
| 
 | |
|     # Documents
 | |
|     print((code_info + "Searching for documents... (limit=10)"))
 | |
|     if customFormatting:
 | |
|         req = '[ext:doc | ext:docx | ext:odt | ext:pdf | ext:rtf | ext:sxw | ext:psw | ext:ppt | ext:pptx | ext:pps | ext:csv | ext:txt | ext:xls] && [intext:"{}"]'.format(
 | |
|             customFormatting)
 | |
|     else:
 | |
|         req = '[ext:doc | ext:docx | ext:odt | ext:pdf | ext:rtf | ext:sxw | ext:psw | ext:ppt | ext:pptx | ext:pps | ext:csv | ext:txt | ext:xls] && [intext:"{}" | intext:"{}"]'.format(
 | |
|             internationalNumber, localNumber)
 | |
|     for result in search(req, stop=10):
 | |
|         print((code_result + "Result found: " + result))
 | |
| 
 | |
|     print((code_info + '---- Reputation footprints ----'))
 | |
| 
 | |
|     osintReputationScan()
 | |
| 
 | |
|     print((code_info + "Generating URL on scamcallfighters.com..."))
 | |
|     print(code_result +
 | |
|           'http://www.scamcallfighters.com/search-phone-{}.html'.format(number))
 | |
| 
 | |
|     tmpNumAsk = input(
 | |
|         code_info + "Would you like to search for temporary number providers footprints ? (Y/n) ")
 | |
| 
 | |
|     if tmpNumAsk.lower() != 'n' and tmpNumAsk.lower() != 'no':
 | |
|         print((code_info + '---- Temporary number providers footprints ----'))
 | |
| 
 | |
|         try:
 | |
|             print((code_info + "Searching for phone number on tempophone.com..."))
 | |
|             response = requests.request(
 | |
|                 "GET", "https://tempophone.com/api/v1/phones")
 | |
|             data = json.loads(response.content.decode('utf-8'))
 | |
|             for voip_number in data['objects']:
 | |
|                 if voip_number['phone'] == formatNumber(number):
 | |
|                     print(
 | |
|                         (code_result + "Found a temporary number provider: tempophone.com"))
 | |
|                     askForExit()
 | |
|         except Exception as e:
 | |
|             print((code_error + "Unable to reach tempophone.com API. Skipping."))
 | |
| 
 | |
|         osintDisposableNumScan()
 | |
| 
 | |
|     print((code_info + '---- Social media footprints ----'))
 | |
| 
 | |
|     osintSocialMediaScan()
 | |
| 
 | |
|     print((code_info + '---- Phone books footprints ----'))
 | |
| 
 | |
|     if numberCountryCode == '+1':
 | |
|         print((code_info + "Generating URL on True People... "))
 | |
|         print(code_result + 'https://www.truepeoplesearch.com/results?phoneno={}'.format(
 | |
|             internationalNumber.replace(' ', '')))
 | |
| 
 | |
|     osintIndividualScan()
 | |
| 
 | |
|     retry_input = input(
 | |
|         code_info + "Would you like to rerun OSINT scan ? (e.g to use a different format) (y/N) ")
 | |
| 
 | |
|     if retry_input.lower() == 'y' or retry_input.lower() == 'yes':
 | |
|         osintScan(True)
 | |
|     else:
 | |
|         return -1
 | |
| 
 | |
| 
 | |
| def askForExit():
 | |
|     if not args.output:
 | |
|         user_input = input(code_info + "Continue scanning ? (y/N) ")
 | |
| 
 | |
|         if user_input.lower() == 'y' or user_input.lower() == 'yes':
 | |
|             return -1
 | |
|         else:
 | |
|             print(code_info + "Good bye!")
 | |
|             sys.exit()
 | |
| 
 | |
| 
 | |
| def scanNumber(InputNumber):
 | |
|     global number
 | |
|     global localNumber
 | |
|     global internationalNumber
 | |
|     global numberCountryCode
 | |
|     global numberCountry
 | |
| 
 | |
|     print(code_title +
 | |
|           "[!] ---- Fetching informations for {} ---- [!]".format(formatNumber(InputNumber)))
 | |
| 
 | |
|     localScan(InputNumber)
 | |
| 
 | |
|     if not number:
 | |
|         print((code_error + "Error: number {} is not valid. Skipping.".format(formatNumber(InputNumber))))
 | |
|         sys.exit()
 | |
| 
 | |
|     numverifyScan()
 | |
|     ovhScan()
 | |
|     osintScan()
 | |
| 
 | |
|     print(code_info + "Scan finished.")
 | |
| 
 | |
|     if not args.no_ansi and not args.output:
 | |
|         print('\n' + Style.RESET_ALL)
 | |
|     else:
 | |
|         print('\n')
 | |
| 
 | |
| 
 | |
| def download_file(url, target_path):
 | |
|     response = requests.get(url, stream=True)
 | |
|     handle = open(target_path, "wb")
 | |
|     for chunk in response.iter_content(chunk_size=512):
 | |
|         if chunk:  # filter out keep-alive new chunks
 | |
|             handle.write(chunk)
 | |
| 
 | |
| 
 | |
| def updateTool():
 | |
|     print('Updating PhoneInfoga...')
 | |
|     print('Actual version: {}'.format(__version__))
 | |
| 
 | |
|     # Fetching last github tag
 | |
|     new_version = json.loads(requests.get(
 | |
|         'https://api.github.com/repos/sundowndev/PhoneInfoga/tags').content)[0]['name']
 | |
|     print('Last version: {}'.format(new_version))
 | |
| 
 | |
|     osintFiles = [
 | |
|         'disposable_num_providers.json',
 | |
|         'individuals.json',
 | |
|         'reputation.json',
 | |
|         'social_medias.json'
 | |
|     ]
 | |
| 
 | |
|     try:
 | |
|         print('[*] Updating OSINT files')
 | |
| 
 | |
|         for file in osintFiles:
 | |
|             url = 'https://raw.githubusercontent.com/sundowndev/PhoneInfoga/master/osint/{}'.format(
 | |
|                 file)
 | |
|             output_directory = 'osint/{}'.format(file)
 | |
|             download_file(url, output_directory)
 | |
| 
 | |
|         print('[*] Updating python script')
 | |
| 
 | |
|         url = 'https://raw.githubusercontent.com/sundowndev/PhoneInfoga/master/phoneinfoga.py'
 | |
|         output_directory = 'phoneinfoga.py'
 | |
|         download_file(url, output_directory)
 | |
|     except Exception as e:
 | |
|         print('Update failed. Try using git pull.')
 | |
|         sys.exit()
 | |
| 
 | |
|     print('The tool was successfully updated.')
 | |
|     sys.exit()
 | |
| 
 | |
| 
 | |
| def main():
 | |
|     scanners = ['any', 'all', 'numverify', 'ovh']
 | |
| 
 | |
|     banner()
 | |
| 
 | |
|     if sys.version_info[0] < 3:
 | |
|         print(
 | |
|             "\033[1m\033[93m(!) Please run the tool using Python 3" + Style.RESET_ALL)
 | |
|         sys.exit()
 | |
| 
 | |
|     # Reset text color at exit
 | |
|     atexit.register(resetColors)
 | |
| 
 | |
|     # If any param is passed, execute help command
 | |
|     if not len(sys.argv) > 1:
 | |
|         parser.print_help()
 | |
|         sys.exit()
 | |
|     elif args.version:
 | |
|         print("Version {}".format(__version__))
 | |
|         sys.exit()
 | |
| 
 | |
|     requests.packages.urllib3.disable_warnings()
 | |
|     requests.packages.urllib3.util.ssl_.DEFAULT_CIPHERS += 'HIGH:!DH:!aNULL'
 | |
|     try:
 | |
|         requests.packages.urllib3.contrib.pyopenssl.DEFAULT_SSL_CIPHER_LIST += 'HIGH:!DH:!aNULL'
 | |
|     except AttributeError:
 | |
|         # no pyopenssl support used / needed / available
 | |
|         pass
 | |
| 
 | |
|     if args.update:
 | |
|         updateTool()
 | |
| 
 | |
|     if args.output:
 | |
|         if args.osint:
 | |
|             print(
 | |
|                 '\033[91m[!] OSINT scanner is not available using output option (sorry).')
 | |
|             sys.exit()
 | |
| 
 | |
|         sys.stdout = args.output
 | |
|         banner()  # Output banner again in the file
 | |
| 
 | |
|     # Verify scanner option
 | |
|     if not args.scanner in scanners:
 | |
|         print((code_error + "Error: scanner doesn't exists."))
 | |
|         sys.exit()
 | |
| 
 | |
|     if args.number:
 | |
|         scanNumber(args.number)
 | |
|     elif args.input:
 | |
|         for line in args.input.readlines():
 | |
|             scanNumber(line)
 | |
|     else:
 | |
|         parser.print_help()
 | |
|         sys.exit()
 | |
| 
 | |
|     if args.output:
 | |
|         args.output.close()
 | |
| 
 | |
| 
 | |
| def signal_handler(signal, frame):
 | |
|     print('\n[-] You pressed Ctrl+C! Exiting.')
 | |
|     sys.exit()
 | |
| 
 | |
| 
 | |
| if __name__ == '__main__':
 | |
|     signal.signal(signal.SIGINT, signal_handler)
 | |
|     main()
 |