Merge pull request #32 from sundowndev/develop

Scanning improvements, readme & refactor
This commit is contained in:
Raphael 2019-02-18 16:58:42 +01:00 committed by GitHub
commit 8bac8eb377
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 252 additions and 223 deletions

View File

@ -1,15 +1,35 @@
# PhoneInfoga
<h1 align="center">PhoneInfoga</h1>
[![Build Status](https://travis-ci.org/sundowndev/PhoneInfoga.svg?branch=master)](https://travis-ci.org/sundowndev/PhoneInfoga)
![](https://img.shields.io/badge/python-3.6-blue.svg)
![](https://img.shields.io/github/tag/SundownDEV/PhoneInfoga.svg)
![](https://img.shields.io/badge/license-MIT-blue.svg)
<div align="center">
<a href="https://travis-ci.org/sundowndev/PhoneInfoga">
<img src="https://img.shields.io/travis/sundowndev/PhoneInfoga/master.svg?style=flat-square" alt="Build Status" />
</a>
<a href="#">
<img src="https://img.shields.io/badge/python-3.6-blue.svg?style=flat-square" alt="Python version" />
</a>
<a href="https://github.com/sundowndev/PhoneInfoga/releases">
<img src="https://img.shields.io/github/tag/SundownDEV/PhoneInfoga.svg?style=flat-square" alt="Latest version" />
</a>
<a href="https://github.com/sundowndev/PhoneInfoga/blob/master/LICENSE">
<img src="https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square" alt="License" />
</a>
</div>
Information gathering & OSINT reconnaissance tool for phone numbers.
<h4 align="center">Information gathering & OSINT reconnaissance tool for phone numbers</h4>
One of the most advanced tools to scan phone numbers using only free resources. The goal is to first gather basic information such as country, area, carrier and line type on any international phone numbers with a very good accuracy. Then try to determine the VoIP provider or search for footprints on search engines to try identify the owner.
<div align="center">
<sub>For the love of open source investigations. Built with ❤︎ by
<a href="https://twitter.com/sundowndev">@sundowndev</a>
</div>
### [OSINT Tutorial: Building an OSINT Reconnaissance Tool from Scratch](https://medium.com/@SundownDEV/phone-number-scanning-osint-recon-tool-6ad8f0cac27b)
<h3 align="center">
<a href="https://github.com/sundowndev/PhoneInfoga/wiki">Documentation</a> |
<a href="https://medium.com/@SundownDEV/phone-number-scanning-osint-recon-tool-6ad8f0cac27b">OSINT Tutorial</a>
</h3>
## About
PhoneInfoga is one of the most advanced tools to scan phone numbers using only free resources. The goal is to first gather basic information such as country, area, carrier and line type on any international phone numbers with a very good accuracy. Then try to determine the VoIP provider or search for footprints on search engines to try identify the owner.
## Features

File diff suppressed because one or more lines are too long

View File

@ -2,6 +2,12 @@
scriptDir=$(dirname -- "$(readlink -f -- "$BASH_SOURCE")")
python3 $scriptDir/../phoneinfoga.py -n "+86 591 2284 8571" -h
python3 $scriptDir/../phoneinfoga.py -n "+86 591 2284 8571" -s any --no-ansi
python3 $scriptDir/../phoneinfoga.py -i $scriptDir/input.txt -o $scriptDir/output_from_input.txt -s any
python3 $scriptDir/../phoneinfoga.py -n "+86 591 2284 8571" -s all -o $scriptDir/output_single.txt
echo "Test script executed."

View File

@ -4,90 +4,84 @@
/ ___/| | | | (_) | | | | __/\/ /_ | | | | _| (_) | (_| | (_| |
\/ |_| |_|\___/|_| |_|\___\____/ |_| |_|_| \___/ \__, |\__,_|
|___/
PhoneInfoga Ver. v1.1.0-rc1
PhoneInfoga Ver. v1.0.0
Coded by Sundowndev
[!] ---- Fetching informations for 8562099453217 ---- [!]
[*] Running local scan...
[-] Running local scan...
[+] International format: +856 20 99 453 217
[+] Local format: 02099453217
[+] Country code: +856
[+] Location: Laos
[+] Country found: Laos (+856)
[+] City/Area: Laos
[+] Carrier: Unitel
[+] Area: Laos
[+] Timezone: Asia/Vientiane
[*] The number is valid and possible.
[*] Scan finished.
[-] The number is valid and possible.
[-] Scan finished.
[!] ---- Fetching informations for 59172768361 ---- [!]
[*] Running local scan...
[-] Running local scan...
[+] International format: +591 72768361
[+] Local format: 072768361
[+] Country code: +591
[+] Location: Bolivia
[+] Country found: Bolivia (+591)
[+] City/Area: Bolivia
[+] Carrier: Entel
[+] Area: Bolivia
[+] Timezone: America/La_Paz
[*] The number is valid and possible.
[*] Scan finished.
[-] The number is valid and possible.
[-] Scan finished.
[!] ---- Fetching informations for 32474123456 ---- [!]
[*] Running local scan...
[-] Running local scan...
[+] International format: +32 474 12 34 56
[+] Local format: 0474123456
[+] Country code: +32
[+] Location: Belgium
[+] Country found: Belgium (+32)
[+] City/Area: Belgium
[+] Carrier: Proximus
[+] Area: Belgium
[+] Timezone: Europe/Brussels
[*] The number is valid and possible.
[*] Scan finished.
[-] The number is valid and possible.
[-] Scan finished.
[!] ---- Fetching informations for 15417543010 ---- [!]
[*] Running local scan...
[-] Running local scan...
[+] International format: +1 541-754-3010
[+] Local format: 05417543010
[+] Country code: +1
[+] Location: Corvallis, OR
[+] Country found: United States (+1)
[+] City/Area: Corvallis, OR
[+] Carrier:
[+] Area: Corvallis, OR
[+] Timezone: America/Los_Angeles
[*] The number is valid and possible.
[*] Scan finished.
[-] The number is valid and possible.
[-] Scan finished.
[!] ---- Fetching informations for 8659122848571 ---- [!]
[*] Running local scan...
[-] Running local scan...
[+] International format: +86 591 2284 8571
[+] Local format: 059122848571
[+] Country code: +86
[+] Location: Fuzhou, Fujian
[+] Country found: China (+86)
[+] City/Area: Fuzhou, Fujian
[+] Carrier:
[+] Area: Fuzhou, Fujian
[+] Timezone: Asia/Shanghai
[*] The number is valid and possible.
[*] Scan finished.
[-] The number is valid and possible.
[-] Scan finished.
[!] ---- Fetching informations for 74964819375 ---- [!]
[*] Running local scan...
[-] Running local scan...
[+] International format: +7 496 481-93-75
[+] Local format: 04964819375
[+] Country code: +7
[+] Location: Moscow
[+] Country found: Russia (+7)
[+] City/Area: Moscow
[+] Carrier:
[+] Area: Moscow
[+] Timezone: Europe/Moscow
[*] The number is valid and possible.
[*] Scan finished.
[-] The number is valid and possible.
[-] Scan finished.
[!] ---- Fetching informations for 39172768361 ---- [!]
[*] Running local scan...
[*] Scan finished.
[-] Running local scan...
[-] Scan finished.

View File

@ -4,28 +4,27 @@
/ ___/| | | | (_) | | | | __/\/ /_ | | | | _| (_) | (_| | (_| |
\/ |_| |_|\___/|_| |_|\___\____/ |_| |_|_| \___/ \__, |\__,_|
|___/
PhoneInfoga Ver. v1.1.0-rc1
PhoneInfoga Ver. v1.0.0
Coded by Sundowndev
[!] ---- Fetching informations for 8659122848571 ---- [!]
[*] Running local scan...
[-] Running local scan...
[+] International format: +86 591 2284 8571
[+] Local format: 059122848571
[+] Country code: +86
[+] Location: Fuzhou, Fujian
[+] Country found: China (+86)
[+] City/Area: Fuzhou, Fujian
[+] Carrier:
[+] Area: Fuzhou, Fujian
[+] Timezone: Asia/Shanghai
[*] The number is valid and possible.
[*] Running Numverify.com scan...
[-] The number is valid and possible.
[-] Running Numverify.com scan...
[+] Number: (+86) 059122848571
[+] Country: China (People's Republic of) (CN)
[+] Location: Fuzhou
[+] Carrier:
[+] Line type: landline
(!) This is most likely a landline, but it can still be a fixed VoIP number.
[*] Running OVH scan...
[*] Scan finished.
[-] Running OVH scan...
[-] Scan finished.

View File

@ -4,36 +4,28 @@ __version__ = 'v1.0.0'
try:
import sys
import signal
from colorama import Fore, Style
import atexit
import argparse
import random
except KeyboardInterrupt:
print('[!] Exiting.')
sys.exit()
except:
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()
def banner():
print(" ___ _ _____ __ ")
print(" / _ \ |__ ___ _ __ ___ \_ \_ __ / _| ___ __ _ __ _ ")
print(" / /_)/ '_ \ / _ \| '_ \ / _ \ / /\/ '_ \| |_ / _ \ / _` |/ _` |")
print(" / ___/| | | | (_) | | | | __/\/ /_ | | | | _| (_) | (_| | (_| |")
print(" \/ |_| |_|\___/|_| |_|\___\____/ |_| |_|_| \___/ \__, |\__,_|")
print(" |___/ ")
print(" PhoneInfoga Ver. {}".format(__version__))
print(" Coded by Sundowndev")
print("\n")
banner()
if sys.version_info[0] < 3:
print("\033[1m\033[93m(!) Please run the tool using Python 3" + Style.RESET_ALL)
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]')
@ -58,106 +50,22 @@ parser.add_argument('-u', '--update', action='store_true',
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()
def resetColors():
if not args.output:
print(Style.RESET_ALL)
# 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()
try:
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 KeyboardInterrupt:
print('\033[91m[!] Exiting.')
sys.exit()
except:
print('\033[91m[!] Missing requirements. Try running python3 -m pip install -r requirements.txt')
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:
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)
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:
print('Update failed. Try using git pull.')
sys.exit()
print('The tool was successfully updated.')
sys.exit()
scanners = ['any', 'all', 'numverify', 'ovh']
uagent = []
uagent.append("Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.0) Opera 12.14")
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 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(
@ -174,6 +82,36 @@ 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
@ -229,10 +167,11 @@ def search(req, stop):
if re.match(r"^(?:\/search\?q\=)", url) is not None:
url = 'https://google.com' + url
links.append(url)
if links is not None:
return links
except:
else:
return []
except Exception as e:
print(code_error + 'Request failed. Please retry or open an issue on https://github.com/sundowndev/PhoneInfoga.')
@ -253,7 +192,7 @@ def localScan(InputNumber):
try:
PhoneNumberObject = phonenumbers.parse(FormattedPhoneNumber, None)
except:
except Exception as e:
return False
else:
if not phonenumbers.is_valid_number(PhoneNumberObject):
@ -264,18 +203,6 @@ def localScan(InputNumber):
numberCountryCode = phonenumbers.format_number(
PhoneNumberObject, phonenumbers.PhoneNumberFormat.INTERNATIONAL).split(' ')[0]
try:
countries = json.load(open('data/CountryCodes.json'))
for country in countries:
if (country['dial_code'].replace(' ', '') == numberCountryCode):
print(code_info + 'Country code found: {} ({})'.format(country['name'],country['code']))
numberCountry = country['code']
break
except:
print(code_error + 'Unable to find country code.')
print(numberCountry)
localNumber = phonenumbers.format_number(
PhoneNumberObject, phonenumbers.PhoneNumberFormat.E164).replace(numberCountryCode, '')
internationalNumber = phonenumbers.format_number(
@ -283,11 +210,12 @@ def localScan(InputNumber):
print(code_result + 'International format: {}'.format(internationalNumber))
print(code_result + 'Local format: 0{}'.format(localNumber))
print(code_result + 'Country code: {}'.format(numberCountryCode))
print(code_result + 'Location: {}'.format(geocoder.description_for_number(PhoneNumberObject, "en")))
print(code_result + 'Country found: {} ({})'.format(
geocoder.country_name_for_number(PhoneNumberObject, "en"), numberCountryCode))
print(code_result + 'City/Area: {}'.format(
geocoder.description_for_number(PhoneNumberObject, "en")))
print(code_result +
'Carrier: {}'.format(carrier.name_for_number(PhoneNumberObject, 'en')))
print(code_result + 'Area: {}'.format(geocoder.description_for_number(PhoneNumberObject, 'en')))
for timezoneResult in timezone.time_zones_for_number(PhoneNumberObject):
print(code_result + 'Timezone: {}'.format(timezoneResult))
@ -305,9 +233,14 @@ def numverifyScan():
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']
@ -334,8 +267,8 @@ def numverifyScan():
"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:
print(code_error + 'Numverify is not available')
except Exception as e:
print(code_error + 'Numverify.com is not available')
return -1
if response.content == "Unauthorized" or response.status_code != 200:
@ -383,7 +316,7 @@ def ovhScan():
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:
except Exception as e:
print(code_error + 'OVH API is unreachable. Maybe retry later.')
return -1
@ -431,6 +364,7 @@ def osintIndividualScan():
print(
(code_info + "Searching for footprints on {}...".format(dork['site'])))
for result in search(dorkRequest, stop=dork['stop']):
if result:
print((code_result + "URL: " + result))
@ -474,6 +408,7 @@ def osintSocialMediaScan():
print(
(code_info + "Searching for footprints on {}...".format(dork['site'])))
for result in search(dorkRequest, stop=dork['stop']):
if result:
print((code_result + "URL: " + result))
@ -489,6 +424,7 @@ def osintDisposableNumScan():
print(
(code_info + "Searching for footprints on {}...".format(dork['site'])))
for result in search(dorkRequest, stop=dork['stop']):
if result:
print((code_result + "Result found: {}".format(dork['site'])))
@ -496,7 +432,7 @@ def osintDisposableNumScan():
askForExit()
def osintScan():
def osintScan(rerun=False):
global number
global localNumber
global internationalNumber
@ -508,6 +444,7 @@ def osintScan():
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(
@ -516,7 +453,7 @@ def osintScan():
askingCustomPayload = input(
code_info + 'Would you like to use an additional format for this number ? (y/N) ')
if askingCustomPayload == 'y' or askingCustomPayload == 'yes':
if rerun or askingCustomPayload == 'y' or askingCustomPayload == 'yes':
customFormatting = input(code_info + 'Custom format: ')
print((code_info + '---- Web pages footprints ----'))
@ -568,7 +505,7 @@ def osintScan():
print(
(code_result + "Found a temporary number provider: tempophone.com"))
askForExit()
except:
except Exception as e:
print((code_error + "Unable to reach tempophone.com API. Skipping."))
osintDisposableNumScan()
@ -590,7 +527,7 @@ def osintScan():
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()
osintScan(True)
else:
return -1
@ -634,19 +571,83 @@ def scanNumber(InputNumber):
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:
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
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:
@ -655,7 +656,7 @@ try:
sys.exit()
sys.stdout = args.output
banner()
banner() # Output banner again in the file
# Verify scanner option
if not args.scanner in scanners:
@ -667,9 +668,19 @@ try:
elif args.input:
for line in args.input.readlines():
scanNumber(line)
else:
parser.print_help()
sys.exit()
if args.output:
args.output.close()
except KeyboardInterrupt:
print(("\n" + code_error + "Scan interrupted. Good bye!"))
def signal_handler(signal, frame):
print('\n[-] You pressed Ctrl+C! Exiting.')
sys.exit()
if __name__ == '__main__':
signal.signal(signal.SIGINT, signal_handler)
main()