mirror of
https://github.com/mxrch/GHunt.git
synced 2025-12-22 13:47:07 +00:00
Geolocation module!
This commit is contained in:
67
ghunt/apis/geolocation.py
Normal file
67
ghunt/apis/geolocation.py
Normal file
@@ -0,0 +1,67 @@
|
||||
from ghunt.objects.base import GHuntCreds
|
||||
from ghunt.errors import *
|
||||
import ghunt.globals as gb
|
||||
from ghunt.objects.apis import GAPI
|
||||
from ghunt.parsers.geolocate import GeolocationResponse
|
||||
|
||||
import httpx
|
||||
|
||||
from typing import *
|
||||
import inspect
|
||||
import json
|
||||
|
||||
|
||||
class GeolocationHttp(GAPI):
|
||||
def __init__(self, creds: GHuntCreds, headers: Dict[str, str] = {}):
|
||||
super().__init__()
|
||||
|
||||
if not headers:
|
||||
headers = gb.config.headers
|
||||
|
||||
base_headers = {}
|
||||
|
||||
headers = {**headers, **base_headers}
|
||||
|
||||
self.hostname = "www.googleapis.com"
|
||||
self.scheme = "https"
|
||||
|
||||
self.authentication_mode = None # sapisidhash, cookies_only, oauth or None
|
||||
self.require_key = "geolocation" # key name, or None
|
||||
|
||||
self._load_api(creds, headers)
|
||||
|
||||
async def geolocate(self, as_client: httpx.AsyncClient, bssid: str, body: dict) -> Tuple[bool, GeolocationResponse]:
|
||||
endpoint_name = inspect.currentframe().f_code.co_name
|
||||
|
||||
verb = "POST"
|
||||
base_url = f"/geolocation/v1/geolocate"
|
||||
data_type = "json" # json, data or None
|
||||
|
||||
if bssid:
|
||||
payload = {
|
||||
"considerIp": False,
|
||||
"wifiAccessPoints": [
|
||||
{
|
||||
"macAddress": "00:25:9c:cf:1c:ad"
|
||||
},
|
||||
{
|
||||
"macAddress": bssid
|
||||
},
|
||||
]
|
||||
}
|
||||
else:
|
||||
payload = body
|
||||
|
||||
self._load_endpoint(endpoint_name)
|
||||
req = await self._query(as_client, verb, endpoint_name, base_url, None, payload, data_type)
|
||||
|
||||
# Parsing
|
||||
data = json.loads(req.text)
|
||||
|
||||
resp = GeolocationResponse()
|
||||
if "error" in data:
|
||||
return False, resp
|
||||
|
||||
resp._scrape(data)
|
||||
|
||||
return True, resp
|
||||
47
ghunt/cli.py
47
ghunt/cli.py
@@ -1,33 +1,57 @@
|
||||
from rich_argparse import RichHelpFormatter
|
||||
|
||||
import argparse
|
||||
from typing import *
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def parse_and_run():
|
||||
parser = argparse.ArgumentParser()
|
||||
RichHelpFormatter.styles["argparse.groups"] = "misty_rose1"
|
||||
RichHelpFormatter.styles["argparse.metavar"] = "light_cyan1"
|
||||
RichHelpFormatter.styles["argparse.args"] = "light_steel_blue1"
|
||||
RichHelpFormatter.styles["argparse.prog"] = "light_pink1 bold italic"
|
||||
|
||||
|
||||
parser = argparse.ArgumentParser(formatter_class=RichHelpFormatter)
|
||||
subparsers = parser.add_subparsers(dest="module")
|
||||
|
||||
### Login module
|
||||
parser_login = subparsers.add_parser('login', help="Authenticate GHunt to Google.")
|
||||
parser_login = subparsers.add_parser('login', help="Authenticate GHunt to Google.", formatter_class=RichHelpFormatter)
|
||||
parser_login.add_argument('--clean', action='store_true', help="Clear credentials local file.")
|
||||
|
||||
### Email module
|
||||
parser_email = subparsers.add_parser('email', help="Get information on an email address.")
|
||||
parser_email = subparsers.add_parser('email', help="Get information on an email address.", formatter_class=RichHelpFormatter)
|
||||
parser_email.add_argument("email_address")
|
||||
parser_email.add_argument('--json', type=str, help="File to write the JSON output to.")
|
||||
parser_email.add_argument('--json', type=Path, help="File to write the JSON output to.")
|
||||
|
||||
### Gaia module
|
||||
parser_gaia = subparsers.add_parser('gaia', help="Get information on a Gaia ID.")
|
||||
parser_gaia = subparsers.add_parser('gaia', help="Get information on a Gaia ID.", formatter_class=RichHelpFormatter)
|
||||
parser_gaia.add_argument("gaia_id")
|
||||
parser_gaia.add_argument('--json', type=str, help="File to write the JSON output to.")
|
||||
parser_gaia.add_argument('--json', type=Path, help="File to write the JSON output to.")
|
||||
|
||||
### Drive module
|
||||
parser_drive = subparsers.add_parser('drive', help="Get information on a Drive file or folder.")
|
||||
parser_drive = subparsers.add_parser('drive', help="Get information on a Drive file or folder.", formatter_class=RichHelpFormatter)
|
||||
parser_drive.add_argument("file_id", help="Example: 1N__vVu4c9fCt4EHxfthUNzVOs_tp8l6tHcMBnpOZv_M")
|
||||
parser_drive.add_argument('--json', type=str, help="File to write the JSON output to.")
|
||||
parser_drive.add_argument('--json', type=Path, help="File to write the JSON output to.")
|
||||
|
||||
### Geolocate module
|
||||
parser_geolocate = subparsers.add_parser('geolocate', help="Geolocate a BSSID.", formatter_class=RichHelpFormatter)
|
||||
geolocate_group = parser_geolocate.add_mutually_exclusive_group(required=True)
|
||||
geolocate_group.add_argument("-b", "--bssid", help="Example: 30:86:2d:c4:29:d0")
|
||||
geolocate_group.add_argument("-f", "--file", type=Path, help="File containing a raw request body, useful to put many BSSIDs. ([italic light_steel_blue1][link=https://developers.google.com/maps/documentation/geolocation/requests-geolocation?#sample-requests]Reference format[/link][/italic light_steel_blue1])")
|
||||
parser_geolocate.add_argument('--json', type=Path, help="File to write the JSON output to.")
|
||||
|
||||
### Parsing
|
||||
args = parser.parse_args(args=None if sys.argv[1:] else ['--help'])
|
||||
args = None
|
||||
if not sys.argv[1:]:
|
||||
parser.parse_args(["--help"])
|
||||
else:
|
||||
for mod in ["email", "gaia", "drive", "geolocate"]:
|
||||
if sys.argv[1] == mod and not sys.argv[2:]:
|
||||
parser.parse_args([mod, "--help"])
|
||||
|
||||
args = parser.parse_args(args)
|
||||
process_args(args)
|
||||
|
||||
def process_args(args: argparse.Namespace):
|
||||
@@ -44,4 +68,7 @@ def process_args(args: argparse.Namespace):
|
||||
asyncio.run(gaia.hunt(None, args.gaia_id, args.json))
|
||||
case "drive":
|
||||
from ghunt.modules import drive
|
||||
asyncio.run(drive.hunt(None, args.file_id, args.json))
|
||||
asyncio.run(drive.hunt(None, args.file_id, args.json))
|
||||
case "geolocate":
|
||||
from ghunt.modules import geolocate
|
||||
asyncio.run(geolocate.main(None, args.bssid, args.file, args.json))
|
||||
@@ -12,7 +12,7 @@ def show_banner():
|
||||
[/][green]Y88b d88P [/][blue]888 888[/][green] Y88b 888[/][yellow] 888 888[/][red] Y88b.
|
||||
[/][green] "Y8888P88 [/][blue]888 888[/][green] "Y88888[/][yellow] 888 888[/][red] "Y888[/red] v2
|
||||
|
||||
[bold]By: mxrch (🐦 [deep_sky_blue1]@mxrchreborn[/deep_sky_blue1])
|
||||
[bold]By: mxrch (🐦 [deep_sky_blue1][link=https://x.com/mxrchreborn]@mxrchreborn[/link][/deep_sky_blue1])
|
||||
[indian_red1]Support my work on GitHub Sponsors ! 💖[/indian_red1][/bold]
|
||||
"""
|
||||
|
||||
|
||||
@@ -4,5 +4,6 @@ keys = {
|
||||
"apis_explorer": {"key": "AIzaSyAa8yy0GdcGPHdtD083HiGGx_S0vMPScDM", "origin": "https://explorer.apis.google.com"},
|
||||
"calendar": {"key": "AIzaSyBNlYH01_9Hc5S1J9vuFmu2nUqBZJNAXxs", "origin": "https://calendar.google.com"},
|
||||
"youtubei": {"key": "AIzaSyA8eiZmM1FaDVjRy-df2KTyQ_vz_yYM39w", "origin": "https://youtube.com"},
|
||||
"drive": {"key": "AIzaSyD_InbmSFufIEps5UAt2NmB_3LvBH3Sz_8", "origin": "https://drive.google.com"}
|
||||
"drive": {"key": "AIzaSyD_InbmSFufIEps5UAt2NmB_3LvBH3Sz_8", "origin": "https://drive.google.com"},
|
||||
"geolocation": {"key": "AIzaSyB41DRUbKWJHPxaFjMAwdrzWzbVKartNGg", "origin": "https://geo-devrel-javascript-samples.web.app"} # https://developers.google.com/maps/documentation/javascript/overview
|
||||
}
|
||||
@@ -29,7 +29,7 @@ def show_user(user: DriveExtractedUser):
|
||||
if user.is_last_modifying_user:
|
||||
print("[+] Last user to have modified the document !")
|
||||
|
||||
async def hunt(as_client: httpx.AsyncClient, file_id: str, json_file: bool=None):
|
||||
async def hunt(as_client: httpx.AsyncClient, file_id: str, json_file: bool=Path):
|
||||
if not as_client:
|
||||
as_client = get_httpx_client()
|
||||
|
||||
|
||||
@@ -9,9 +9,10 @@ from ghunt.helpers.knowledge import get_user_type_definition
|
||||
import httpx
|
||||
|
||||
from typing import *
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
async def hunt(as_client: httpx.AsyncClient, email_address: str, json_file: bool=None):
|
||||
async def hunt(as_client: httpx.AsyncClient, email_address: str, json_file: Path=None):
|
||||
if not as_client:
|
||||
as_client = get_httpx_client()
|
||||
|
||||
|
||||
@@ -9,9 +9,10 @@ from ghunt.helpers.utils import get_httpx_client
|
||||
import httpx
|
||||
|
||||
from typing import *
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
async def hunt(as_client: httpx.AsyncClient, gaia_id: str, json_file: bool=None):
|
||||
async def hunt(as_client: httpx.AsyncClient, gaia_id: str, json_file: Path=None):
|
||||
if not as_client:
|
||||
as_client = get_httpx_client()
|
||||
|
||||
|
||||
60
ghunt/modules/geolocate.py
Normal file
60
ghunt/modules/geolocate.py
Normal file
@@ -0,0 +1,60 @@
|
||||
from ghunt import globals as gb
|
||||
from ghunt.helpers.utils import get_httpx_client
|
||||
from ghunt.apis.geolocation import GeolocationHttp
|
||||
from ghunt.helpers import auth
|
||||
|
||||
import httpx
|
||||
from geopy.geocoders import Nominatim
|
||||
|
||||
from typing import *
|
||||
from pathlib import Path
|
||||
import json
|
||||
|
||||
|
||||
async def main(as_client: httpx.AsyncClient, bssid: str, input_file: Path, json_file: Path=None):
|
||||
# Verifying args
|
||||
body = None
|
||||
if input_file:
|
||||
if not input_file.exists():
|
||||
exit(f"[-] The input file \"{input_file}\" doesn't exist.")
|
||||
with open(input_file, "r", encoding="utf-8") as f:
|
||||
try:
|
||||
body = json.load(f)
|
||||
except json.JSONDecodeError:
|
||||
exit("[-] The input file is not a valid JSON file.")
|
||||
|
||||
if not as_client:
|
||||
as_client = get_httpx_client()
|
||||
|
||||
ghunt_creds = await auth.load_and_auth(as_client)
|
||||
|
||||
geo_api = GeolocationHttp(ghunt_creds)
|
||||
found, resp = await geo_api.geolocate(as_client, bssid=bssid, body=body)
|
||||
if not found:
|
||||
exit("[-] The location wasn't found.")
|
||||
|
||||
geolocator = Nominatim(user_agent="nominatim")
|
||||
location = geolocator.reverse(f"{resp.location.latitude}, {resp.location.longitude}", timeout=10)
|
||||
raw_address = location.raw['address']
|
||||
address = location.address
|
||||
|
||||
gb.rc.print("📍 Location found !\n", style="plum2")
|
||||
gb.rc.print(f"🛣️ [italic]Accuracy : {resp.accuracy} meters[/italic]\n")
|
||||
gb.rc.print(f"Latitude : {resp.location.latitude}", style="bold")
|
||||
gb.rc.print(f"Longitude : {resp.location.longitude}\n", style="bold")
|
||||
gb.rc.print(f"🏠 Estimated address : {address}\n")
|
||||
gb.rc.print(f"🗺️ [italic][link=https://www.google.com/maps/search/?q={resp.location.latitude},{resp.location.longitude}]Open in Google Maps[/link][/italic]\n", style=f"cornflower_blue")
|
||||
|
||||
if json_file:
|
||||
from ghunt.objects.encoders import GHuntEncoder;
|
||||
with open(json_file, "w", encoding="utf-8") as f:
|
||||
f.write(json.dumps({
|
||||
"accuracy": resp.accuracy,
|
||||
"latitude": resp.location.latitude,
|
||||
"longitude": resp.location.longitude,
|
||||
"address": raw_address,
|
||||
"pretty_address": address
|
||||
}, cls=GHuntEncoder, indent=4))
|
||||
gb.rc.print(f"[+] JSON output wrote to {json_file} !", style="italic")
|
||||
|
||||
await as_client.aclose()
|
||||
17
ghunt/parsers/geolocate.py
Normal file
17
ghunt/parsers/geolocate.py
Normal file
@@ -0,0 +1,17 @@
|
||||
from ghunt.objects.apis import Parser
|
||||
from ghunt.objects.base import Position
|
||||
|
||||
from typing import *
|
||||
|
||||
|
||||
class GeolocationResponse(Parser):
|
||||
def __init__(self):
|
||||
self.accuracy: int = 0
|
||||
self.location: Position = Position()
|
||||
|
||||
def _scrape(self, base_model_data: dict[str, any]):
|
||||
self.accuracy = base_model_data.get("accuracy")
|
||||
|
||||
location = base_model_data.get("location")
|
||||
self.location.longitude = location.get("lng")
|
||||
self.location.latitude = location.get("lat")
|
||||
@@ -1,4 +1,4 @@
|
||||
metadata = {
|
||||
"version": "2.1.6",
|
||||
"name": "BlackHat Edition"
|
||||
"version": "2.2.0",
|
||||
"name": "Wardriving Edition"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "ghunt"
|
||||
version = "2.1.6"
|
||||
version = "2.2.0"
|
||||
authors = [
|
||||
{name = "mxrch", email = "mxrch.dev@pm.me"},
|
||||
]
|
||||
|
||||
@@ -13,4 +13,5 @@ humanize==4.4.0
|
||||
inflection==0.5.1
|
||||
jsonpickle==2.2.0
|
||||
packaging==23.0
|
||||
jsonpickle==2.2.0
|
||||
jsonpickle==2.2.0
|
||||
rich_argparse==1.5.0
|
||||
Reference in New Issue
Block a user