Merge branch 'feature/python3' into develop
This commit is contained in:
commit
68fa969b39
105
README.md
105
README.md
|
@ -1,25 +1,21 @@
|
|||
# PhoneInfoga
|
||||
|
||||
Advanced information gathering & OSINT reconnaissance tool for phone numbers. Designed for Social Engineering and red teaming.
|
||||

|
||||

|
||||
|
||||
### Hello, friend. Next time cover your tracks.
|
||||
Information gathering & OSINT reconnaissance tool for phone numbers.
|
||||
|
||||
<img src="https://images.complex.com/complex/images/c_limit,w_680/f_auto,fl_lossy,pg_1,q_auto/robotophone_egpp8m/mr-robot-elliot-on-phone" width="350" />
|
||||
|
||||
## The project
|
||||
|
||||
Building the most advanced tool to scan phone numbers using only free resources. The goal is to first identify basic informations such as country, area, carrier and line type on any international phone numbers with a very good accuracy, and then detect the VoIP provider or search for footprints on search engines to try identify the owner.
|
||||
|
||||
**This tool requires python 2.x**
|
||||
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
|
||||
|
||||
- Check if phone number exists
|
||||
- Check if phone number exists and is possible
|
||||
- Gather standard informations such as country, line type and carrier
|
||||
- Check several numbers at once
|
||||
- Set an output for result(s)
|
||||
- Check if number is from a VoIP provider
|
||||
- OSINT reconnaissance using external APIs, Google Hacking, phone books & search engines
|
||||
- Use custom formatting for more effective OSINT reconnaissance
|
||||
|
||||

|
||||
|
||||
## Formats
|
||||
|
||||
|
@ -43,8 +39,7 @@ Use `any` to disable this feature. Default value: `all`
|
|||
```bash
|
||||
git clone https://github.com/sundowndev/PhoneInfoga
|
||||
cd ./PhoneInfoga
|
||||
pip install -r requirements.txt
|
||||
python ./phoneinfoga.py -h
|
||||
pip3 install -r requirements.txt
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
@ -70,10 +65,16 @@ optional arguments:
|
|||
-u, --update Update the tool & databases
|
||||
```
|
||||
|
||||
Example :
|
||||
Example (quotes are optional, use it when typing special formats) :
|
||||
|
||||
```
|
||||
python phoneinfoga.py -n +42837544833
|
||||
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 :
|
||||
|
@ -82,10 +83,12 @@ Check several numbers at once :
|
|||
python ./phoneinfoga.py -i numbers.txt -o results.txt
|
||||
```
|
||||
|
||||
Check for a number range on OVH (just put some zeros) :
|
||||
**Note: `--osint` is not compatible with `--output` option.**
|
||||
|
||||
Use all scanners and run OSINT reconnaissance :
|
||||
|
||||
```
|
||||
python phoneinfoga.py -n +42837544833 -s ovh
|
||||
python phoneinfoga.py -n +42837544833 -s all --osint
|
||||
```
|
||||
|
||||
## Formatting
|
||||
|
@ -109,54 +112,30 @@ In the UK, and many other countries internationally, local dialing may require t
|
|||
|
||||
For example, here’s a UK-based number in standard local formatting: 020 7183 8750
|
||||
|
||||

|
||||
|
||||
Here’s 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!
|
||||
|
||||

|
||||
|
||||
### 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
|
||||
|
||||

