Compare commits

...

80 Commits

Author SHA1 Message Date
Raphael dab7d35e02
Create pull_request_template.md 2019-03-03 12:14:49 +01:00
Raphael cb823066b4
Merge pull request #38 from sundowndev/develop
[Fix] Google search results & add source
2019-02-21 15:05:18 +01:00
Raphael 1c2ec491b5
Version 1.0.2 2019-02-21 14:57:44 +01:00
Raphael aaaf9304bd
Increase web pages results limit to 10 2019-02-21 14:49:58 +01:00
Raphael 937b3abe4f
Merge pull request #37 from sundowndev/source/findwhocallsme
Reputation source & Google search hotfix
2019-02-21 14:47:21 +01:00
sundowndev 3a63bd036d [Fix] Google search results 2019-02-21 14:42:18 +01:00
sundowndev 2e17453143 Use local format in OSINT scan 2019-02-21 14:41:37 +01:00
Raphael be44f64d58
Add findwhocallsme.com source 2019-02-21 13:12:28 +01:00
Raphael 719135c4c3
Merge pull request #35 from sundowndev/develop
[Fix] Country name for OVH scan
2019-02-19 15:12:01 +01:00
Raphael e02b4edaeb
Remove useless .replace() 2019-02-19 15:04:28 +01:00
Raphael f020a1ec85
Version 2019-02-19 14:59:02 +01:00
Raphael dc6c226252
Merge pull request #34 from sundowndev/hotfix/numCountry
Number country
2019-02-19 14:57:44 +01:00
sundowndev 303c583201 Fix: country name for OVH scan 2019-02-19 14:21:11 +01:00
Raphael 8bac8eb377
Merge pull request #32 from sundowndev/develop
Scanning improvements, readme & refactor
2019-02-18 16:58:42 +01:00
Raphael c553ca1e85
Merge pull request #33 from sundowndev/feature/refactor
Refactor
2019-02-18 16:48:47 +01:00
sundowndev 22c8bcfccb Refactor python file
Now using main() to launch tool, put everything else in some functions and put every lib import at the top of the file. Looking forward to a better file structure with multiple python files :-). It\'s already better to handle exceptions
2019-02-18 16:43:10 +01:00
sundowndev 384370eaa1 Test script 2019-02-18 16:07:50 +01:00
Raphael 1ca83be4da
Merge pull request #31 from sundowndev/awesome-readme
Awesome readme
2019-02-18 15:25:27 +01:00
sundowndev 1d69e2708d Autoindent code 2019-02-18 15:18:30 +01:00
sundowndev 006fd8bd91 Show help msg when any number is passed 2019-02-18 15:17:46 +01:00
Raphael ec85cdbd23
Update README.md 2019-02-18 15:10:39 +01:00
Raphael ec2ff93a87
Update README.md 2019-02-18 14:17:38 +01:00
Raphael e1b10a5d50
Beautify readme 2019-02-18 14:08:54 +01:00
sundowndev e1559004fb Add exception on numverify scan 2019-02-18 11:59:48 +01:00
sundowndev a5bf2d4918 Delete country codes file 2019-02-18 11:52:01 +01:00
sundowndev e3b4778cd4 Merge branch 'feature/countryName' into develop 2019-02-18 11:50:40 +01:00
Raphael 6309f6f960
Delete CountryCodes.json 2019-02-18 11:48:53 +01:00
sundowndev 85ba7478d9 Generated examples 2019-02-18 11:47:11 +01:00
sundowndev ea78993e47 Remove (useless) area result in local scan 2019-02-18 11:46:44 +01:00
sundowndev c1efb3650d Use local scan to find code instead of using third party API 2019-02-18 11:41:25 +01:00
Raphael 9116d5654b
Merge pull request #26 from sundowndev/hotfix/data-patch
Hotfix : Remove Canada country code
2019-02-14 18:39:34 +01:00
Raphael 942d7f8edc
Issue templates (#29) 2019-02-14 18:33:08 +01:00
Raphael 807c2a1a6d
Merge pull request #27 from sundowndev/develop
Decode responses to utf8
2019-02-04 19:29:12 +01:00
sundowndev 6fe97094eb Decode responses to utf8 2019-02-04 12:30:19 +01:00
Raphael 2b119cc913
Issue templates 2019-01-31 15:11:20 +01:00
Raphael 5ced4f7aec
Remove Canada and spaces
Issue #24
2019-01-31 14:33:09 +01:00
Raphael e108c1e36c
Merge pull request #20 from sundowndev/develop
v1.0.0-rc4 merge
2019-01-31 13:58:36 +01:00
Raphael 9872168db6
Merge branch 'master' into develop 2019-01-28 22:31:31 +01:00
Raphael 4e2869cba7
locatefamily.com footprinting 2019-01-28 15:05:42 +01:00
Raphael 2a6ecf15dd
Merge pull request #25 from sundowndev/hotfix/countryScan
[Fix #24] Country code scan
2019-01-28 11:38:47 +01:00
sundowndev 00cc280c40 Add exception on OVH API request 2019-01-28 11:36:24 +01:00
sundowndev ff06854856 Local database update 2019-01-28 11:30:05 +01:00
sundowndev c505ef1be8 [Fix #24] Country code scan
Use local json database to find country code instead of using third party API
2019-01-28 11:11:16 +01:00
Raphael 4fdab3bf34
Merge pull request #23 from sundowndev/master
Rebase develop
2019-01-25 22:36:26 +01:00
Raphael 3cfb11355f
Merge pull request #22 from sundowndev/hotfix/numverify
[Fix] Numverify scan & error exception
2019-01-23 18:43:36 +01:00
sundowndev 0eec71535b [Fix] Numverify scan & error exception 2019-01-23 18:40:31 +01:00
Raphael f09c96f826
Version
Set version to 1.0.0 and update number formatting examples.
2019-01-23 18:10:33 +01:00
Raphael 8e1cae6b9c
Delete RESOURCES.md
Moved to wiki
2019-01-20 15:46:50 +01:00
Raphael 27b39208b0
Merge pull request #21 from sundowndev/patch-msg
Patch need help message
2019-01-17 09:19:57 +00:00
Raphael bdc0bf8b23
fallback version to v1.0.0-rc2 2019-01-17 10:12:23 +01:00
Raphael 922186ca79
Need help message link 2019-01-17 10:11:40 +01:00
Raphael 170a94b702
Python badge 2019-01-14 14:25:28 +01:00
Raphael f0b54fbef4
Wiki link 2019-01-14 12:00:15 +01:00
Raphael 17c11ec794
Merge pull request #19 from sundowndev/travis-cfg
travis config
2019-01-14 10:38:12 +00:00
Raphael 58f35cb634
using python 3.7-dev 2019-01-14 11:35:37 +01:00
Raphael c9a8441f36
Build status 2019-01-14 11:34:43 +01:00
Raphael 74904549a9
Update .travis.yml 2019-01-14 11:32:55 +01:00
Raphael ac3eff13de
Create .travis.yml 2019-01-14 11:28:09 +01:00
Raphael 11b47c0562
Merge pull request #18 from sundowndev/develop
1.1.2-rc1 Improve footprinting
2019-01-14 10:22:55 +00:00
Raphael a8a3015f12
version 2019-01-14 11:22:44 +01:00
sundowndev f2dd168491 [Fix] Document footprinting 2019-01-14 11:19:55 +01:00
sundowndev 96406c4e23 Ask to rerun OSINT scan at finish state 2019-01-14 11:19:29 +01:00
sundowndev 7eadfa502b Generated examples 2019-01-14 10:30:07 +01:00
sundowndev 31eb7425c6 no-ansi option & minor refactor 2019-01-14 10:29:09 +01:00
Raphael 51f76150e4
Merge pull request #17 from sundowndev/develop
1.1.0-rc1 release
2019-01-14 08:58:55 +00:00
Raphael 347d0e87bf
Version 2019-01-14 09:58:27 +01:00
sundowndev ea3e0a0024 Script to generate example outputs 2019-01-07 15:02:02 +01:00
Raphael 45875a1d62
Document footprints request 2019-01-07 12:33:54 +01:00
Raphael e9b42d078c
Document footprints : adding .xls extension 2019-01-07 12:12:05 +01:00
Raphael 89baab6f87
[Docs] OSINT Tutorial link 2019-01-04 14:13:44 +01:00
Raphael bcf11a938b
[Fix #15] Add exception on tempophone API call 2018-12-29 18:58:40 +01:00
Raphael 6cce114a7a
Typo 2018-12-26 15:55:32 +01:00
Raphael 59ac083ccd
Add smslive.co 2018-12-26 15:52:30 +01:00
Raphael fd999a1d05
[Docs] OSINT resources 2018-12-21 18:29:39 +01:00
Raphael eb7ba13ee9
[Docs] OSINT resources 2018-12-21 18:24:26 +01:00
Raphael dee05839ec
[Docs] Captcha Troubleshooting
>The cookie should be created after you complete the captcha. If there's no captcha and *GOOGLE_ABUSE_EXEMPTION* cookie, try pressing F5 to refresh the page. The cookie should've been created. If refreshing the page does not help, change the query to something different (change the number or add text). Google will not necessarily ask you to complete a captcha if your request is the exact same as the previous one, because it'll usually be cached.
2018-12-21 11:37:04 +01:00
Raphael ed79a4f23f
tag badge 2018-12-20 15:05:21 +01:00
Raphael 01f60ef4bf
lib import priority
Import sys before other libs to avoid errors on sys.exit() when requirements are missing
2018-12-16 14:04:23 +00:00
Raphael 120e190c29
Rename tests/list.txt to examples/input.txt 2018-12-14 17:26:37 +01:00
Raphael 7a14c7c5bd
[Docs] Typo 2018-12-14 17:23:52 +01:00
12 changed files with 543 additions and 335 deletions

5
.github/pull_request_template.md vendored Normal file
View File

@ -0,0 +1,5 @@
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:

7
.travis.yml Normal file
View File

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

124
README.md
View File

@ -1,11 +1,35 @@
# PhoneInfoga
<h1 align="center">PhoneInfoga</h1>
![](https://img.shields.io/badge/python-3.x-blue.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>
<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
@ -21,29 +45,18 @@ One of the most advanced tools to scan phone numbers using only free resources.
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
```bash
git clone https://github.com/sundowndev/PhoneInfoga
cd ./PhoneInfoga
cd PhoneInfoga/
python3 -m pip install -r requirements.txt
```
## Usage
### [The full usage documentation has been moved to the wiki](https://github.com/sundowndev/PhoneInfoga/wiki)
```
usage: phoneinfoga.py -n <number> [options]
@ -65,79 +78,6 @@ optional arguments:
-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
This tool is licensed under the GNU General Public License v3.0.

13
examples/generate.sh Executable file
View File

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

@ -0,0 +1,87 @@
___ _ _____ __
/ _ \ |__ ___ _ __ ___ \_ \_ __ / _| ___ __ _ __ _
/ /_)/ '_ \ / _ \| '_ \ / _ \ / /\/ '_ \| |_ / _ \ / _` |/ _` |
/ ___/| | | | (_) | | | | __/\/ /_ | | | | _| (_) | (_| | (_| |
\/ |_| |_|\___/|_| |_|\___\____/ |_| |_|_| \___/ \__, |\__,_|
|___/
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

@ -0,0 +1,30 @@
___ _ _____ __
/ _ \ |__ ___ _ __ ___ \_ \_ __ / _| ___ __ _ __ _
/ /_)/ '_ \ / _ \| '_ \ / _ \ / /\/ '_ \| |_ / _ \ / _` |/ _` |
/ ___/| | | | (_) | | | | __/\/ /_ | | | | _| (_) | (_| | (_| |
\/ |_| |_|\___/|_| |_|\___\____/ |_| |_|_| \___/ \__, |\__,_|
|___/
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,5 +98,10 @@
"site": "receive-sms-online.com",
"request": "site:\"receive-sms-online.com\" intext:\"$n\"",
"stop": 1
},
{
"site": "smslive.co",
"request": "site:\"smslive.co\" intext:\"$n\"",
"stop": 1
}
]

View File

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

View File

@ -1,12 +1,17 @@
[
{
"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
},
{
"title": "phone fraud footprints",
"request": "intitle:\"Phone Fraud\" intext:\"$n\" | intext:\"$i\"",
"request": "intitle:\"Phone Fraud\" intext:\"$i\" | intext:\"$n\" | intext:\"$l\"",
"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",
"request": "site:\"facebook.com\" intext:\"$i\" | intext:\"$n\"",
"request": "site:\"facebook.com\" intext:\"$i\" | intext:\"$n\" | intext:\"$l\"",
"stop": 5
},
{
"site": "twitter.com",
"request": "site:\"twitter.com\" intext:\"$i\" | intext:\"$n\"",
"request": "site:\"twitter.com\" intext:\"$i\" | intext:\"$n\" | intext:\"$l\"",
"stop": 5
},
{
"site": "linkedin.com",
"request": "site:\"linkedin.com\" intext:\"$i\" | intext:\"$n\"",
"request": "site:\"linkedin.com\" intext:\"$i\" | intext:\"$n\" | intext:\"$l\"",
"stop": 5
},
{
"site": "instagram.com",
"request": "site:\"instagram.com\" intext:\"$i\" | intext:\"$n\"",
"request": "site:\"instagram.com\" intext:\"$i\" | intext:\"$n\" | intext:\"$l\"",
"stop": 5
}
]

View File

@ -1,39 +1,32 @@
#!/usr/bin/env python3
__version__ = 'v1.0.0-rc2'
__version__ = 'v1.0.2'
try:
import sys
import signal
from colorama import Fore, Style
import atexit
import sys
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__),
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,
@ -54,105 +47,71 @@ parser.add_argument('--osint', action='store_true',
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)
# 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
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 (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 = ''
customFormatting = ''
def search(req, stop):
global googleAbuseToken
@ -160,7 +119,7 @@ def search(req, stop):
chosenUserAgent = random.choice(uagent)
s = requests.Session()
reqSession = requests.Session()
headers = {
'User-Agent': chosenUserAgent,
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
@ -169,21 +128,26 @@ def search(req, stop):
'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:
URL = 'https://www.google.com/search?tbs=li:1&q={}&amp;gws_rd=ssl'.format(req)
r = s.get(URL + googleAbuseToken, headers=headers)
REQ = urlencode({'q': req})
URL = 'https://www.google.com/search?tbs=li:1&{}&amp;gws_rd=ssl&amp;gl=us '.format(
REQ)
r = reqSession.get(URL + googleAbuseToken, headers=headers)
while r.status_code == 503:
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#dealing-with-google-captcha')
print('\n' + code_info +
'Need help ? Read https://github.com/sundowndev/PhoneInfoga/wiki')
token = input('\nGOOGLE_ABUSE_EXEMPTION=')
googleAbuseToken = '&google_abuse=' + token
r = s.get(URL + googleAbuseToken, headers=headers)
r = reqSession.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")
links = []
@ -204,15 +168,20 @@ def search(req, stop):
if re.match(r"^(?:\/search\?q\=)", url) is not None:
url = 'https://google.com' + url
links.append(url)
if url is not None:
links.append(url)
return links
except:
print(code_error + 'Request failed. Please retry or open an issue on GitHub.')
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
@ -226,27 +195,33 @@ def localScan(InputNumber):
try:
PhoneNumberObject = phonenumbers.parse(FormattedPhoneNumber, None)
except:
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]
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))
countryRequest = json.loads(requests.request('GET', 'https://restcountries.eu/rest/v2/callingcode/{}'.format(numberCountryCode.replace('+', ''))).content)
numberCountry = countryRequest[0]['alpha2Code']
localNumber = phonenumbers.format_number(
PhoneNumberObject, phonenumbers.PhoneNumberFormat.E164).replace(numberCountryCode, '0')
internationalNumber = phonenumbers.format_number(
PhoneNumberObject, phonenumbers.PhoneNumberFormat.INTERNATIONAL)
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 code: {}'.format(numberCountryCode))
print(code_result + 'Location: {}'.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')))
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))
@ -255,6 +230,7 @@ def localScan(InputNumber):
else:
print(code_warning + 'The number is valid but might not be possible.')
def numverifyScan():
global number
@ -263,9 +239,14 @@ def numverifyScan():
print(code_info + 'Running Numverify.com scan...')
requestSecret = ''
resp = requests.get('https://numverify.com/')
soup = BeautifulSoup(resp.text, "html5lib")
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']
@ -274,36 +255,43 @@ def numverifyScan():
apiKey = hashlib.md5((number + requestSecret).encode('utf-8')).hexdigest()
headers = {
'host': "numverify.com",
'connection': "keep-alive",
'content-length': "49",
'accept': "application/json",
'origin': "https://numverify.com",
'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",
'content-type': "multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW",
'referer': "https://numverify.com/",
'accept-encoding': "gzip, deflate, br",
'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"
'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'
}
response = requests.request("GET", "https://numverify.com/php_helper_scripts/phone_api.php?secret_key={}&number={}".format(apiKey, number), data="", headers=headers)
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
data = json.loads(response.content)
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"])
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 +
"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"]))
@ -313,6 +301,7 @@ def numverifyScan():
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
@ -322,16 +311,20 @@ def ovhScan():
print(code_info + 'Running OVH scan...')
querystring = { "country": numberCountry.lower() }
querystring = {"country": numberCountry.lower()}
headers = {
'accept': "application/json",
'cache-control': "no-cache"
}
response = requests.request("GET", "https://api.ovh.com/1.0/telephony/number/detailedZones", data="", headers=headers, params=querystring)
data = json.loads(response.content)
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')
@ -339,11 +332,14 @@ def ovhScan():
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 + "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 '')))
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
@ -355,6 +351,7 @@ def replaceVariables(string):
return string
def osintIndividualScan():
global number
global internationalNumber
@ -366,17 +363,20 @@ def osintIndividualScan():
for dork in dorks:
if dork['dialCode'] is None or dork['dialCode'] == numberCountryCode:
if customFormatting:
dorkRequest = replaceVariables(dork['request']) + ' | intext:"{}"'.format(customFormatting)
dorkRequest = replaceVariables(
dork['request']) + ' | intext:"{}"'.format(customFormatting)
else:
dorkRequest = replaceVariables(dork['request'])
print((code_info + "Searching for footprints on {}...".format(dork['site'])))
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))
print((code_result + "URL: " + result))
else:
return -1
def osintReputationScan():
global number
global internationalNumber
@ -386,14 +386,15 @@ def osintReputationScan():
for dork in dorks:
if customFormatting:
dorkRequest = replaceVariables(dork['request']) + ' | intext:"{}"'.format(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']):
if result:
print((code_result + "URL: " + result))
print((code_result + "URL: " + result))
def osintSocialMediaScan():
global number
@ -404,14 +405,17 @@ def osintSocialMediaScan():
for dork in dorks:
if customFormatting:
dorkRequest = replaceVariables(dork['request']) + ' | intext:"{}"'.format(customFormatting)
dorkRequest = replaceVariables(
dork['request']) + ' | intext:"{}"'.format(customFormatting)
else:
dorkRequest = replaceVariables(dork['request'])
print((code_info + "Searching for footprints on {}...".format(dork['site'])))
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))
print((code_result + "URL: " + result))
def osintDisposableNumScan():
global number
@ -421,19 +425,20 @@ def osintDisposableNumScan():
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']):
if result:
print((code_result + "Result found: {}".format(dork['site'])))
print((code_result + "URL: " + result))
askForExit()
print(
(code_info + "Searching for footprints on {}...".format(dork['site'])))
def osintScan():
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 numberCountry
global customFormatting
if not args.osint:
@ -441,55 +446,68 @@ def osintScan():
print(code_info + 'Running OSINT footprint reconnaissance...')
# Whitepages
print((code_info + "Generating scan URL on 411.com..."))
print(code_result + "Scan URL: https://www.411.com/phone/{}".format(internationalNumber.replace('+', '').replace(' ', '-')))
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) ')
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 ----'))
print((code_info + "Searching for footprints on web pages... (limit=5)"))
print((code_info + "Searching for footprints on web pages... (limit=10)"))
if customFormatting:
req = '{} | intext:"{}" | intext:"{}" | intext:"{}"'.format(number,number,internationalNumber,customFormatting)
req = '{} | intext:"{}" | intext:"{}" | intext:"{}"'.format(
number, number, internationalNumber, customFormatting)
else:
req = '{} | intext:"{}" | intext:"{}"'.format(number,number,internationalNumber)
for result in search(req, stop=5):
if result:
print((code_result + "Result found: " + result))
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 = '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)
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 = '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)
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):
if result:
print((code_result + "Result found: " + result))
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))
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) ")
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 ----'))
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)
for voip_number in data['objects']:
if voip_number['phone'] == formatNumber(number):
print((code_result + "Found a temporary number provider: tempophone.com"))
askForExit()
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()
@ -501,10 +519,20 @@ def osintScan():
if numberCountryCode == '+1':
print((code_info + "Generating URL on True People... "))
print(code_result + 'https://www.truepeoplesearch.com/results?phoneno={}'.format(internationalNumber.replace(' ', '')))
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) ")
@ -515,17 +543,19 @@ def askForExit():
print(code_info + "Good bye!")
sys.exit()
def scanNumber(InputNumber):
print(code_title + "[!] ---- Fetching informations for {} ---- [!]".format(formatNumber(InputNumber)))
localScan(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()
@ -536,28 +566,98 @@ def scanNumber(InputNumber):
print(code_info + "Scan finished.")
print('\n' + Style.RESET_ALL)
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()
try:
if args.output:
code_info = '[*] '
code_warning = '(!) '
code_result = '[+] '
code_error = '[!] '
code_title = ''
if args.osint:
print('\033[91m[!] OSINT scanner is not available using output option (sorry).')
print(
'\033[91m[!] OSINT scanner is not available using output option (sorry).')
sys.exit()
sys.stdout = args.output
banner()
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
banner() # Output banner again in the file
# Verify scanner option
if not args.scanner in scanners:
@ -569,9 +669,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()