├── Example.png ├── GmailOSINT.py ├── README.md └── requirements.txt /Example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Shakedash-dev/GmailOSINT/67498febd040163fb7b2dcfd023769f230f33c19/Example.png -------------------------------------------------------------------------------- /GmailOSINT.py: -------------------------------------------------------------------------------- 1 | # Name: GmailOSINT.py 2 | # Author: Shakedash 3 | # Description: Recieves a phone number or a gmail address and returns it's GAIA ID, name of the person and places he reviewed (and time taken). 4 | # Date: 18.1.2023 5 | 6 | # Imports. 7 | import undetected_chromedriver as uc 8 | from selenium.webdriver.common.by import By 9 | from time import sleep 10 | from re import findall 11 | import argparse 12 | import sys 13 | 14 | # Constants. 15 | DEFAULT_SLEEP_TIME = 10 16 | LOGIN_URL = "https://accounts.google.com/AccountChooser/signinchooser?service=mail&continue=https%3A%2F%2Fmail.google.com%2Fmail%2F&flowName=GlifWebSignIn&flowEntry=AccountChooser" 17 | REVIEWS_URL = "https://www.google.com/maps/contrib/{0}/reviews" 18 | 19 | FORGOT_PASS_XPATH = '//*[@id="forgotPassword"]/div/button' 20 | IDENTIFIER_UNKNOWN_XPATH = '//*[@id="yDmH0d"]/c-wiz/div/div[2]/div/div[1]/div/form/span/section/div/div/div[1]/div/div[2]/div[2]/div' 21 | GAIA_ID_SCRIPT_XPATH = "/html/head/script[1]" 22 | SUBMIT_IDENT_XPATH = '//*[@id="identifierNext"]/div/button' 23 | INPUT_BOX_XPATH = '//*[@id="identifierId"]' 24 | CHOOSE_AUTH_METHOD_XPATH = '//*[@id="view_container"]/div/div/div[2]/div/div[1]/div/form/span/section/div/div/div/ul' 25 | ADDRESS_IN_MAPS_XPATH = '//*[@id="QA0Szd"]/div/div/div[1]/div[2]/div/div[1]/div/div/div[5]/div[2]/div[{0}]/div/div[3]/div[2]/div[2]/div[1]/div/div[2]/span[1]' 26 | BUSINESS_IN_MAPS_XPATH = '//*[@id="QA0Szd"]/div/div/div[1]/div[2]/div/div[1]/div/div/div[5]/div[2]/div[{0}]/div/div[3]/div[2]/div[2]/div[1]/div/div[1]/span' 27 | REVIEW_TIME_IN_MAPS_XPATH = '//*[@id="QA0Szd"]/div/div/div[1]/div[2]/div/div[1]/div/div/div[5]/div[2]/div[{0}]/div/div[3]/div[4]/div[1]/span[3]' 28 | FULL_NAME_XPATH = ( 29 | '//*[@id="QA0Szd"]/div/div/div[1]/div[2]/div/div[1]/div/div/div[2]/div[2]/div[2]/h1' 30 | ) 31 | 32 | # Globals. 33 | sleep_time = DEFAULT_SLEEP_TIME 34 | 35 | # This function checks if one of the elements it recieves exists. 36 | def CheckPageLoaded(driver, elements): 37 | 38 | # Check if page is loaded times. 39 | for i in range(sleep_time): 40 | sleep(1) 41 | not_found_elements_counter = 0 42 | for element in elements: 43 | try: 44 | driver.find_element(By.XPATH, element) 45 | except: 46 | not_found_elements_counter += 1 47 | 48 | # If one of the elements the function is looking for exists, it probebly means the page is loaded 49 | # (or loaded enough to continue running). 50 | if not_found_elements_counter != len(elements): 51 | 52 | # Just return the execution to the original function. 53 | return True 54 | 55 | # If the loop is ending and the function didn't find any elements, it probebly means the page is not loaded. 56 | if i == sleep_time - 1: 57 | return False 58 | 59 | 60 | # Prints the error message to screen, closes the driver, and exits. 61 | def exit_peacefully(driver, message): 62 | print(message) 63 | driver.close() 64 | sys.exit(1) 65 | 66 | 67 | # Initializing argparse with sleep and identifier arguments. 68 | def argpars_init(): 69 | global sleep_time 70 | parser = argparse.ArgumentParser() 71 | parser.add_argument( 72 | "Identifier_Id", 73 | help="The identifier you want to search the GAIA ID by.\nCan be phone number or gmail address.", 74 | ) 75 | parser.add_argument( 76 | "-s", 77 | "--sleep", 78 | type=int, 79 | help="Number of seconds to sleep between actions. If internet connection is poor, increase this argument.", 80 | ) 81 | args = parser.parse_args() 82 | if args.sleep: 83 | sleep_time = args.sleep 84 | return args.Identifier_Id 85 | 86 | 87 | # Find the GAIA ID inside the page. 88 | def FindGAIAID(driver): 89 | 90 | # Get the GAIA ID out of the response. 91 | script_content = driver.find_element(By.XPATH, GAIA_ID_SCRIPT_XPATH).get_attribute( 92 | "innerHTML" 93 | ) 94 | gaia_id = findall("\d{21}", script_content) 95 | 96 | # If GAIA ID found. 97 | if gaia_id != []: 98 | return gaia_id[0] 99 | else: 100 | print("No GAIA ID found for the current user.") 101 | 102 | 103 | # Recieves GAIA ID and returns the person's name. 104 | def GetNameByGAIAID(driver, gaia_id): 105 | driver.get(REVIEWS_URL.format(gaia_id)) 106 | 107 | if not CheckPageLoaded(driver, [FULL_NAME_XPATH]): 108 | exit_peacefully( 109 | driver, "Poor internet connection...\nPlease use --sleep 20 (or higher)" 110 | ) 111 | full_name = driver.find_element(By.XPATH, FULL_NAME_XPATH).get_attribute( 112 | "innerHTML" 113 | ) 114 | return full_name 115 | 116 | 117 | # GetAdressOfReviews() must be called after GetNameByGAIAID(), because it doe's not change the URL to the needed URL as GetNameByGAIAID() already doe's that. 118 | # It returns a list of the location the account reviewed on. 119 | def GetAdressOfReviews(driver): 120 | addresses = [] 121 | more_reviews = True 122 | c = 1 123 | 124 | # Wait a bit for the page to load. 125 | CheckPageLoaded(driver, [ADDRESS_IN_MAPS_XPATH.format(1)]) 126 | 127 | # Keep iterating on reviews untill finished. 128 | while more_reviews: 129 | try: 130 | address = driver.find_element( 131 | By.XPATH, ADDRESS_IN_MAPS_XPATH.format(str(c)) 132 | ).get_attribute("innerHTML") 133 | 134 | # Sometimes businesses don't have a location to them so at least we can use the business name 135 | if address == "": 136 | address = driver.find_element( 137 | By.XPATH, BUSINESS_IN_MAPS_XPATH.format(str(c)) 138 | ).get_attribute("innerHTML") 139 | review_time = driver.find_element( 140 | By.XPATH, REVIEW_TIME_IN_MAPS_XPATH.format(str(c)) 141 | ).get_attribute("innerHTML") 142 | addresses.append((address, review_time)) 143 | except: 144 | more_reviews = False 145 | c += 2 # The XPATH changes by the count of 2 (for each review) for some reason. 146 | return addresses 147 | 148 | 149 | def main(): 150 | gaia_id = "" # Init. 151 | Identifier_Id = argpars_init() 152 | 153 | driver = uc.Chrome(use_subprocess=True) 154 | # driver.maximize_window() 155 | 156 | driver.get(LOGIN_URL) 157 | driver.refresh() 158 | 159 | # Insert identifier. 160 | driver.find_element(By.XPATH, INPUT_BOX_XPATH).send_keys(Identifier_Id) 161 | 162 | # Submit. 163 | driver.find_element(By.XPATH, SUBMIT_IDENT_XPATH).click() 164 | 165 | # Check if page is loaded and proceed if so. 166 | if not CheckPageLoaded(driver, [FORGOT_PASS_XPATH, IDENTIFIER_UNKNOWN_XPATH]): 167 | exit_peacefully( 168 | driver, "Poor internet connection...\nPlease use --sleep 20 (or higher)" 169 | ) 170 | 171 | # Check if a user exists for the given identifier. 172 | userexists = True 173 | try: 174 | driver.find_element( 175 | By.XPATH, IDENTIFIER_UNKNOWN_XPATH 176 | ) # If no error = unknown user. 177 | userexists = False 178 | except: 179 | pass 180 | 181 | if not userexists: 182 | exit_peacefully( 183 | driver, 184 | f"A Gmail account doe's not exists for identifier {Identifier_Id}", 185 | ) 186 | 187 | # The try\except are for a wierd bug that sometimes happen. 188 | try: 189 | # Click forgot password. 190 | driver.find_element(By.XPATH, FORGOT_PASS_XPATH).click() 191 | except: 192 | sleep(1) 193 | 194 | # Click forgot password again. 195 | driver.find_element(By.XPATH, FORGOT_PASS_XPATH).click() 196 | 197 | # Need some loading time. 198 | sleep(sleep_time / 2) 199 | 200 | # Check if page is loaded and proceed if so. 201 | if not CheckPageLoaded(driver, [CHOOSE_AUTH_METHOD_XPATH]): 202 | 203 | # Check if the GAIA ID exists because in some cases there isn't a CHOOSE_AUTH_METHOD_XPATH element, 204 | # but still the GAIA ID can be found. 205 | gaia_id = FindGAIAID(driver) 206 | exit_peacefully( 207 | driver, 208 | "Poor internet connection...\nUsing --sleep 20 (or higher) might help", 209 | ) 210 | 211 | # Find GAIA ID. 212 | gaia_id = FindGAIAID(driver) 213 | print(f"GAIA ID: {gaia_id}") 214 | 215 | # Get the full name of the owner of the gmail account. 216 | print(f"Full Name: {GetNameByGAIAID(driver, gaia_id)}") 217 | 218 | c = 1 219 | for address in GetAdressOfReviews(driver): 220 | print(f"Address {c}: {address[0]}") 221 | print(f"Time Taken {c}: {address[1]}\n") 222 | c += 1 223 | 224 | # Close the browser peacefully. 225 | driver.close() 226 | 227 | 228 | if __name__ == "__main__": 229 | main() 230 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GmailOSINT 2 | Use Google services to gather details on an owner of a google account.
3 | Created for research purposes only. Don't use it on someone other than yourself. 4 | 5 | # What it does? 6 | Recieve phone number or gmail address.
7 | Returns: 8 | 1. GAIA ID 9 | 2. Full Name 10 | 3. Addresses the account posted reviews on. 11 | 4. Times the reviews taken. 12 | 13 | ## Warning! 14 | It can sometimes pop a 2FA screen on the victim's phone, dependent on user's configuration.
15 | So Do not use it on other people. Only yourself. 16 | 17 | # Installation 18 | ``` 19 | git clone https://github.com/Shakedash-dev/GmailOSINT.git & cd GmailOSINT 20 | pip install requirements.txt 21 | ``` 22 | Can also be compiled using pyinstaller. 23 | 24 | # Usage 25 | ``` 26 | python3 GmailOSINT.py john.doe@gmail.com 27 | python3 GmailOSINT.py +12345678901 28 | ``` 29 | Can use `--sleep 20` or higher if the connection is slow. 30 | 31 | # Example 32 | ![GmailOSINT POC](https://github.com/Shakedash-dev/GmailOSINT/blob/main/Example.png) 33 | 34 | 35 | # Tested on 36 | Windows 11, Python3.10.0 37 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | undetected-chromedriver 2 | selenium --------------------------------------------------------------------------------