Compare commits

..

No commits in common. "master" and "v1.0.0-rc1" have entirely different histories.

13 changed files with 317 additions and 551 deletions

View File

@ -1,5 +0,0 @@
1. Please DO NOT open pull request on the **master** branch. Use the **develop** branch instead!
2. Explain your changes as much as possible
3. If possible, use a well understanding title and use labels ! (e.g: "[Bug] Google Captcha", "[Feature] Footprinting on Bing")
Thank you for contributing ! :tada:

View File

@ -1,7 +0,0 @@
language: python
python:
- "3.6"
- "3.7-dev"
install:
- pip install -r requirements.txt
script: bash ./examples/generate.sh

126
README.md
View File

@ -1,35 +1,11 @@
<h1 align="center">PhoneInfoga</h1> # PhoneInfoga
<div align="center"> ![](https://img.shields.io/badge/python-3.x-blue.svg)
<a href="https://travis-ci.org/sundowndev/PhoneInfoga"> ![](https://img.shields.io/badge/license-MIT-blue.svg)
<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>
<h4 align="center">Information gathering & OSINT reconnaissance tool for phone numbers</h4> Information gathering & OSINT reconnaissance tool for phone numbers.
<div align="center"> 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.
<sub>For the love of open source investigations. Built with ❤︎ by
<a href="https://twitter.com/sundowndev">@sundowndev</a>
</div>
<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 ## Features
@ -45,18 +21,29 @@ PhoneInfoga is one of the most advanced tools to scan phone numbers using only f
The tool only accepts E164 and International formats as input. The tool only accepts E164 and International formats as input.
- E164: +3396360XXXX
- International: +33 9 63 60 XX XX
- National: 09 63 60 XX XX
- RFC3966: tel:+33-9-63-60-XX-XX
- Out-of-country format from US: 011 33 9 63 60 XX XX
## Available scanners
Use `any` to disable this feature. Default value: `all`
- numverify
- ovh
## Installation ## Installation
```bash ```bash
git clone https://github.com/sundowndev/PhoneInfoga git clone https://github.com/sundowndev/PhoneInfoga
cd PhoneInfoga/ cd ./PhoneInfoga
python3 -m pip install -r requirements.txt pip3 install -r requirements.txt
``` ```
## Usage ## Usage
### [The full usage documentation has been moved to the wiki](https://github.com/sundowndev/PhoneInfoga/wiki)
``` ```
usage: phoneinfoga.py -n <number> [options] usage: phoneinfoga.py -n <number> [options]
@ -78,6 +65,79 @@ optional arguments:
-u, --update Update the tool & databases -u, --update Update the tool & databases
``` ```
Example (quotes are optional, use it when typing special formats) :
```
python phoneinfoga.py -n "(+42)837544833"
```
Check for a number range on OVH :
```
python phoneinfoga.py -n +42837544833 -s ovh
```
Check several numbers at once :
```
python ./phoneinfoga.py -i numbers.txt -o results.txt
```
**Note: `--osint` is not compatible with `--output` option.**
Use all scanners and run OSINT reconnaissance :
```
python phoneinfoga.py -n +42837544833 -s all --osint
```
## Formatting
E.164 formatting for phone numbers entails the following:
- A + (plus) sign
- International Country Calling code
- Local Area code
- Local Phone number
For example, heres a US-based number in standard local formatting: (415) 555-2671
![](https://i.imgur.com/0e2SMdL.png)
Heres the same phone number in E.164 formatting: +14155552671
![](https://i.imgur.com/KfrvacR.png)
In the UK, and many other countries internationally, local dialing may require the addition of a '0' in front of the subscriber number. With E.164 formatting, this '0' must usually be removed.
For example, heres a UK-based number in standard local formatting: 020 7183 8750
Heres the same phone number in E.164 formatting: +442071838750
## Dealing with Google captcha
PhoneInfo use a workaround to handle Google bot detection. When running OSINT scan, you will usually be blacklisted very easily by Google, which will ask the tool to complete a captcha.
>When you search on Google using custom requests (Google Dorks), you get very easily blacklisted. So Google shows up a page where you have to complete a captcha to continue. As soon as the captcha is completed, Google create a cookie named "GOOGLE_ABUSE_EXEMPTION" which is used to whitelist your browser and IP address for some minutes. This temporary whitelist is enough to let you gather a lot of information from many sources. So I decided to add a simple user manipulation to bypass this bot detection. [...] So I'll just try make requests and wait until I get a 503 error, which means I got blacklisted. Then I ask the user to follow an URL to manually complete the captcha and copy the whitelist token to paste it in the CLI. The tool is now able to continue to scan!
![](https://i.imgur.com/qbFZa1m.png)
### Steps
- Follow the URL
- Complete the captcha if needed
- Open the dev tool (F12 on most browsers)
- Go to **Storage**, then **Cookies**
- Copy the value of the *GOOGLE_ABUSE_EXEMPTION* cookie and paste it in the CLI
**Note: sometimes you'll need to refresh the page to get the cookie.**
![](https://i.imgur.com/KkE1EM5.png)
## Custom formatting
Sometimes the phone number has footprints but is used with a different formatting. This is a problem because for example if we search for "+15417543010", we'll not find web pages that write it that way : "(541) 7543010". So the tool use a (optional) custom formatting given by the user to find further and more accurate results.
## License ## License
This tool is licensed under the GNU General Public License v3.0. This tool is licensed under the GNU General Public License v3.0.

View File

@ -1,13 +0,0 @@
#!/bin/bash
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

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

View File

@ -1,30 +0,0 @@
___ _ _____ __
/ _ \ |__ ___ _ __ ___ \_ \_ __ / _| ___ __ _ __ _
/ /_)/ '_ \ / _ \| '_ \ / _ \ / /\/ '_ \| |_ / _ \ / _` |/ _` |
/ ___/| | | | (_) | | | | __/\/ /_ | | | | _| (_) | (_| | (_| |
\/ |_| |_|\___/|_| |_|\___\____/ |_| |_|_| \___/ \__, |\__,_|
|___/
PhoneInfoga Ver. v1.0.0
Coded by Sundowndev
[!] ---- Fetching informations for 8659122848571 ---- [!]
[-] Running local scan...
[+] International format: +86 591 2284 8571
[+] Local format: 059122848571
[+] Country found: China (+86)
[+] City/Area: Fuzhou, Fujian
[+] Carrier:
[+] Timezone: Asia/Shanghai
[-] 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.

View File

@ -98,10 +98,5 @@
"site": "receive-sms-online.com", "site": "receive-sms-online.com",
"request": "site:\"receive-sms-online.com\" intext:\"$n\"", "request": "site:\"receive-sms-online.com\" intext:\"$n\"",
"stop": 1 "stop": 1
},
{
"site": "smslive.co",
"request": "site:\"smslive.co\" intext:\"$n\"",
"stop": 1
} }
] ]

View File

@ -1,13 +1,13 @@
[ [
{ {
"site": "numinfo.net", "site": "numinfo.net",
"request": "site:\"numinfo.net\" intext:\"$i\" | intext:\"$n\" | intext:\"$l\"", "request": "site:\"numinfo.net\" intext:\"$n\" | intext:\"$i\"",
"dialCode": null, "dialCode": null,
"stop": 2 "stop": 2
}, },
{ {
"site": "sync.me", "site": "sync.me",
"request": "site:\"sync.me\" intext:\"$i\" | intext:\"$n\" | intext:\"$l\"", "request": "site:\"sync.me\" intext:\"$n\" | intext:\"$i\"",
"dialCode": null, "dialCode": null,
"stop": 1 "stop": 1
}, },
@ -19,19 +19,13 @@
}, },
{ {
"site": "pastebin.com", "site": "pastebin.com",
"request": "site:\"pastebin.com\" intext:\"$i\" | intext:\"$n\" | intext:\"$l\"", "request": "site:\"pastebin.com\" intext:\"$n\" | intext:\"$i\"",
"dialCode": null, "dialCode": null,
"stop": 5 "stop": 5
}, },
{ {
"site": "whycall.me", "site": "whycall.me",
"request": "site:\"whycall.me\" intext:\"$i\" | intext:\"$n\" | intext:\"$l\"", "request": "site:\"whycall.me\" intext:\"$n\" | intext:\"$l\"",
"dialCode": null,
"stop": 1
},
{
"site": "locatefamily.com",
"request": "site:locatefamily.com intext:\"$i\" | intext:\"$n\" | intext:\"$l\"",
"dialCode": null, "dialCode": null,
"stop": 1 "stop": 1
} }

View File

@ -1,17 +1,12 @@
[ [
{ {
"title": "reputation report on whosenumber.info", "title": "reputation report on whosenumber.info",
"request": "site:whosenumber.info intext:\"$n\" intitle:\"who called\"", "request": "site:\"whosenumber.info\" intext:\"$n\" intitle:\"who called\"",
"stop": 1 "stop": 1
}, },
{ {
"title": "phone fraud footprints", "title": "phone fraud footprints",
"request": "intitle:\"Phone Fraud\" intext:\"$i\" | intext:\"$n\" | intext:\"$l\"", "request": "intitle:\"Phone Fraud\" intext:\"$n\" | intext:\"$i\"",
"stop": 5 "stop": 5
},
{
"title": "reputation report on findwhocallsme.com",
"request": "site:findwhocallsme.com intext:\"$n\" | intext:\"$i\"",
"stop": 1
} }
] ]

View File

@ -1,22 +1,22 @@
[ [
{ {
"site": "facebook.com", "site": "facebook.com",
"request": "site:\"facebook.com\" intext:\"$i\" | intext:\"$n\" | intext:\"$l\"", "request": "site:\"facebook.com\" intext:\"$i\" | intext:\"$n\"",
"stop": 5 "stop": 5
}, },
{ {
"site": "twitter.com", "site": "twitter.com",
"request": "site:\"twitter.com\" intext:\"$i\" | intext:\"$n\" | intext:\"$l\"", "request": "site:\"twitter.com\" intext:\"$i\" | intext:\"$n\"",
"stop": 5 "stop": 5
}, },
{ {
"site": "linkedin.com", "site": "linkedin.com",
"request": "site:\"linkedin.com\" intext:\"$i\" | intext:\"$n\" | intext:\"$l\"", "request": "site:\"linkedin.com\" intext:\"$i\" | intext:\"$n\"",
"stop": 5 "stop": 5
}, },
{ {
"site": "instagram.com", "site": "instagram.com",
"request": "site:\"instagram.com\" intext:\"$i\" | intext:\"$n\" | intext:\"$l\"", "request": "site:\"instagram.com\" intext:\"$i\" | intext:\"$n\"",
"stop": 5 "stop": 5
} }
] ]

View File

@ -1,32 +1,31 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
__version__ = 'v1.0.2' __version__ = '1.0.0-rc1'
try: def banner():
import sys print(" ___ _ _____ __ ")
import signal print(" / _ \ |__ ___ _ __ ___ \_ \_ __ / _| ___ __ _ __ _ ")
from colorama import Fore, Style print(" / /_)/ '_ \ / _ \| '_ \ / _ \ / /\/ '_ \| |_ / _ \ / _` |/ _` |")
import atexit print(" / ___/| | | | (_) | | | | __/\/ /_ | | | | _| (_) | (_| | (_| |")
import argparse print(" \/ |_| |_|\___/|_| |_|\___\____/ |_| |_|_| \___/ \__, |\__,_|")
import random print(" |___/ ")
import time print(" PhoneInfoga Ver. {}".format(__version__))
import hashlib print(" Coded by Sundowndev")
import json print("\n")
import re
import requests print("\n \033[92m")
import urllib3 banner()
from bs4 import BeautifulSoup
import html5lib import sys
import phonenumbers import argparse
from phonenumbers import carrier import random
from phonenumbers import geocoder
from phonenumbers import timezone if sys.version_info[0] < 3:
from urllib.parse import urlencode print("\033[1m\033[93m(!) Please run the tool using Python 3")
except Exception as e:
print('[!] Missing requirements. Try running python3 -m pip install -r requirements.txt')
sys.exit() sys.exit()
parser = argparse.ArgumentParser(description="Advanced information gathering tool for phone numbers (https://github.com/sundowndev/PhoneInfoga) version {}".format(__version__), 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]') usage='%(prog)s -n <number> [options]')
parser.add_argument('-n', '--number', metavar='number', type=str, parser.add_argument('-n', '--number', metavar='number', type=str,
@ -47,79 +46,97 @@ parser.add_argument('--osint', action='store_true',
parser.add_argument('-u', '--update', action='store_true', parser.add_argument('-u', '--update', action='store_true',
help='Update the project') 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() args = parser.parse_args()
uagent = [] # If any param is passed, execute help command
uagent.append( if not len(sys.argv) > 1:
"Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.0) Opera 12.14") parser.print_help()
uagent.append( sys.exit()
"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 try:
localNumber = '' # Local number format; e.g: 06 12 34 56 78 import time
internationalNumber = '' # International number format; e.g: +33 6 12 34 56 78 import hashlib
numberCountryCode = '' # Dial code; e.g: 33 import json
numberCountry = '' # Country; e.g: fr import re
import requests
from bs4 import BeautifulSoup
import html5lib
import phonenumbers
from phonenumbers import carrier
from phonenumbers import geocoder
from phonenumbers import timezone
except KeyboardInterrupt:
print('\033[91m[!] Exiting.')
sys.exit()
except:
print('\033[91m[!] Missing requirements. Try running pip install -r requirements.txt')
sys.exit()
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 (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
localNumber = '' # Local number format
internationalNumber = '' # International numberformat
numberCountryCode = '' # Dial code; e.g:"+33"
numberCountry = '' # Country; e.g:France
googleAbuseToken = '' googleAbuseToken = ''
customFormatting = '' 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): def search(req, stop):
global googleAbuseToken global googleAbuseToken
global uagent global uagent
chosenUserAgent = random.choice(uagent) chosenUserAgent = random.choice(uagent)
reqSession = requests.Session() s = requests.Session()
headers = { headers = {
'User-Agent': chosenUserAgent, 'User-Agent': chosenUserAgent,
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8', 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
@ -128,26 +145,21 @@ def search(req, stop):
'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.7', 'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.7',
'Keep-Alive': '115', 'Keep-Alive': '115',
'Connection': 'keep-alive', '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:;' '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: try:
REQ = urlencode({'q': req}) URL = 'https://www.google.com/search?tbs=li:1&q={}&amp;gws_rd=ssl'.format(req)
URL = 'https://www.google.com/search?tbs=li:1&{}&amp;gws_rd=ssl&amp;gl=us '.format( r = s.get(URL + googleAbuseToken, headers=headers)
REQ)
r = reqSession.get(URL + googleAbuseToken, headers=headers)
while r.status_code != 200: while r.status_code == 503:
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(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 + print('\n' + code_info + 'Need help ? Read https://github.com/sundowndev/PhoneInfoga#dealing-with-google-captcha')
'Need help ? Read https://github.com/sundowndev/PhoneInfoga/wiki')
token = input('\nGOOGLE_ABUSE_EXEMPTION=') token = input('\nGOOGLE_ABUSE_EXEMPTION=')
googleAbuseToken = '&google_abuse=' + token googleAbuseToken = '&google_abuse=' + token
r = reqSession.get(URL + googleAbuseToken, headers=headers) r = s.get(URL + googleAbuseToken, headers=headers)
soup = BeautifulSoup(r.text, 'html5lib')
soup = BeautifulSoup(r.content, 'html.parser')
results = soup.find("div", id="search").find_all("div", class_="g") results = soup.find("div", id="search").find_all("div", class_="g")
links = [] links = []
@ -168,20 +180,15 @@ def search(req, stop):
if re.match(r"^(?:\/search\?q\=)", url) is not None: if re.match(r"^(?:\/search\?q\=)", url) is not None:
url = 'https://google.com' + url url = 'https://google.com' + url
if url is not None: links.append(url)
links.append(url)
return links return links
except Exception as e: except:
print(code_error + 'Request failed. Please retry or open an issue on https://github.com/sundowndev/PhoneInfoga.') print(code_error + 'Request failed. Please retry or open an issue on GitHub.')
print(e)
return []
def formatNumber(InputNumber): def formatNumber(InputNumber):
return re.sub("(?:\+)?(?:[^[0-9]*)", "", InputNumber) return re.sub("(?:\+)?(?:[^[0-9]*)", "", InputNumber)
def localScan(InputNumber): def localScan(InputNumber):
global number global number
global localNumber global localNumber
@ -195,33 +202,27 @@ def localScan(InputNumber):
try: try:
PhoneNumberObject = phonenumbers.parse(FormattedPhoneNumber, None) PhoneNumberObject = phonenumbers.parse(FormattedPhoneNumber, None)
except Exception as e: except:
return False return False
else: else:
if not phonenumbers.is_valid_number(PhoneNumberObject): if not phonenumbers.is_valid_number(PhoneNumberObject):
return False return False
number = phonenumbers.format_number( number = phonenumbers.format_number(PhoneNumberObject, phonenumbers.PhoneNumberFormat.E164).replace('+', '')
PhoneNumberObject, phonenumbers.PhoneNumberFormat.E164).replace('+', '') numberCountryCode = phonenumbers.format_number(PhoneNumberObject, phonenumbers.PhoneNumberFormat.INTERNATIONAL).split(' ')[0]
numberCountryCode = phonenumbers.format_number(
PhoneNumberObject, phonenumbers.PhoneNumberFormat.INTERNATIONAL).split(' ')[0]
numberCountry = phonenumbers.region_code_for_country_code(
int(numberCountryCode))
localNumber = phonenumbers.format_number( countryRequest = json.loads(requests.request('GET', 'https://restcountries.eu/rest/v2/callingcode/{}'.format(numberCountryCode.replace('+', ''))).content)
PhoneNumberObject, phonenumbers.PhoneNumberFormat.E164).replace(numberCountryCode, '0') numberCountry = countryRequest[0]['alpha2Code']
internationalNumber = phonenumbers.format_number(
PhoneNumberObject, phonenumbers.PhoneNumberFormat.INTERNATIONAL)
country = geocoder.country_name_for_number(PhoneNumberObject, "en") localNumber = phonenumbers.format_number(PhoneNumberObject, phonenumbers.PhoneNumberFormat.E164).replace(numberCountryCode, '')
location = geocoder.description_for_number(PhoneNumberObject, "en") internationalNumber = phonenumbers.format_number(PhoneNumberObject, phonenumbers.PhoneNumberFormat.INTERNATIONAL)
carrierName = carrier.name_for_number(PhoneNumberObject, 'en')
print(code_result + 'International format: {}'.format(internationalNumber)) print(code_result + 'International format: {}'.format(internationalNumber))
print(code_result + 'Local format: 0{}'.format(localNumber)) print(code_result + 'Local format: 0{}'.format(localNumber))
print(code_result + 'Country found: {} ({})'.format(country, numberCountryCode)) print(code_result + 'Country code: {}'.format(numberCountryCode))
print(code_result + 'City/Area: {}'.format(location)) print(code_result + 'Location: {}'.format(geocoder.description_for_number(PhoneNumberObject, "en")))
print(code_result + 'Carrier: {}'.format(carrierName)) 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): for timezoneResult in timezone.time_zones_for_number(PhoneNumberObject):
print(code_result + 'Timezone: {}'.format(timezoneResult)) print(code_result + 'Timezone: {}'.format(timezoneResult))
@ -230,7 +231,6 @@ def localScan(InputNumber):
else: else:
print(code_warning + 'The number is valid but might not be possible.') print(code_warning + 'The number is valid but might not be possible.')
def numverifyScan(): def numverifyScan():
global number global number
@ -239,14 +239,9 @@ def numverifyScan():
print(code_info + 'Running Numverify.com scan...') print(code_info + 'Running Numverify.com scan...')
try: requestSecret = ''
requestSecret = '' resp = requests.get('https://numverify.com/')
resp = requests.get('https://numverify.com/') soup = BeautifulSoup(resp.text, "html5lib")
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"): for tag in soup.find_all("input", type="hidden"):
if tag['name'] == "scl_request_secret": if tag['name'] == "scl_request_secret":
requestSecret = tag['value'] requestSecret = tag['value']
@ -255,43 +250,36 @@ def numverifyScan():
apiKey = hashlib.md5((number + requestSecret).encode('utf-8')).hexdigest() apiKey = hashlib.md5((number + requestSecret).encode('utf-8')).hexdigest()
headers = { headers = {
'Host': 'numverify.com', 'host': "numverify.com",
'User-Agent': 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:64.0) Gecko/20100101 Firefox/64.0', 'connection': "keep-alive",
'Accept': 'application/json, text/javascript, */*; q=0.01', 'content-length': "49",
'Accept-Language': 'fr,fr-FR;q=0.8,en-US;q=0.5,en;q=0.3', 'accept': "application/json",
'Accept-Encoding': 'gzip, deflate, br', 'origin': "https://numverify.com",
'Referer': 'https://numverify.com/', 'x-requested-with': "XMLHttpRequest",
'X-Requested-With': 'XMLHttpRequest', 'user-agent': "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36",
'DNT': '1', 'content-type': "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW",
'Connection': 'keep-alive', 'referer': "https://numverify.com/",
'Pragma': 'no-cache', 'accept-encoding': "gzip, deflate, br",
'Cache-Control': 'no-cache' 'accept-language': "en-US,en;q=0.9,fr;q=0.8,la;q=0.7,es;q=0.6,zh-CN;q=0.5,zh;q=0.4",
'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)
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: 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).")) print((code_error + "An error occured while calling the API (bad request or wrong api key)."))
return -1 return -1
data = json.loads(response.content)
if data["valid"] == False: if data["valid"] == False:
print((code_error + "Error: Please specify a valid phone number. Example: +6464806649")) print((code_error + "Error: Please specify a valid phone number. Example: +6464806649"))
sys.exit() sys.exit()
InternationalNumber = '({}){}'.format( InternationalNumber = '({}){}'.format(data["country_prefix"], data["local_format"])
data["country_prefix"], data["local_format"])
print((code_result + print((code_result + "Number: ({}) {}").format(data["country_prefix"],data["local_format"]))
"Number: ({}) {}").format(data["country_prefix"], data["local_format"])) print((code_result + "Country: {} ({})").format(data["country_name"],data["country_code"]))
print((code_result +
"Country: {} ({})").format(data["country_name"], data["country_code"]))
print((code_result + "Location: {}").format(data["location"])) print((code_result + "Location: {}").format(data["location"]))
print((code_result + "Carrier: {}").format(data["carrier"])) print((code_result + "Carrier: {}").format(data["carrier"]))
print((code_result + "Line type: {}").format(data["line_type"])) print((code_result + "Line type: {}").format(data["line_type"]))
@ -301,7 +289,6 @@ def numverifyScan():
elif data["line_type"] == 'mobile': elif data["line_type"] == 'mobile':
print((code_warning + "This is most likely a mobile number, but it can still be a VoIP number.")) print((code_warning + "This is most likely a mobile number, but it can still be a VoIP number."))
def ovhScan(): def ovhScan():
global localNumber global localNumber
global numberCountry global numberCountry
@ -311,20 +298,16 @@ def ovhScan():
print(code_info + 'Running OVH scan...') print(code_info + 'Running OVH scan...')
querystring = {"country": numberCountry.lower()} querystring = { "country": numberCountry.lower() }
headers = { headers = {
'accept': "application/json", 'accept': "application/json",
'cache-control': "no-cache" 'cache-control': "no-cache"
} }
try: response = requests.request("GET", "https://api.ovh.com/1.0/telephony/number/detailedZones", data="", headers=headers, params=querystring)
response = requests.request(
"GET", "https://api.ovh.com/1.0/telephony/number/detailedZones", data="", headers=headers, params=querystring) data = json.loads(response.content)
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): if isinstance(data, list):
askedNumber = "0" + localNumber.replace(localNumber[-4:], 'xxxx') askedNumber = "0" + localNumber.replace(localNumber[-4:], 'xxxx')
@ -332,14 +315,11 @@ def ovhScan():
for voip_number in data: for voip_number in data:
if voip_number['number'] == askedNumber: if voip_number['number'] == askedNumber:
print((code_info + "1 result found in OVH database")) print((code_info + "1 result found in OVH database"))
print( print((code_result + "Number range: {}".format(voip_number['number'])))
(code_result + "Number range: {}".format(voip_number['number'])))
print((code_result + "City: {}".format(voip_number['city']))) print((code_result + "City: {}".format(voip_number['city'])))
print((code_result + "Zip code: {}".format( print((code_result + "Zip code: {}".format(voip_number['zipCode'] if voip_number['zipCode'] is not None else '')))
voip_number['zipCode'] if voip_number['zipCode'] is not None else '')))
askForExit() askForExit()
def replaceVariables(string): def replaceVariables(string):
global number global number
global internationalNumber global internationalNumber
@ -351,7 +331,6 @@ def replaceVariables(string):
return string return string
def osintIndividualScan(): def osintIndividualScan():
global number global number
global internationalNumber global internationalNumber
@ -363,20 +342,17 @@ def osintIndividualScan():
for dork in dorks: for dork in dorks:
if dork['dialCode'] is None or dork['dialCode'] == numberCountryCode: if dork['dialCode'] is None or dork['dialCode'] == numberCountryCode:
if customFormatting: if customFormatting:
dorkRequest = replaceVariables( dorkRequest = replaceVariables(dork['request']) + ' | intext:"{}"'.format(customFormatting)
dork['request']) + ' | intext:"{}"'.format(customFormatting)
else: else:
dorkRequest = replaceVariables(dork['request']) dorkRequest = replaceVariables(dork['request'])
print( print((code_info + "Searching for footprints on {}...".format(dork['site'])))
(code_info + "Searching for footprints on {}...".format(dork['site'])))
for result in search(dorkRequest, stop=dork['stop']): for result in search(dorkRequest, stop=dork['stop']):
print((code_result + "URL: " + result)) if result:
print((code_result + "URL: " + result))
else: else:
return -1 return -1
def osintReputationScan(): def osintReputationScan():
global number global number
global internationalNumber global internationalNumber
@ -386,15 +362,14 @@ def osintReputationScan():
for dork in dorks: for dork in dorks:
if customFormatting: if customFormatting:
dorkRequest = replaceVariables( dorkRequest = replaceVariables(dork['request']) + ' | intext:"{}"'.format(customFormatting)
dork['request']) + ' | intext:"{}"'.format(customFormatting)
else: else:
dorkRequest = replaceVariables(dork['request']) dorkRequest = replaceVariables(dork['request'])
print((code_info + "Searching for {}...".format(dork['title']))) print((code_info + "Searching for {}...".format(dork['title'])))
for result in search(dorkRequest, stop=dork['stop']): for result in search(dorkRequest, stop=dork['stop']):
print((code_result + "URL: " + result)) if result:
print((code_result + "URL: " + result))
def osintSocialMediaScan(): def osintSocialMediaScan():
global number global number
@ -405,17 +380,14 @@ def osintSocialMediaScan():
for dork in dorks: for dork in dorks:
if customFormatting: if customFormatting:
dorkRequest = replaceVariables( dorkRequest = replaceVariables(dork['request']) + ' | intext:"{}"'.format(customFormatting)
dork['request']) + ' | intext:"{}"'.format(customFormatting)
else: else:
dorkRequest = replaceVariables(dork['request']) dorkRequest = replaceVariables(dork['request'])
print( print((code_info + "Searching for footprints on {}...".format(dork['site'])))
(code_info + "Searching for footprints on {}...".format(dork['site'])))
for result in search(dorkRequest, stop=dork['stop']): for result in search(dorkRequest, stop=dork['stop']):
print((code_result + "URL: " + result)) if result:
print((code_result + "URL: " + result))
def osintDisposableNumScan(): def osintDisposableNumScan():
global number global number
@ -425,20 +397,19 @@ def osintDisposableNumScan():
for dork in dorks: for dork in dorks:
dorkRequest = replaceVariables(dork['request']) dorkRequest = replaceVariables(dork['request'])
print( print((code_info + "Searching for footprints on {}...".format(dork['site'])))
(code_info + "Searching for footprints on {}...".format(dork['site'])))
for result in search(dorkRequest, stop=dork['stop']): for result in search(dorkRequest, stop=dork['stop']):
print((code_result + "Result found: {}".format(dork['site']))) if result:
print((code_result + "URL: " + result)) print((code_result + "Result found: {}".format(dork['site'])))
askForExit() print((code_result + "URL: " + result))
askForExit()
def osintScan():
def osintScan(rerun=False):
global number global number
global localNumber global localNumber
global internationalNumber global internationalNumber
global numberCountryCode global numberCountryCode
global numberCountry
global customFormatting global customFormatting
if not args.osint: if not args.osint:
@ -446,68 +417,55 @@ def osintScan(rerun=False):
print(code_info + 'Running OSINT footprint reconnaissance...') print(code_info + 'Running OSINT footprint reconnaissance...')
if not rerun: # Whitepages
# Whitepages print((code_info + "Generating scan URL on 411.com..."))
print((code_info + "Generating scan URL on 411.com...")) print(code_result + "Scan URL: https://www.411.com/phone/{}".format(internationalNumber.replace('+', '').replace(' ', '-')))
print(code_result + "Scan URL: https://www.411.com/phone/{}".format(
internationalNumber.replace('+', '').replace(' ', '-')))
askingCustomPayload = input( askingCustomPayload = input(code_info + 'Would you like to use an additional format for this number ? (y/N) ')
code_info + 'Would you like to use an additional format for this number ? (y/N) ')
if rerun or askingCustomPayload == 'y' or askingCustomPayload == 'yes': if askingCustomPayload == 'y' or askingCustomPayload == 'yes':
customFormatting = input(code_info + 'Custom format: ') customFormatting = input(code_info + 'Custom format: ')
print((code_info + '---- Web pages footprints ----')) print((code_info + '---- Web pages footprints ----'))
print((code_info + "Searching for footprints on web pages... (limit=10)")) print((code_info + "Searching for footprints on web pages... (limit=5)"))
if customFormatting: if customFormatting:
req = '{} | intext:"{}" | intext:"{}" | intext:"{}"'.format( req = '{} | intext:"{}" | intext:"{}" | intext:"{}"'.format(number,number,internationalNumber,customFormatting)
number, number, internationalNumber, customFormatting)
else: else:
req = '{} | intext:"{}" | intext:"{}"'.format( req = '{} | intext:"{}" | intext:"{}"'.format(number,number,internationalNumber)
number, number, internationalNumber) for result in search(req, stop=5):
if result:
for result in search(req, stop=10): print((code_result + "Result found: " + result))
print((code_result + "Result found: " + result))
# Documents # Documents
print((code_info + "Searching for documents... (limit=10)")) print((code_info + "Searching for documents... (limit=10)"))
if customFormatting: 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( req = 'intext:"{}" | intext:"{}" | intext:"{}" ext:doc | ext:docx | ext:odt | ext:pdf | ext:rtf | ext:sxw | ext:psw | ext:ppt | ext:pptx | ext:pps | ext:csv | ext:txt'.format(number,internationalNumber,customFormatting)
customFormatting)
else: 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( req = 'intext:"{}" | intext:"{}" ext:doc | ext:docx | ext:odt | ext:pdf | ext:rtf | ext:sxw | ext:psw | ext:ppt | ext:pptx | ext:pps | ext:csv | ext:txt'.format(number,internationalNumber)
internationalNumber, localNumber) for result in search('intext:"{}" | intext:"{}" ext:doc | ext:docx | ext:odt | ext:pdf | ext:rtf | ext:sxw | ext:psw | ext:ppt | ext:pptx | ext:pps | ext:csv | ext:txt'.format(number,internationalNumber), stop=10):
for result in search(req, stop=10): if result:
print((code_result + "Result found: " + result)) print((code_result + "Result found: " + result))
print((code_info + '---- Reputation footprints ----')) print((code_info + '---- Reputation footprints ----'))
osintReputationScan() osintReputationScan()
print((code_info + "Generating URL on scamcallfighters.com...")) print((code_info + "Generating URL on scamcallfighters.com..."))
print(code_result + print(code_result + 'http://www.scamcallfighters.com/search-phone-{}.html'.format(number))
'http://www.scamcallfighters.com/search-phone-{}.html'.format(number))
tmpNumAsk = input( tmpNumAsk = input(code_info + "Would you like to search for temporary number providers footprints ? (Y/n) ")
code_info + "Would you like to search for temporary number providers footprints ? (Y/n) ")
if tmpNumAsk.lower() != 'n' and tmpNumAsk.lower() != 'no': if tmpNumAsk.lower() != 'n' and tmpNumAsk.lower() != 'no':
print((code_info + '---- Temporary number providers footprints ----')) print((code_info + '---- Temporary number providers footprints ----'))
try: print((code_info + "Searching for phone number on tempophone.com..."))
print((code_info + "Searching for phone number on tempophone.com...")) response = requests.request("GET", "https://tempophone.com/api/v1/phones")
response = requests.request( data = json.loads(response.content)
"GET", "https://tempophone.com/api/v1/phones") for voip_number in data['objects']:
data = json.loads(response.content.decode('utf-8')) if voip_number['phone'] == formatNumber(number):
for voip_number in data['objects']: print((code_result + "Found a temporary number provider: tempophone.com"))
if voip_number['phone'] == formatNumber(number): askForExit()
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() osintDisposableNumScan()
@ -519,20 +477,10 @@ def osintScan(rerun=False):
if numberCountryCode == '+1': if numberCountryCode == '+1':
print((code_info + "Generating URL on True People... ")) print((code_info + "Generating URL on True People... "))
print(code_result + 'https://www.truepeoplesearch.com/results?phoneno={}'.format( print(code_result + 'https://www.truepeoplesearch.com/results?phoneno={}'.format(internationalNumber.replace(' ', '')))
internationalNumber.replace(' ', '')))
osintIndividualScan() 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(): def askForExit():
if not args.output: if not args.output:
user_input = input(code_info + "Continue scanning ? (y/N) ") user_input = input(code_info + "Continue scanning ? (y/N) ")
@ -543,19 +491,17 @@ def askForExit():
print(code_info + "Good bye!") print(code_info + "Good bye!")
sys.exit() sys.exit()
def scanNumber(InputNumber): def scanNumber(InputNumber):
print(code_title + "[!] ---- Fetching informations for {} ---- [!]".format(formatNumber(InputNumber)))
localScan(InputNumber)
global number global number
global localNumber global localNumber
global internationalNumber global internationalNumber
global numberCountryCode global numberCountryCode
global numberCountry global numberCountry
print(code_title +
"[!] ---- Fetching informations for {} ---- [!]".format(formatNumber(InputNumber)))
localScan(InputNumber)
if not number: if not number:
print((code_error + "Error: number {} is not valid. Skipping.".format(formatNumber(InputNumber)))) print((code_error + "Error: number {} is not valid. Skipping.".format(formatNumber(InputNumber))))
sys.exit() sys.exit()
@ -566,98 +512,28 @@ def scanNumber(InputNumber):
print(code_info + "Scan finished.") print(code_info + "Scan finished.")
if not args.no_ansi and not args.output: print('\n')
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()
try:
if args.output: if args.output:
code_info = '[*] '
code_warning = '(!) '
code_result = '[+] '
code_error = '[!] '
code_title = ''
if args.osint: if args.osint:
print( print('\033[91m[!] OSINT scanner is not available using output option (sorry).')
'\033[91m[!] OSINT scanner is not available using output option (sorry).')
sys.exit() sys.exit()
sys.stdout = args.output sys.stdout = args.output
banner() # Output banner again in the file banner()
else:
code_info = '\033[97m[*] '
code_warning = '\033[93m(!) '
code_result = '\033[1;32m[+] '
code_error = '\033[91m[!] '
code_title = '\033[1m\033[93m'
# Verify scanner option # Verify scanner option
if not args.scanner in scanners: if not args.scanner in scanners:
@ -669,19 +545,9 @@ def main():
elif args.input: elif args.input:
for line in args.input.readlines(): for line in args.input.readlines():
scanNumber(line) scanNumber(line)
else:
parser.print_help()
sys.exit()
if args.output: if args.output:
args.output.close() 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() sys.exit()
if __name__ == '__main__':
signal.signal(signal.SIGINT, signal_handler)
main()

View File

@ -3,5 +3,3 @@ bs4
html5lib html5lib
phonenumbers phonenumbers
argparse argparse
urllib3
colorama