|
||||
|
||||
## 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) 754–3010". 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.
|
||||
|
||||
## Resources
|
||||
|
||||
Regular expression : `^[+]*[(]{0,1}[0-9]{1,4}[)]{0,1}[-\s\./0-9]*$`
|
||||
|
||||
### Docs
|
||||
|
||||
- http://whitepages.fr/phonesystem/
|
||||
- https://support.twilio.com/hc/en-us/articles/223183008-Formatting-International-Phone-Numbers
|
||||
- https://en.wikipedia.org/wiki/National_conventions_for_writing_telephone_numbers
|
||||
|
||||
### open data
|
||||
|
||||
- https://api.ovh.com/console/#/telephony
|
||||
- `/telephony/number/ranges`
|
||||
- `/telephony/number/detailedZones`
|
||||
- `/telephony/number/specificNumbers`
|
||||
- https://countrycode.org/
|
||||
- http://www.countryareacode.net/en/
|
||||
- http://directory.didww.com/area-prefixes
|
||||
- http://hs3x.com/
|
||||
- http://www.numinfo.net/
|
||||
|
||||
### Scanners
|
||||
|
||||
- https://www.phonevalidator.com/
|
||||
- https://freecarrierlookup.com/
|
||||
- https://www.411.com/
|
||||
- https://www.washington.edu/home/peopledir/
|
||||
|
||||
### OSINT
|
||||
|
||||
- https://osintframework.com/
|
||||
- http://raidersec.blogspot.com/2012/12/automated-open-source-intelligence.html#google_api
|
||||
|
||||
#### Google dork requests
|
||||
|
||||
- `insubject:"+XXXXXXXXX" | insubject:"+XXXXX" | insubject:"XXXXX XXX XXX`
|
||||
- `insubject:"{number}" | intitle:"{number}"`
|
||||
- `intext:"{number}" 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:html`
|
||||
- voip provider check: `site:"hs3x.com" intext:"+61437954897"`
|
||||
- scam number check:`site:signal-arnaques.com intext:"0682649478" intitle:" | Phone Fraud"`
|
||||
|
|
1647
data/area_codes.json
1647
data/area_codes.json
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,102 @@
|
|||
[
|
||||
{
|
||||
"site": "hs3x.com",
|
||||
"request": "site:\"hs3x.com\" intext:\"+$n\"",
|
||||
"stop": 1
|
||||
},
|
||||
{
|
||||
"site": "receive-sms-now.com",
|
||||
"request": "site:\"receive-sms-now.com\" intext:\"$n\"",
|
||||
"stop": 1
|
||||
},
|
||||
{
|
||||
"site": "smslisten.com",
|
||||
"request": "site:\"smslisten.com\" intext:\"$n\"",
|
||||
"stop": 1
|
||||
},
|
||||
{
|
||||
"site": "smsnumbersonline.com",
|
||||
"request": "site:\"smsnumbersonline.com\" intext:\"+$n\"",
|
||||
"stop": 1
|
||||
},
|
||||
{
|
||||
"site": "freesmscode.com",
|
||||
"request": "site:\"freesmscode.com\" intext:\"+$n\"",
|
||||
"stop": 1
|
||||
},
|
||||
{
|
||||
"site": "catchsms.com",
|
||||
"request": "site:\"catchsms.com\" intext:\"+$n\"",
|
||||
"stop": 1
|
||||
},
|
||||
{
|
||||
"site": "smstibo.com",
|
||||
"request": "site:\"smstibo.com\" intext:\"+$n\"",
|
||||
"stop": 1
|
||||
},
|
||||
{
|
||||
"site": "smsreceiving.com",
|
||||
"request": "site:\"smsreceiving.com\" intext:\"+$n\"",
|
||||
"stop": 1
|
||||
},
|
||||
{
|
||||
"site": "getfreesmsnumber.com",
|
||||
"request": "site:\"getfreesmsnumber.com\" intext:\"+$n\"",
|
||||
"stop": 1
|
||||
},
|
||||
{
|
||||
"site": "sellaite.com",
|
||||
"request": "site:\"sellaite.com\" intext:\"+$n\"",
|
||||
"stop": 1
|
||||
},
|
||||
{
|
||||
"site": "receive-sms-online.info",
|
||||
"request": "site:\"receive-sms-online.info\" intext:\"+$n\"",
|
||||
"stop": 1
|
||||
},
|
||||
{
|
||||
"site": "receivesmsonline.com",
|
||||
"request": "site:\"receivesmsonline.com\" intext:\"+$n\"",
|
||||
"stop": 1
|
||||
},
|
||||
{
|
||||
"site": "receive-a-sms.com",
|
||||
"request": "site:\"receive-a-sms.com\" intext:\"+$n\"",
|
||||
"stop": 1
|
||||
},
|
||||
{
|
||||
"site": "sms-receive.net",
|
||||
"request": "site:\"sms-receive.net\" intext:\"+$n\"",
|
||||
"stop": 1
|
||||
},
|
||||
{
|
||||
"site": "receivefreesms.com",
|
||||
"request": "site:\"receivefreesms.com\" intext:\"+$n\"",
|
||||
"stop": 1
|
||||
},
|
||||
{
|
||||
"site": "receive-sms.com",
|
||||
"request": "site:\"receive-sms.com\" intext:\"+$n\"",
|
||||
"stop": 1
|
||||
},
|
||||
{
|
||||
"site": "receivetxt.com",
|
||||
"request": "site:\"receivetxt.com\" $n",
|
||||
"stop": 1
|
||||
},
|
||||
{
|
||||
"site": "freephonenum.com",
|
||||
"request": "site:\"freephonenum.com\" intext:\"$n\"",
|
||||
"stop": 1
|
||||
},
|
||||
{
|
||||
"site": "freesmsverification.com",
|
||||
"request": "site:\"freesmsverification.com\" $n",
|
||||
"stop": 1
|
||||
},
|
||||
{
|
||||
"site": "receive-sms-online.com",
|
||||
"request": "site:\"receive-sms-online.com\" intext:\"$n\"",
|
||||
"stop": 1
|
||||
}
|
||||
]
|
|
@ -0,0 +1,20 @@
|
|||
[
|
||||
{
|
||||
"site": "numinfo.net",
|
||||
"request": "site:\"numinfo.net\" intext:\"$n\" | $i",
|
||||
"dialCode": null,
|
||||
"stop": 2
|
||||
},
|
||||
{
|
||||
"site": "sync.me",
|
||||
"request": "site:\"sync.me\" intext:\"$n\" | $i",
|
||||
"dialCode": null,
|
||||
"stop": 1
|
||||
},
|
||||
{
|
||||
"site": "whocallsyou.de",
|
||||
"request": "site:\"whocallsyou.de\" intext:\"0$n\"",
|
||||
"dialCode": null,
|
||||
"stop": 1
|
||||
}
|
||||
]
|
|
@ -0,0 +1,12 @@
|
|||
[
|
||||
{
|
||||
"title": "reputation report on whosenumber.info",
|
||||
"request": "site:\"whosenumber.info\" intext:\"$n\" intitle:\"who called\"",
|
||||
"stop": 1
|
||||
},
|
||||
{
|
||||
"title": "phone fraud footprints",
|
||||
"request": "intitle:\"Phone Fraud\" intext:\"$n\" | \"$n\"",
|
||||
"stop": 5
|
||||
}
|
||||
]
|
|
@ -0,0 +1,22 @@
|
|||
[
|
||||
{
|
||||
"site": "facebook.com",
|
||||
"request": "site:\"facebook.com\" intext:\"$i\" | intext:\"$n\"",
|
||||
"stop": 5
|
||||
},
|
||||
{
|
||||
"site": "twitter.com",
|
||||
"request": "site:\"twitter.com\" intext:\"$i\" | intext:\"$n\"",
|
||||
"stop": 5
|
||||
},
|
||||
{
|
||||
"site": "linkedin.com",
|
||||
"request": "site:\"linkedin.com\" intext:\"$i\" | intext:\"$n\"",
|
||||
"stop": 5
|
||||
},
|
||||
{
|
||||
"site": "instagram.com",
|
||||
"request": "site:\"instagram.com\" intext:\"$i\" | intext:\"$n\"",
|
||||
"stop": 5
|
||||
}
|
||||
]
|
487
phoneinfoga.py
487
phoneinfoga.py
|
@ -1,23 +1,24 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
__version__ = '0.6-dev'
|
||||
__version__ = '0.9-dev'
|
||||
|
||||
def banner():
|
||||
print " ___ _ _____ __ "
|
||||
print " / _ \ |__ ___ _ __ ___ \_ \_ __ / _| ___ __ _ __ _ "
|
||||
print " / /_)/ '_ \ / _ \| '_ \ / _ \ / /\/ '_ \| |_ / _ \ / _` |/ _` |"
|
||||
print " / ___/| | | | (_) | | | | __/\/ /_ | | | | _| (_) | (_| | (_| |"
|
||||
print " \/ |_| |_|\___/|_| |_|\___\____/ |_| |_|_| \___/ \__, |\__,_|"
|
||||
print " |___/ "
|
||||
print " PhoneInfoga Ver. %s " % __version__
|
||||
print " Coded by Sundowndev "
|
||||
print(" ___ _ _____ __ ")
|
||||
print(" / _ \ |__ ___ _ __ ___ \_ \_ __ / _| ___ __ _ __ _ ")
|
||||
print(" / /_)/ '_ \ / _ \| '_ \ / _ \ / /\/ '_ \| |_ / _ \ / _` |/ _` |")
|
||||
print(" / ___/| | | | (_) | | | | __/\/ /_ | | | | _| (_) | (_| | (_| |")
|
||||
print(" \/ |_| |_|\___/|_| |_|\___\____/ |_| |_|_| \___/ \__, |\__,_|")
|
||||
print(" |___/ ")
|
||||
print(" PhoneInfoga Ver. %s " % __version__)
|
||||
print(" Coded by Sundowndev ")
|
||||
print("\n")
|
||||
|
||||
print "\n \033[92m"
|
||||
print("\n \033[92m")
|
||||
banner()
|
||||
print "\033[94m\n"
|
||||
|
||||
import sys
|
||||
import argparse
|
||||
import random
|
||||
|
||||
parser = argparse.ArgumentParser(description=
|
||||
"Advanced information gathering tool for phone numbers (https://github.com/sundowndev/PhoneInfoga) version %s" % __version__,
|
||||
|
@ -49,30 +50,118 @@ if not len(sys.argv) > 1:
|
|||
sys.exit();
|
||||
|
||||
if args.update:
|
||||
print 'update'
|
||||
print('update')
|
||||
sys.exit()
|
||||
|
||||
import requests
|
||||
import hashlib
|
||||
import json
|
||||
from bs4 import BeautifulSoup
|
||||
import re
|
||||
import phonenumbers
|
||||
from phonenumbers import carrier
|
||||
from phonenumbers import geocoder
|
||||
from phonenumbers import timezone
|
||||
try:
|
||||
import time
|
||||
import hashlib
|
||||
import json
|
||||
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()
|
||||
|
||||
scanners = ['any', 'all', 'numverify', 'ovh']
|
||||
|
||||
def formatNumber(number):
|
||||
return re.sub("(?:\+)?(?:[^[0-9]*)", "", number)
|
||||
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")
|
||||
|
||||
def localScan(number):
|
||||
print code_info + 'Running local scan...'
|
||||
number = '' # Full number format
|
||||
localNumber = '' # Local number format
|
||||
internationalNumber = '' # International numberformat
|
||||
numberCountryCode = '' # Dial code; e.g:"+33"
|
||||
numberCountry = '' # Country; e.g:France
|
||||
|
||||
PhoneNumber = dict();
|
||||
googleAbuseToken = ''
|
||||
customFormatting = ''
|
||||
|
||||
FormattedPhoneNumber = "+" + formatNumber(number)
|
||||
def search(req, stop):
|
||||
global googleAbuseToken
|
||||
global uagent
|
||||
|
||||
chosenUserAgent = random.choice(uagent)
|
||||
|
||||
s = requests.Session()
|
||||
headers = {
|
||||
'User-Agent': chosenUserAgent,
|
||||
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
|
||||
'Accept-Language': 'en-us,en;q=0.5',
|
||||
'Accept-Encoding': 'gzip,deflate',
|
||||
'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.7',
|
||||
'Keep-Alive': '115',
|
||||
'Connection': 'keep-alive',
|
||||
'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=%s&gws_rd=ssl' % (req)
|
||||
r = s.get(URL + googleAbuseToken, headers=headers)
|
||||
|
||||
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 : %s' % URL)
|
||||
print('\n' + code_info + 'Need help ? Read https://github.com/sundowndev/PhoneInfoga#dealing-with-google-captcha')
|
||||
token = input('\nGOOGLE_ABUSE_EXEMPTION=')
|
||||
googleAbuseToken = '&google_abuse=' + token
|
||||
r = s.get(URL + googleAbuseToken, headers=headers)
|
||||
|
||||
soup = BeautifulSoup(r.content, 'html.parser')
|
||||
results = soup.find("div", id="search").find_all("div", class_="g")
|
||||
|
||||
links=[]
|
||||
counter=0
|
||||
|
||||
for result in results:
|
||||
counter += 1
|
||||
|
||||
if int(counter) > int(stop):
|
||||
break
|
||||
|
||||
url = result.find("a").get('href')
|
||||
url = re.sub(r'(?:\/url\?q\=)', '', url)
|
||||
url = re.sub(r'(?:\/url\?url\=)', '', url)
|
||||
url = re.sub(r'(?:\&sa\=)(?:.*)', '', url)
|
||||
url = re.sub(r'(?:\&rct\=)(?:.*)', '', url)
|
||||
|
||||
if re.match(r"^(/search\?q=)", url) is not None:
|
||||
url = 'https://google.com' + url
|
||||
|
||||
links.append(url)
|
||||
|
||||
return links
|
||||
except:
|
||||
print(code_error + 'Request failed. Please retry or open an issue on GitHub.')
|
||||
|
||||
def formatNumber(InputNumber):
|
||||
return re.sub("(?:\+)?(?:[^[0-9]*)", "", InputNumber)
|
||||
|
||||
def localScan(InputNumber):
|
||||
global number
|
||||
global localNumber
|
||||
global internationalNumber
|
||||
global numberCountryCode
|
||||
global numberCountry
|
||||
|
||||
print(code_info + 'Running local scan...')
|
||||
|
||||
FormattedPhoneNumber = "+" + formatNumber(InputNumber)
|
||||
|
||||
try:
|
||||
PhoneNumberObject = phonenumbers.parse(FormattedPhoneNumber, None)
|
||||
|
@ -82,30 +171,36 @@ def localScan(number):
|
|||
if not phonenumbers.is_valid_number(PhoneNumberObject):
|
||||
return False
|
||||
|
||||
PhoneNumber['full'] = phonenumbers.format_number(PhoneNumberObject, phonenumbers.PhoneNumberFormat.E164).replace('+', '')
|
||||
PhoneNumber['countryCode'] = phonenumbers.format_number(PhoneNumberObject, phonenumbers.PhoneNumberFormat.INTERNATIONAL).split(' ')[0]
|
||||
PhoneNumber['number'] = phonenumbers.format_number(PhoneNumberObject, phonenumbers.PhoneNumberFormat.E164).replace(PhoneNumber['countryCode'], '')
|
||||
number = phonenumbers.format_number(PhoneNumberObject, phonenumbers.PhoneNumberFormat.E164).replace('+', '')
|
||||
numberCountryCode = phonenumbers.format_number(PhoneNumberObject, phonenumbers.PhoneNumberFormat.INTERNATIONAL).split(' ')[0]
|
||||
|
||||
print code_result + 'Local format: (0)%s' % PhoneNumber['number']
|
||||
print code_result + 'Country code: %s' % PhoneNumber['countryCode']
|
||||
print code_result + 'Location: %s' % geocoder.description_for_number(PhoneNumberObject, "en")
|
||||
print code_result + 'Carrier: %s' % carrier.name_for_number(PhoneNumberObject, 'en')
|
||||
print code_result + 'Area: %s' % geocoder.description_for_number(PhoneNumberObject, 'en')
|
||||
countryRequest = json.loads(requests.request('GET', 'https://restcountries.eu/rest/v2/callingcode/%s' % numberCountryCode.replace('+', '')).content)
|
||||
numberCountry = countryRequest[0]['alpha2Code']
|
||||
|
||||
localNumber = phonenumbers.format_number(PhoneNumberObject, phonenumbers.PhoneNumberFormat.E164).replace(numberCountryCode, '')
|
||||
internationalNumber = phonenumbers.format_number(PhoneNumberObject, phonenumbers.PhoneNumberFormat.INTERNATIONAL)
|
||||
|
||||
print(code_result + 'International format: %s' % internationalNumber)
|
||||
print(code_result + 'Local format: 0%s' % localNumber)
|
||||
print(code_result + 'Country code: %s' % numberCountryCode)
|
||||
print(code_result + 'Location: %s' % geocoder.description_for_number(PhoneNumberObject, "en"))
|
||||
print(code_result + 'Carrier: %s' % carrier.name_for_number(PhoneNumberObject, 'en'))
|
||||
print(code_result + 'Area: %s' % geocoder.description_for_number(PhoneNumberObject, 'en'))
|
||||
for timezoneResult in timezone.time_zones_for_number(PhoneNumberObject):
|
||||
print code_result + 'Timezone: %s' % (timezoneResult)
|
||||
print(code_result + 'Timezone: %s' % (timezoneResult))
|
||||
|
||||
if phonenumbers.is_possible_number(PhoneNumberObject):
|
||||
print code_info + 'The number is valid and possible.'
|
||||
print(code_info + 'The number is valid and possible.')
|
||||
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.')
|
||||
|
||||
return PhoneNumber
|
||||
def numverifyScan():
|
||||
global number
|
||||
|
||||
def numverifyScan(PhoneNumber):
|
||||
if not args.scanner == 'numverify' and not args.scanner == 'all':
|
||||
return -1
|
||||
|
||||
print code_info + 'Running Numverify.com scan...'
|
||||
print(code_info + 'Running Numverify.com scan...')
|
||||
|
||||
requestSecret = ''
|
||||
resp = requests.get('https://numverify.com/')
|
||||
|
@ -115,15 +210,13 @@ def numverifyScan(PhoneNumber):
|
|||
requestSecret = tag['value']
|
||||
break;
|
||||
|
||||
apiKey = hashlib.md5()
|
||||
apiKey.update(PhoneNumber + requestSecret)
|
||||
apiKey = apiKey.hexdigest()
|
||||
apiKey = hashlib.md5((number + requestSecret).encode('utf-8')).hexdigest()
|
||||
|
||||
headers = {
|
||||
'host': "numverify.com",
|
||||
'connection': "keep-alive",
|
||||
'content-length': "49",
|
||||
'accept': "application/json, text/javascript, */*; q=0.01",
|
||||
'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",
|
||||
|
@ -134,40 +227,41 @@ def numverifyScan(PhoneNumber):
|
|||
'cache-control': "no-cache"
|
||||
}
|
||||
|
||||
response = requests.request("GET", "https://numverify.com/php_helper_scripts/phone_api.php?secret_key=" + apiKey + "&number=" + PhoneNumber, data="", headers=headers)
|
||||
response = requests.request("GET", "https://numverify.com/php_helper_scripts/phone_api.php?secret_key=" + apiKey + "&number=" + number, data="", headers=headers)
|
||||
|
||||
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
|
||||
|
||||
data = json.loads(response.content)
|
||||
|
||||
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()
|
||||
|
||||
InternationalNumber = '('+data["country_prefix"]+')' + data["local_format"]
|
||||
|
||||
print(code_result + "Number: (%s) %s") % (data["country_prefix"],data["local_format"])
|
||||
print(code_result + "Country: %s (%s)") % (data["country_name"],data["country_code"])
|
||||
print(code_result + "Location: %s") % data["location"]
|
||||
print(code_result + "Carrier: %s") % data["carrier"]
|
||||
print(code_result + "Line type: %s") % data["line_type"]
|
||||
print((code_result + "Number: (%s) %s") % (data["country_prefix"],data["local_format"]))
|
||||
print((code_result + "Country: %s (%s)") % (data["country_name"],data["country_code"]))
|
||||
print((code_result + "Location: %s") % data["location"])
|
||||
print((code_result + "Carrier: %s") % data["carrier"])
|
||||
print((code_result + "Line type: %s") % data["line_type"])
|
||||
|
||||
if data["line_type"] == 'landline':
|
||||
print(code_warning + "This is most likely a land line, but it can still be a fixed VoIP.")
|
||||
print((code_warning + "This is most likely a land line, but it can still be a fixed VoIP."))
|
||||
elif data["line_type"] == 'mobile':
|
||||
print(code_warning + "This is most likely a mobile, but it can still be a VoIP.")
|
||||
print((code_warning + "This is most likely a mobile, but it can still be a VoIP."))
|
||||
|
||||
def ovhScan():
|
||||
global localNumber
|
||||
global numberCountry
|
||||
|
||||
def ovhScan(countryCode, number):
|
||||
if not args.scanner == 'ovh' and not args.scanner == 'all':
|
||||
return -1
|
||||
|
||||
print code_info + 'Running OVH scan...'
|
||||
print(code_info + 'Running OVH scan...')
|
||||
|
||||
#cc
|
||||
|
||||
querystring = {"country":"fr"}
|
||||
querystring = { "country": numberCountry.lower() }
|
||||
|
||||
headers = {
|
||||
'accept': "application/json",
|
||||
|
@ -179,88 +273,233 @@ def ovhScan(countryCode, number):
|
|||
data = json.loads(response.content)
|
||||
|
||||
if isinstance(data, list):
|
||||
askedNumber = "0" + number.replace(number[-4:], 'xxxx')
|
||||
askedNumber = "0" + localNumber.replace(localNumber[-4:], 'xxxx')
|
||||
|
||||
for voip_number in data:
|
||||
if voip_number['number'] == askedNumber:
|
||||
print(code_info + "1 result found in OVH database")
|
||||
print(code_result + "Number range: " + voip_number['number'])
|
||||
print(code_result + "City: " + voip_number['city'])
|
||||
print(code_result + "Zip code: " + voip_number['zipCode'] if voip_number['zipCode'] is not None else '')
|
||||
print((code_info + "1 result found in OVH database"))
|
||||
print((code_result + "Number range: " + voip_number['number']))
|
||||
print((code_result + "City: " + voip_number['city']))
|
||||
print((code_result + "Zip code: " + voip_number['zipCode'] if voip_number['zipCode'] is not None else ''))
|
||||
askForExit()
|
||||
|
||||
def osintIndividualScan():
|
||||
global number
|
||||
global internationalNumber
|
||||
global numberCountryCode
|
||||
global customFormatting
|
||||
|
||||
dorks = json.load(open('osint/individuals.json'))
|
||||
|
||||
for dork in dorks:
|
||||
if dork['dialCode'] is None or dork['dialCode'] == numberCountryCode:
|
||||
if customFormatting:
|
||||
dorkRequest = dork['request'].replace('$n', number).replace('$i', internationalNumber) + ' | intext:"%s"' % (customFormatting)
|
||||
else:
|
||||
dorkRequest = dork['request'].replace('$n', number).replace('$i', internationalNumber)
|
||||
|
||||
print((code_info + "Searching for footprints on %s..." % dork['site']))
|
||||
for result in search(dorkRequest, stop=dork['stop']):
|
||||
if result:
|
||||
print((code_result + "URL: " + result))
|
||||
else:
|
||||
return -1
|
||||
|
||||
def osintReputationScan():
|
||||
global number
|
||||
global internationalNumber
|
||||
global customFormatting
|
||||
|
||||
dorks = json.load(open('osint/reputation.json'))
|
||||
|
||||
for dork in dorks:
|
||||
if customFormatting:
|
||||
dorkRequest = dork['request'].replace('$n', number).replace('$i', internationalNumber) + ' | intext:"%s"' % (customFormatting)
|
||||
else:
|
||||
dorkRequest = dork['request'].replace('$n', number).replace('$i', internationalNumber)
|
||||
|
||||
print((code_info + "Searching for %s..." % dork['title']))
|
||||
for result in search(dorkRequest, stop=dork['stop']):
|
||||
if result:
|
||||
print((code_result + "URL: " + result))
|
||||
|
||||
def osintSocialMediaScan():
|
||||
global number
|
||||
global internationalNumber
|
||||
global customFormatting
|
||||
|
||||
dorks = json.load(open('osint/social_medias.json'))
|
||||
|
||||
for dork in dorks:
|
||||
if customFormatting:
|
||||
dorkRequest = dork['request'].replace('$n', number).replace('$i', internationalNumber) + ' | intext:"%s"' % (customFormatting)
|
||||
else:
|
||||
dorkRequest = dork['request'].replace('$n', number).replace('$i', internationalNumber)
|
||||
|
||||
print((code_info + "Searching for footprints on %s..." % dork['site']))
|
||||
for result in search(dorkRequest, stop=dork['stop']):
|
||||
if result:
|
||||
print((code_result + "URL: " + result))
|
||||
|
||||
def osintDisposableNumScan():
|
||||
global number
|
||||
|
||||
dorks = json.load(open('osint/disposable_num_providers.json'))
|
||||
|
||||
for dork in dorks:
|
||||
dorkRequest = dork['request'].replace('$n', number)
|
||||
|
||||
print((code_info + "Searching for footprints on %s..." % dork['site']))
|
||||
for result in search(dorkRequest, stop=dork['stop']):
|
||||
if result:
|
||||
print((code_result + "Result found: %s" % dork['site']))
|
||||
print((code_result + "URL: " + result))
|
||||
askForExit()
|
||||
|
||||
def osintScan():
|
||||
global number
|
||||
global localNumber
|
||||
global internationalNumber
|
||||
global numberCountryCode
|
||||
global numberCountry
|
||||
global customFormatting
|
||||
|
||||
def osintScan(countryCode, number):
|
||||
if not args.osint:
|
||||
return -1
|
||||
|
||||
from googlesearch import search
|
||||
|
||||
print code_info + 'Running OSINT reconnaissance...'
|
||||
# OSINT recon
|
||||
|
||||
# social profiles: facebook, twitter, linkedin, instagram
|
||||
# websites
|
||||
# emails
|
||||
print(code_info + 'Running OSINT footprint reconnaissance...')
|
||||
|
||||
# Whitepages
|
||||
print(code_info + "Searching for owner on 411.com...")
|
||||
#https://www.411.com/phone/33-6-79-36-82-33
|
||||
print((code_info + "Generating scan URL on 411.com..."))
|
||||
print(code_result + "Scan URL: https://www.411.com/phone/%s" % internationalNumber.replace('+', '').replace(' ', '-'))
|
||||
|
||||
# Reputation
|
||||
print(code_info + "Searching for reputation page on whosenumber.info...")
|
||||
for result in search('site:whosenumber.info intext:"%s" intitle:"who called"' % number, stop=1):
|
||||
askingCustomPayload = input(code_info + 'Would you like to use an additional format for this number ? (y/N) ')
|
||||
|
||||
if 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)"))
|
||||
if customFormatting:
|
||||
req = '%s | intext:"%s" | intext:"%s" | intext:"%s"' % (number,number,internationalNumber,customFormatting)
|
||||
else:
|
||||
req = '%s | intext:"%s" | intext:"%s"' % (number,number,internationalNumber)
|
||||
for result in search(req, stop=5):
|
||||
if result:
|
||||
print(code_result + "Found 1 result on whosenumber.info.")
|
||||
print(code_info + "This usually means you are not the first to search about this number. Check the URL for eventual comments.")
|
||||
print(code_result + "URL: " + result)
|
||||
print((code_result + "Result found: " + result))
|
||||
|
||||
# VoIP providers
|
||||
print(code_info + "Searching for results on hs3x.com...")
|
||||
for result in search('site:"hs3x.com" intext:"+%s"' % number, stop=1):
|
||||
# Documents
|
||||
print((code_info + "Searching for documents... (limit=10)"))
|
||||
if customFormatting:
|
||||
req = 'intext:"%s" | intext:"%s" | intext:"%s" ext:doc | ext:docx | ext:odt | ext:pdf | ext:rtf | ext:sxw | ext:psw | ext:ppt | ext:pptx | ext:pps | ext:csv | ext:txt' % (number,internationalNumber,customFormatting)
|
||||
else:
|
||||
req = 'intext:"%s" | intext:"%s" ext:doc | ext:docx | ext:odt | ext:pdf | ext:rtf | ext:sxw | ext:psw | ext:ppt | ext:pptx | ext:pps | ext:csv | ext:txt' % (number,internationalNumber)
|
||||
for result in search('intext:"%s" | intext:"%s" ext:doc | ext:docx | ext:odt | ext:pdf | ext:rtf | ext:sxw | ext:psw | ext:ppt | ext:pptx | ext:pps | ext:csv | ext:txt' % (number,internationalNumber), stop=10):
|
||||
if result:
|
||||
print(code_result + "Found 1 result on hs3x.com.")
|
||||
print(code_info + "This number seems to be a VoIP number from hs3x.")
|
||||
print(code_result + "URL: " + result)
|
||||
print((code_result + "Result found: " + result))
|
||||
|
||||
def scanNumber(number):
|
||||
print code_title + "[!] ---- Fetching informations for %s ---- [!]" % formatNumber(number)
|
||||
print((code_info + '---- Reputation footprints ----'))
|
||||
|
||||
PhoneNumber = localScan(number)
|
||||
osintReputationScan()
|
||||
|
||||
if not PhoneNumber:
|
||||
print(code_error + "Error: number " + formatNumber(number) + " is not valid. Skipping.")
|
||||
print((code_info + "Generating URL on scamcallfighters.com..."))
|
||||
print(code_result + 'http://www.scamcallfighters.com/search-phone-%s.html' % number)
|
||||
|
||||
tmpNumAsk = input(code_info + "Would you like to search for temporary number providers footprints ? (Y/n) ")
|
||||
|
||||
if tmpNumAsk.lower() != 'n' and tmpNumAsk.lower() != 'no':
|
||||
print((code_info + '---- Temporary number providers footprints ----'))
|
||||
|
||||
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()
|
||||
|
||||
osintDisposableNumScan()
|
||||
|
||||
print((code_info + '---- Social media footprints ----'))
|
||||
|
||||
osintSocialMediaScan()
|
||||
|
||||
print((code_info + '---- Phone books footprints ----'))
|
||||
|
||||
if numberCountryCode == '+1':
|
||||
print((code_info + "Generating URL on True People... "))
|
||||
print(code_result + 'https://www.truepeoplesearch.com/results?phoneno=%s' % internationalNumber.replace(' ', ''))
|
||||
|
||||
osintIndividualScan()
|
||||
|
||||
def askForExit():
|
||||
if not args.output:
|
||||
user_input = input(code_info + "Continue scanning ? (y/N) ")
|
||||
|
||||
if user_input.lower() == 'y' or user_input.lower() == 'yes':
|
||||
return -1
|
||||
else:
|
||||
print(code_info + "Good bye!")
|
||||
sys.exit()
|
||||
|
||||
def scanNumber(InputNumber):
|
||||
print(code_title + "[!] ---- Fetching informations for %s ---- [!]" % formatNumber(InputNumber))
|
||||
|
||||
localScan(InputNumber)
|
||||
|
||||
global number
|
||||
global localNumber
|
||||
global internationalNumber
|
||||
global numberCountryCode
|
||||
global numberCountry
|
||||
|
||||
if not number:
|
||||
print((code_error + "Error: number " + formatNumber(InputNumber) + " is not valid. Skipping."))
|
||||
sys.exit()
|
||||
|
||||
numverifyScan(PhoneNumber['full'])
|
||||
ovhScan(PhoneNumber['countryCode'], PhoneNumber['number']) # TODO: replace 1st parameter to be dynamic
|
||||
osintScan(PhoneNumber['countryCode'], PhoneNumber['full'])
|
||||
numverifyScan()
|
||||
ovhScan()
|
||||
osintScan()
|
||||
|
||||
print '\n'
|
||||
print(code_info + "Scan finished.")
|
||||
|
||||
# Verify scanner option
|
||||
if not args.scanner in scanners:
|
||||
print(code_error + "Error: scanner doesn't exists.")
|
||||
print('\n')
|
||||
|
||||
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).')
|
||||
sys.exit()
|
||||
|
||||
sys.stdout = args.output
|
||||
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
|
||||
if not args.scanner in scanners:
|
||||
print((code_error + "Error: scanner doesn't exists."))
|
||||
sys.exit()
|
||||
|
||||
if args.number:
|
||||
scanNumber(args.number)
|
||||
elif args.input:
|
||||
for line in args.input.readlines():
|
||||
scanNumber(line)
|
||||
|
||||
if args.output:
|
||||
args.output.close()
|
||||
except KeyboardInterrupt:
|
||||
print((code_error + "Scan interrupted. Good bye!"))
|
||||
sys.exit()
|
||||
|
||||
if args.output:
|
||||
code_info = '[*] '
|
||||
code_warning = '(!) '
|
||||
code_result = '[+] '
|
||||
code_error = '[!] '
|
||||
code_title = ''
|
||||
|
||||
sys.stdout = args.output
|
||||
else:
|
||||
code_info = '\033[97m[*] '
|
||||
code_warning = '\033[93m(!) '
|
||||
code_result = '\033[1;32m[+] '
|
||||
code_error = '\033[91m[!] '
|
||||
code_title = '\033[1m\033[93m'
|
||||
|
||||
if args.number:
|
||||
scanNumber(args.number)
|
||||
elif args.input:
|
||||
for line in args.input.readlines():
|
||||
scanNumber(line)
|
||||
|
||||
if args.output:
|
||||
args.output.close()
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
requests
|
||||
ovh
|
||||
bs4
|
||||
html5lib
|
||||
phonenumbers
|
||||
google
|
||||
argparse
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
+856 20 99 453 217
|
||||
+59172768361
|
||||
+33679368233
|
||||
+32474123456
|
||||
+1 (541) 754-3010
|
||||
+86 591 2284 8571
|
||||
+7 496 4819375
|
15
todo.md
15
todo.md
|
@ -1,15 +0,0 @@
|
|||
# Todo list
|
||||
|
||||
- **Input feature: Done**
|
||||
- **Output feature: Done**
|
||||
- **OVH scanner (search for number range): Done**
|
||||
- Update feature
|
||||
- **Offline scan: Done**
|
||||
- OSINT recon
|
||||
- Search for social profiles (facebook, twitter, linkedin, instagram)
|
||||
- Search for documents
|
||||
- Search for websites
|
||||
- Search for emails
|
||||
- Search on 411
|
||||
- Search on hs3x
|
||||
- Search on whosenumber
|
Loading…
Reference in New Issue