├── .github └── workflows │ └── python-publish.yml ├── LICENSE ├── README.md ├── config_keys.yaml ├── requirements.txt ├── setup.py └── subdominator ├── __init__.py └── subdominator.py /.github/workflows/python-publish.yml: -------------------------------------------------------------------------------- 1 | name: Release to PyPI 2 | 3 | on: 4 | 5 | release: 6 | 7 | types: 8 | - created 9 | 10 | jobs: 11 | 12 | deploy: 13 | 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | 18 | - name: Check out code 19 | 20 | uses: actions/checkout@v2 21 | 22 | 23 | - name: Set up Python 24 | 25 | uses: actions/setup-python@v2 26 | 27 | with: 28 | 29 | python-version: 3.x # Choose your Python version 30 | 31 | - name: Install dependencies 32 | run: | 33 | python3 -m pip install --upgrade pip 34 | pip install setuptools wheel twine 35 | 36 | - name: Build and publish 37 | run: | 38 | python3 setup.py sdist bdist_wheel 39 | python3 -m twine upload dist/*.tar.gz 40 | env: 41 | 42 | TWINE_USERNAME: ${{ secrets.PYPI_USER }} 43 | 44 | TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }} 45 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Sanjai kumar 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Subdominator - Unleash the Power of Subdomain Enumeration 2 | 3 | Subdominator is a powerful tool for passive subdomain enumeration during bug hunting and reconnaissance processes. It is designed to help researchers and cybersecurity professionals discover potential security vulnerabilities by efficiently enumerating subdomains. 4 | 5 | ### Latest release Installation: 6 | 7 | #### Method 1: 8 | 9 | ```bash 10 | 11 | git clone https://github.com/sanjai-AK47/Subdominator.git 12 | 13 | pip install git+https://github.com/sanjai-AK47/Subdominator.git 14 | 15 | subdominator -h 16 | 17 | ``` 18 | copy the config_keys.yaml configuration file from Subdominator github repository if you dont have in your machiene 19 | 20 | ## Dont Worry if the above installation failed there another method also there for you 21 | 22 | #### Method2: 23 | 24 | ```bash 25 | git clone https://github.com/sanjai-AK47/Subdominator.git 26 | cd Subdominator 27 | pip install . 28 | subdominator -h 29 | 30 | ``` 31 | 32 | ### Update to latest version: 33 | ```bash 34 | pip install git+https://github.com/sanjai-AK47/Subdominator.git 35 | ``` 36 | 37 | ### Features Of Subdominator Version1.0.6 38 | 39 | - Subdominator OSINT mode has been enhanced and improved which will give more results than previous versions 40 | - Subdominator Supports stdout 41 | - Subdominator notification results are improved 42 | 43 | 44 | ### Oneliners with Subdominator: 45 | 46 | Subdominator new features is it supports the onliners with other tools of [projectdiscovery](https://github.com/projectdiscovery) and My tools [Subprober](https://github.com/sanjai-AK47) to improver your reconnassaince with efficiently 47 | 48 | ```bash 49 | subdominator -d apple.com -o subdominator_subdomains.txt -cf | httprober -c 50 | subprober --verbose --title --server --application-type --word-count -c 20 -o subprober.txt --silent -sp 50 | ``` 51 | 52 | Result Images: 53 | 54 |  55 | 56 | 57 | ### ALL Users Insatllation: 58 | 59 | ```bash 60 | 61 | git clone https://github.com/sanjai-AK47/Subdominator.git 62 | 63 | cd SubDominator 64 | 65 | pip install subdominator or pip install . 66 | 67 | subdominator -h 68 | ``` 69 | 70 | 71 | ## Subdominator Usage: 72 | 73 | ``` yaml 74 | 75 | 76 | [DESCRIPTION]: Subdominator is a subdomain enumeration tool that discovers subdomains by Free ! open source and API resources 77 | 78 | [USAGE]: 79 | 80 | subdominator [flags] 81 | 82 | [FLAGS]: 83 | 84 | 85 | -h, --help : This flag will show this help message and exits. 86 | 87 | -d, --domain : Specify a domain name for Subdominator to collect subdomains. 88 | 89 | -dL, --domains-list : Specify a file name for Subdominator to collect subdomains. 90 | 91 | -o, --output : Specify a filename to save the subdomain enumeration results. 92 | 93 | -cf, --config : Switching config flag will initiate Subdominator's Config mode (default mode: OSINT). 94 | 95 | -nt, --notify : Swtiching notify flag will enable the subdominator to send the results via notification. 96 | 97 | -vrs, --version : Switching version flag will show the subdominator current vesion and exits. 98 | 99 | -r, --recursive : Switching recursive flag will enumerate the subdomains which has wild cards. 100 | 101 | -ske, --show-key-error : Switching this flag will show the api key errors if user didn't give keys or keys usage exhausts. 102 | 103 | -sre, --show-req-error : Switching this flag will show the sources which are unable to reach for subdomain enumeraion. 104 | 105 | [NOTE]: 106 | 107 | - Subdominator resultings will be Excellent! when your's api key configuration are well 108 | 109 | - If you didn't want to run in config mode then don't give -cf or --config flag without API key configurations 110 | 111 | - To see the resources for API keys configuration please see here --> https://github.com/sanjai-AK47/Subdominator 112 | 113 | - If you have any errors in installation or facing errors in subdominator please report here --> https://github.com/sanjai-AK47/Subdominator 114 | 115 | - Hope you like the Subdominator, if you like this open source project 🔥, Then a give a ⭐ here --> https://github.com/sanjai-AK47/Subdominator 116 | 117 | - Want to contribute some sources or connect with me? then ping me here --> https://www.linkedin.com/in/d-sanjai-kumar-109a7227b 118 | 119 | ``` 120 | 121 | [INFO]: Enabling the notification flag will send the subdominator results via notification 122 | 123 | 124 | ## Dont forget to configure your yaml file with api keys: 125 | 126 | 127 | ## Setup for Notification !: 128 | 129 | Set up a Pushbullet account on your PC and Phone 130 | 131 | For PC 132 | 133 | Go to [Pushbullet.com](https://www.pushbullet.com/) 134 | 135 | Create an account 136 | 137 | Get a api key and paste in Pushbullet-Notify in configuration yaml file 138 | 139 | Add the extension to your PC with the Pushbullet Extension regarding to your browser 140 | 141 | For Android | IOS 142 | 143 | Install the Pushbullet app on your phone. 144 | 145 | Log in using the same email address that you used to log in to your PC !. 146 | 147 | 148 | ### V1.0.5 yaml file: 149 | 150 | ```yaml 151 | Virustotal: #Unlimited keys [Note]: Users follow my instruction and syntax as same if u want add 1 or more keys for particular api services for this configuration file and Thankyou! 152 | 153 | - #Insert your Virustotal API key here 154 | 155 | Chaos: #Unlimited keys 156 | 157 | - # Insert your Chaos API key here 158 | 159 | Dnsdumpter: #Unlimited keys and tokens 160 | 161 | 162 | - # Csrf_Cookie:Csrf_Token 163 | 164 | Whoisxml: #Unlimited keys 165 | 166 | - # Insert your Whoisxml API key here 167 | 168 | SecurityTrails: #Unlimited keys 169 | 170 | - # Insert your SecurityTrails API key here 171 | 172 | Bevigil: #Unlimited keys 173 | 174 | - # Insert your Bevigil API keys 175 | 176 | Binaryedge: #Unlimited keys 177 | 178 | - # Insert your Binaryedge API key here 179 | 180 | Rapidapi: #Unlimited keys 181 | 182 | - # Insert your Rapidapi API key here 183 | 184 | Redhunt: #Unlimited keys 185 | 186 | - # Insert your Redhunt API key here 187 | 188 | Bufferover: #Unlimited keys 189 | 190 | - # Insert your Bufferover API key here 191 | 192 | Certspotter: #Unlimited keys 193 | 194 | - # Insert your Certspotter API key here 195 | 196 | Censys: #Unlimited censys-id and key as you want 197 | 198 | - # Censys_API_ID:Censys_Secret_Token 199 | 200 | Fullhunt: #Unlimited keys 201 | 202 | - # Insert your Fullhunt API key here 203 | 204 | Leakix: #Unlimited keys 205 | 206 | - # Insert your Leakix API key here 207 | 208 | Netlas: #Unlimited keys 209 | 210 | - # Insert your Netlas API key here 211 | 212 | Shodan: #Unlimited keys 213 | - Insert your Shodan API key here 214 | 215 | Hunter: #Unlimited keys 216 | - Insert your Hunterhow API key here 217 | 218 | Zoomeye-API: #Unlimited keys 219 | 220 | - # Insert your Zoomeye API key here 221 | 222 | Zoomeye-Auth: #Unlimited as u want 223 | 224 | - # your_zoomeye_email:your_zoomeye_password 225 | 226 | Pushbullet-Notify: #limited keys is enough for pushbullet 227 | 228 | - # Insert your Pushbullet Notify key here 229 | ``` 230 | 231 | #### Please make sure to replace `#your_api_key_here` with the respective API keys and replace the `email` with your api email and `password` api passoword you obtain from the corresponding websites. 232 | 233 | ### Set the Unlimited api keys Where its commented can holds Unlimited api keys 234 | 235 | ## Update your yaml file if you are existing user: 236 | 237 | ```yaml 238 | 239 | Shodan: #Unlimited keys 240 | - Insert your Shodan API key here 241 | 242 | 243 | Hunter: #Unlimited keys 244 | - Insert your Hunterhow API key here 245 | 246 | ``` 247 | 248 | 249 | ## Example API keys setup: 250 | 251 | ```yaml 252 | [Note]: Users follow my instruction and syntax as same if u want add 1 or more keys for particular api services for this configuration file and Thankyou! 253 | 254 | Dnsdumpter: #Unlimited keys and tokens 255 | 256 | - zsdqYb0rvIVYh2uPHo5Yk4EljV9GEK3579fdg70s9dflW37Q5pZl8pvQHUHWav:Z488dfiasugf89692356bRfLyBxuTytPjA17aa2yA5ULO8HySZoG6ptOKoY 257 | 258 | 259 | Redhunt: #Unlimited keys 260 | 261 | - VRp7HK3jWiRSnpPHo2rDWp09078074tv 262 | 263 | Censys: #Unlimited censys-id and key as you want 264 | 265 | - d573246-2343e-4072344-8773249-174cd6a0:Rdf2rII6cqkQ93425934KfZzzJ2q 266 | 267 | 268 | Zoomeye-Auth: #Unlimited as u want 269 | 270 | - yourZoomeyeMail@gmail.com:ZoomeyePassword 271 | 272 | 273 | ``` 274 | 275 | [INFO]: To check your configuration file syntax is right check [here](https://onlineyamltools.com/validate-yaml) by pasting your config_keys.yaml file to avoid yaml keys arrangements and syntax errors 276 | 277 | [INFO]: Observe the change that for token, cookie, censys id and api, zoomeye auths are now changed so we can store unlimited keys and configuration and it will make easy and no more configuration after that . Which means spending time with configuration of api keys helps you in future 278 | 279 | 280 | ### API Integrations and Credits 281 | 282 | Subdominator integrates with various APIs to gather valuable subdomain information. We would like to give credit to the following websites for providing free-to-obtain API keys for subdomain enumeration. 283 | Claim your free API keys here: 284 | 285 | - **VirusTotal**: [VirusTotal](https://www.virustotal.com) 286 | - **Chaos**: [Chaos](https://chaos.projectdiscovery.io) 287 | - **Dnsdumpter**: [Dnsdumpster](https://dnsdumpster.com) 288 | - **Whoisxml**: [WhoisXML](https://whois.whoisxmlapi.com) 289 | - **SecurityTrails**: [SecurityTrails](https://securitytrails.com) 290 | - **Bevigil**: [Bevigil](https://bevigil.com/) 291 | - **Binaryedge**: [BinaryEdge](https://binaryedge.io) 292 | - **Fullhunt**: [Fullhunt](https://fullhunt.io) 293 | - **Rapidapi**: [RapidAPI](https://rapidapi.com) 294 | - **Bufferover**: [Bufferover](https://tls.bufferover.run/) 295 | - **Certspotter**: [Certspotter](https://sslmate.com/certspotter) 296 | - **Censys**: [Censys](https://search.censys.io/) 297 | - **Fullhunt**: [Fullhunt](https://fullhunt.io/) 298 | - **Zoomeye**: [Zoomeye](https://www.zoomeye.org/) 299 | - **Netlas**: [Netlas](https://netlas.io/) 300 | - **Leakix**: [Leakix](https://leakix.net/) 301 | - **Redhunt**: [Redhunt](https://https://devportal.redhuntlabs.com/) 302 | - **Shodan** : [Shodan](https://shodan.io) 303 | - **HunterHow** : [Hunter](https://hunter.how/) 304 | 305 | 306 | ### Dnsdumpter: 307 | 308 | Dnsdumpster requires csrf token and cookie to obtain it visit **Dnsdumpter**: [Dnsdumpster](https://dnsdumpster.com) 309 | 310 | Search any domain and Intercept the requests your burp that contains token and cookie. Copy that and paste in your yaml file 311 | 312 | 313 |  314 | 315 | ## Information: 316 | 317 | Subdominator a Subdomain enumeration tool builded for bug hunters and pentesters and other Cybersecurity people, it mainly builded for information gathering purpose 318 | so [I'm](https://www.linkedin.com/in/d-sanjai-kumar-109a7227b/) not responsible for any illegal works and also support the Subdominator project with 319 | a ⭐ and show your ❤️ and support guys! 320 | Happy Hacking with Subdominator! If you have any suggestions or feedback, feel free to contribute or open an issue on our GitHub repository: [Subdominator GitHub Repository](https://github.com/sanjai-AK47/Subdominator) or can contact me through [LinkedIN](https://www.linkedin.com/in/d-sanjai-kumar-109a7227b/) for any issues or upgrades 321 | -------------------------------------------------------------------------------- /config_keys.yaml: -------------------------------------------------------------------------------- 1 | Virustotal: #Unlimited keys [Note]: Users follow my instruction and syntax as same if u want add 1 or more keys for particular api services for this configuration file and Thankyou! 2 | 3 | - # Insert you VirusTotal API key 4 | 5 | Chaos: #Unlimited keys 6 | 7 | - # Insert your Chaos API key here 8 | 9 | Dnsdumpter: #Unlimited keys and tokens 10 | 11 | 12 | - # Csrf_Cookie:Csrf_Token 13 | 14 | Whoisxml: #Unlimited keys 15 | 16 | - # Insert your Whoisxml API key here 17 | 18 | SecurityTrails: #Unlimited keys 19 | 20 | - # Insert your SecurityTrails API key here 21 | 22 | Bevigil: #Unlimited keys 23 | 24 | - # Insert your Bevigil API keys 25 | 26 | Binaryedge: #Unlimited keys 27 | 28 | - # Insert your Binaryedge API key here 29 | 30 | Rapidapi: #Unlimited keys 31 | 32 | - # Insert your Rapidapi API key here 33 | 34 | Redhunt: #Unlimited keys 35 | 36 | - # Insert your Redhunt API key here 37 | 38 | Bufferover: #Unlimited keys 39 | 40 | - # Insert your Bufferover API key here 41 | 42 | Certspotter: #Unlimited keys 43 | 44 | - # Insert your Certspotter API key here 45 | 46 | Censys: #Unlimited censys-id and key as you want 47 | 48 | - # Censys_API_ID:Censys_Secret_Token 49 | 50 | Fullhunt: #Unlimited keys 51 | 52 | - # Insert your Fullhunt API key here 53 | 54 | Shodan: #Unlimited keys 55 | 56 | - # Insert your Shodan API key here 57 | 58 | Hunter: 59 | 60 | - # Insert you Hunter.how API key here 61 | 62 | Leakix: #Unlimited keys 63 | 64 | - # Insert your Leakix API key here 65 | 66 | Netlas: #Unlimited keys 67 | 68 | - # Insert your Netlas API key here 69 | 70 | Zoomeye-API: #Unlimited keys 71 | 72 | - # Insert your Zoomeye API key here 73 | 74 | Zoomeye-Auth: #Unlimited as u want 75 | 76 | - # your_zoomeye_email:your_zoomeye_password 77 | 78 | Pushbullet-Notify: #limited keys is enough for pushbullet 79 | 80 | - # Insert your Pushbullet Notify key here 81 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | censys>=2.2.10 2 | colorama>=0.4.6 3 | fake_useragent>=1.2.1 4 | httpx>=0.26.0 5 | plyer>=2.1.0 6 | pywebio>=1.8.2 7 | Requests>=2.31.0 8 | PyYAML>=6.0.1 9 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup, find_packages 2 | 3 | setup( 4 | name='subdominator', 5 | version='1.0.6', 6 | author='D. Sanjai Kumar', 7 | author_email='bughunterz0047@gmail.com', 8 | description='Subdominator - An ultimate subdomain enumeration tool', 9 | packages=find_packages(), 10 | install_requires=[ 11 | 'censys>=2.2.9', 12 | 'colorama>=0.4.6', 13 | 'httpx>=0.25.1', 14 | 'plyer>=2.1.0', 15 | 'fake_useragent>=1.2.1', 16 | 'pywebio>=1.8.2', 17 | 'requests>=2.31.0', 18 | 'argparse>=1.4.0', 19 | 'PyYAML>=6.0.1' 20 | ], 21 | entry_points={ 22 | 'console_scripts': [ 23 | 'subdominator = subdominator.subdominator:main' 24 | ] 25 | }, 26 | ) 27 | -------------------------------------------------------------------------------- /subdominator/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aashishsec/Subdominator/06e18a7a8838bed71f9db2c1956ffc0e977c4302/subdominator/__init__.py -------------------------------------------------------------------------------- /subdominator/subdominator.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | import httpx 3 | import pywebio 4 | import requests 5 | from colorama import Fore,Back,Style 6 | import argparse 7 | import yaml 8 | import time as t 9 | import re 10 | import random 11 | import logging 12 | import datetime 13 | import os 14 | from plyer import notification 15 | import sys 16 | from censys.search import CensysCerts 17 | import concurrent.futures 18 | from censys.common.exceptions import CensysUnauthorizedException, CensysRateLimitExceededException,CensysException 19 | from fake_useragent import UserAgent 20 | import base64 21 | from datetime import datetime, timedelta 22 | import datetime as dt 23 | 24 | logging.basicConfig(level=logging.INFO, format="%(message)s") 25 | 26 | logging.getLogger("httpx").setLevel(logging.WARNING) 27 | 28 | logging.getLogger("requests").setLevel(logging.WARNING) 29 | 30 | red = Fore.RED 31 | 32 | green = Fore.GREEN 33 | 34 | magenta = Fore.MAGENTA 35 | 36 | cyan = Fore.CYAN 37 | 38 | mixed = Fore.RED + Fore.BLUE 39 | 40 | blue = Fore.BLUE 41 | 42 | yellow = Fore.YELLOW 43 | 44 | white = Fore.WHITE 45 | 46 | reset = Style.RESET_ALL 47 | 48 | bold = Style.BRIGHT 49 | 50 | colors = [ green, cyan, blue] 51 | 52 | random_color = random.choice(colors) 53 | 54 | 55 | 56 | 57 | banner = f"""{bold} 58 | 59 | _____ __ ____ _ ______ 60 | / ___/__ __/ /_ / __ \____ ____ ___ (_)___ ____ /_ __/___ _____ 61 | \__ \/ / / / __ \/ / / / __ \/ __ `__ \/ / __ \/ __ `// / / __ \/ ___/ 62 | ___/ / /_/ / /_/ / /_/ / /_/ / / / / / / / / / / /_/ // / / /_/ / / 63 | /____/\__,_/_.___/_____/\____/_/ /_/ /_/_/_/ /_/\__,_//_/ \____/_/ 64 | 65 | 66 | {bold}{white}Author : D.Sanjai Kumar @CyberRevoltSecurities 67 | 68 | 69 | {reset}""" 70 | 71 | 72 | subdomains_list = [] 73 | 74 | 75 | 76 | start = t.time() 77 | 78 | 79 | 80 | 81 | #creating new and old arguments to pass values: 82 | 83 | parser = argparse.ArgumentParser(add_help=False) 84 | 85 | parser.add_argument("-h", "--help", action="store_true") 86 | 87 | parser.add_argument("-d", "--domain", type=str) 88 | 89 | parser.add_argument("-dL", "--domains-list", type=str) 90 | 91 | parser.add_argument("-nt", "--notify", action="store_true") 92 | 93 | parser.add_argument("-r", "--recursive", action="store_true") 94 | 95 | parser.add_argument("-vrs", "--version", action="store_true") 96 | 97 | parser.add_argument("-cf", "--config", action="store_true") 98 | 99 | parser.add_argument("-ske", "--show-key-error", action="store_true") 100 | 101 | parser.add_argument("-sre", "--show-req-error", action="store_true") 102 | 103 | parser.add_argument("-o", "--output",type=str) 104 | 105 | args=parser.parse_args() 106 | 107 | list = args.domains_list 108 | 109 | domain = args.domain 110 | 111 | config = args.config 112 | 113 | recursive = args.recursive 114 | 115 | version = args.version 116 | 117 | notify = args.notify 118 | 119 | output = args.output 120 | 121 | 122 | # get the latest version when given domains or domain 123 | def check_version(): 124 | 125 | version = "v1.0.6" 126 | 127 | url = f"https://api.github.com/repos/sanjai-AK47/Subdominator/releases/latest" 128 | 129 | try: 130 | 131 | response = requests.get(url) 132 | 133 | if response.status_code == 200: 134 | 135 | data = response.json() 136 | 137 | latest = data.get('tag_name') 138 | 139 | if latest == version: 140 | 141 | 142 | logging.info(f"[{bold}{bold}{blue}Version{reset}]: {bold}{white}Subdominator current version {version}{reset} ({bold}{green}latest{reset})") 143 | 144 | t.sleep(1) 145 | 146 | 147 | else: 148 | 149 | logging.info(f"[{bold}{bold}{blue}Version{reset}]: {bold}{white}Subdominator current version {version}{reset} ({bold}{red}outdated{reset})") 150 | 151 | logging.info(f"[{bold}{red}ALERT{reset}]: {bold}{white}Subdominator new version detected update to latest version!{reset}") 152 | 153 | t.sleep(1) 154 | 155 | else: 156 | 157 | pass 158 | 159 | except Exception as e: 160 | 161 | pass 162 | 163 | 164 | 165 | #Customised help 166 | def subdominator_help(): 167 | 168 | print(f""" 169 | {bold}{random_color}{banner}{reset} 170 | """) 171 | 172 | check_version() 173 | 174 | print(f""" 175 | 176 | {bold}{white}[{reset}{bold}{blue}DESCRIPTION{reset}{bold}{white}]{reset}: {bold}{white}Subdominator is a subdomain enumeration tool that discovers subdomains by Free ! open source and API resources{reset} 177 | 178 | {bold}{white}[{reset}{bold}{blue}USAGE{reset}{bold}{white}]{reset}: {bold}{white} 179 | 180 | subdominator [flags]{reset} 181 | 182 | {bold}{white}[{reset}{bold}{blue}FLAGS{reset}{bold}{white}]{reset}: {bold}{white} 183 | 184 | 185 | -h, --help : This flag will show this help message and exits. 186 | 187 | -d, --domain : Specify a domain name for Subdominator to collect subdomains. 188 | 189 | -dL, --domains-list : Specify a file name for Subdominator to collect subdomains. 190 | 191 | -o, --output : Specify a filename to save the subdomain enumeration results. 192 | 193 | -cf, --config : Switching config flag will initiate Subdominator's Config mode (default mode: OSINT). 194 | 195 | -nt, --notify : Swtiching notify flag will enable the subdominator to send the results via notification. 196 | 197 | -vrs, --version : Switching version flag will show the subdominator current vesion and exits. 198 | 199 | -r, --recursive : Switching recursive flag will enumerate the subdomains which has wild cards. 200 | 201 | -ske, --show-key-error : Switching this flag will show the api key errors if user didn't give keys or keys usage exhausts. 202 | 203 | -sre, --show-req-error : Switching this flag will show the sources which are unable to reach for subdomain enumeraion. 204 | 205 | [{bold}{blue}NOTE{reset}]: {bold}{white} 206 | 207 | - Subdominator resultings will be Excellent! when your's api key configuration are well 208 | 209 | - If you didn't want to run in config mode then don't give -cf or --config flag without API key configurations 210 | 211 | - To see the resources for API keys configuration please see here --> https://github.com/sanjai-AK47/Subdominator 212 | 213 | - If you have any errors in installation or facing errors in subdominator please report here --> https://github.com/sanjai-AK47/Subdominator 214 | 215 | - Hope you like the Subdominator, if you like this open source project 🔥, Then a give a ⭐ here --> https://github.com/sanjai-AK47/Subdominator 216 | 217 | - Want to contribute some sources or connect with me? then ping me here --> https://www.linkedin.com/in/d-sanjai-kumar-109a7227b 218 | """) 219 | 220 | quit() 221 | 222 | 223 | #======================================================Notifier============================================================================================================== 224 | 225 | #notify works good 226 | 227 | def notify(subdomains): 228 | 229 | 230 | try: 231 | 232 | 233 | with open(filename, "r") as keys: 234 | 235 | data = yaml.safe_load(keys) 236 | 237 | push_key = random.choice(data.get("Pushbullet-Notify", [])) 238 | 239 | 240 | if push_key is None : 241 | 242 | if args.show_key_error: 243 | 244 | logging.info(f"[{bold}{red}ALERT{reset}]: There is no api keys found for Notification, Subdominator will not send any notification") 245 | 246 | return 247 | 248 | else: 249 | 250 | pass 251 | 252 | try: 253 | 254 | noti = [] 255 | 256 | for subdomain in subdomains: 257 | 258 | noti.append(subdomain) 259 | 260 | url = f'https://api.pushbullet.com/v2/pushes' 261 | 262 | body = '\n'.join(noti) 263 | 264 | headers = { 265 | 'Access-Token': push_key, 266 | 267 | 'Content-Type': 'application/json' 268 | } 269 | data = { 270 | 'type': 'note', 271 | 'title': f"Subdominator Notify ⚡", 272 | 'body': f"{body}\n Total Subdomains Found: {len(subdomains)}" 273 | } 274 | 275 | try: 276 | 277 | with httpx.Client() as client: 278 | 279 | response = client.post(url, json=data, headers=headers, timeout=10) 280 | 281 | 282 | except httpx.HTTPError as e: 283 | 284 | if args.show_req_error: 285 | 286 | logging.info(f'[{bold}{red}INFO{reset}]: {bold}{white}Error occured when sending notification to you due to: {e}{reset}') 287 | 288 | 289 | except Exception as e: 290 | 291 | if args.show_req_error: 292 | 293 | logging.info(f"[{bold}{red}ALERT{reset}]: PushBullet blocking our requests to send notification to you") 294 | 295 | 296 | except yaml.YAMLError as e: 297 | 298 | logging.info(f"[{bold}{red}ALERT{reset}]: Please Check that You didnt messed up the Cofiguration files variables and it Values of Pushbullet-notify") 299 | 300 | except Exception as e: 301 | 302 | logging.info(f"[{bold}{red}ALERT{reset}]: Subdominator met with an Unknown Error due to: {e}") 303 | 304 | 305 | # get unique subdomains for file that contains list of domains 306 | 307 | def list_unique_subdomains(subdomains, domain): 308 | 309 | 310 | 311 | unique_subdomains = sorted(set(subdomains)) 312 | 313 | 314 | 315 | for subdomain in unique_subdomains: 316 | 317 | if subdomain.endswith(f".{domain}") : 318 | 319 | 320 | print(f"{subdomain}") 321 | 322 | 323 | if args.output: 324 | 325 | if os.path.isfile(args.output): 326 | 327 | filename = args.output 328 | 329 | elif os.path.isdir(args.output): 330 | 331 | filename = os.path.join(args.output, f"{domain}.subdomains.txt") 332 | 333 | else: 334 | 335 | filename = args.output 336 | 337 | if not args.output: 338 | 339 | filename = f"{domain}.subdomains.txt" 340 | 341 | 342 | with open(filename, "a") as w: 343 | 344 | w.write(subdomain + '\n') 345 | 346 | total = len(unique_subdomains) 347 | 348 | end = t.time() 349 | 350 | temp_time = end - start 351 | 352 | if temp_time > 60: 353 | 354 | total_time_taken = temp_time/60 355 | 356 | logging.info(f"[{bold}{blue}INFO{reset}]: Total subdomains found {total} in {total_time_taken:.2f} minutes ") 357 | 358 | elif temp_time < 60: 359 | 360 | total_time_taken = temp_time 361 | 362 | logging.info(f"[{bold}{blue}INFO{reset}]: Total subdomains found {total} in {total_time_taken:.2f} seconds ") 363 | 364 | logging.info(f"[{bold}{blue}INFO{reset}]: Output for {domain} save in {filename}") 365 | 366 | logging.info(f"[{bold}{green}WISH{reset}]: Happy Hacking Hacker ☠️ 🔥 🚀") 367 | 368 | if args.notify: 369 | 370 | notify(unique_subdomains) 371 | 372 | subdomains_list.clear() 373 | 374 | #get unique subdomains for single domain 375 | 376 | def single_unique_subdomains(subdomains, domain): 377 | 378 | unique_subdomains = sorted(set(subdomains)) 379 | 380 | for subdomain in unique_subdomains: 381 | 382 | 383 | print(f"{subdomain}") 384 | 385 | 386 | if args.output: 387 | 388 | if os.path.isfile(args.output): 389 | 390 | filename = args.output 391 | 392 | elif os.path.isdir(args.output): 393 | 394 | filename = os.path.join(args.output, f"{domain}.subdomains.txt") 395 | 396 | else: 397 | 398 | filename = args.output 399 | 400 | if not args.output: 401 | 402 | filename = f"{domain}.subdomains.txt" 403 | 404 | 405 | with open(filename, "a") as w: 406 | 407 | w.write(subdomain + '\n') 408 | 409 | total = len(unique_subdomains) 410 | 411 | end = t.time() 412 | 413 | temp_time = end - start 414 | 415 | if temp_time > 60: 416 | 417 | total_time_taken = temp_time/60 418 | 419 | logging.info(f"[{bold}{blue}INFO{reset}]: Total {total} subdomains found for {args.domain} in {total_time_taken:.2f} minutes ") 420 | 421 | elif temp_time < 60: 422 | 423 | total_time_taken = temp_time 424 | 425 | logging.info(f"[{bold}{blue}INFO{reset}]: Total {total} subdomains found for {args.domain} in {total_time_taken:.2f} seconds ") 426 | 427 | 428 | logging.info(f"[{bold}{blue}INFO{reset}]: Output for {args.domain} save in {filename}") 429 | 430 | logging.info(f"[{bold}{green}WISH{reset}]: Happy Hacking Hacker ☠️ 🔥 🚀") 431 | 432 | if args.notify: 433 | 434 | notify(unique_subdomains) 435 | 436 | 437 | 438 | 439 | #check for user config 440 | def check_config_file(): 441 | 442 | filename = "config_keys.yaml" 443 | 444 | path = "/" 445 | 446 | for root,dirs,files in os.walk(path): 447 | 448 | if filename in files: 449 | 450 | file_path = os.path.join(root, filename) 451 | 452 | logging.info(f"[{bold}{blue}INFO{reset}]: {bold}{white}Loading the configuration file from {file_path}{reset}") 453 | 454 | return file_path 455 | 456 | logging.info(f"[{bold}{red}ALERT{reset}]: {bold}{white}Config File not found please kindly install the Subdomiantor with its {filename} file{reset}") 457 | 458 | exit() 459 | 460 | 461 | #=================================================================================API calls here======================================================================================================================================== 462 | 463 | #virustotal works good with random api keys 464 | def api_virustotal(domain, filename): 465 | 466 | try: 467 | 468 | with open (filename, "r") as keys: 469 | 470 | data = yaml.safe_load(keys) 471 | 472 | 473 | 474 | virus_key = random.choice(data.get("Virustotal", [])) 475 | 476 | 477 | 478 | if virus_key is None: 479 | 480 | if args.show_key_error: 481 | 482 | logging.info(f"[{bold}{red}ALERT{reset}]: There is no api keys found for VirusTotal ") 483 | 484 | return 485 | 486 | else: 487 | 488 | pass 489 | 490 | try: 491 | 492 | url = f"https://www.virustotal.com/vtapi/v2/domain/report?apikey={virus_key}&domain={domain}" 493 | 494 | with httpx.Client() as requests: 495 | 496 | response = requests.get(url, timeout=10) 497 | 498 | if response.status_code == 200: 499 | 500 | data = response.json() 501 | 502 | if 'subdomains' in data: 503 | 504 | subdomains = data['subdomains'] 505 | 506 | for subdomain in subdomains: 507 | 508 | subdomains_list.append(subdomain) 509 | 510 | 511 | 512 | else: 513 | logging.info(f"[{bold}{red}ALERT{reset}]: VirusTotal Unable to find subdomains for {domain}") 514 | 515 | 516 | 517 | 518 | 519 | else: 520 | 521 | logging.info(f"[{bold}{red}ALERT{reset}]: VirusTotal blocking our requests Check your api usage: {virus_key}") 522 | 523 | except Exception as e: 524 | 525 | if args.show_req_error: 526 | 527 | logging.info (f"[{red}Alert{reset}]: Virustotal Blocking our requests") 528 | 529 | except yaml.YAMLError as e: 530 | 531 | logging.info(f"[{bold}{red}ALERT{reset}]: Please Check that You didnt messed up the Cofiguration files variables and it Values of VirusTotal") 532 | 533 | pass 534 | 535 | except Exception as e: 536 | 537 | logging.info(f"[{bold}{red}ALERT{reset}]: Subdominator met with an Unknown Error due to: {e}") 538 | 539 | 540 | 541 | 542 | 543 | #Chaos works good 544 | 545 | def api_chaos(domain, filename): 546 | 547 | try: 548 | 549 | with open(filename, "r") as key: 550 | 551 | data = yaml.safe_load(key) 552 | 553 | 554 | 555 | chaos_api_key = random.choice(data.get('Chaos', [])) 556 | 557 | if chaos_api_key is None: 558 | 559 | if args.show_key_error: 560 | 561 | logging.info(f"[{bold}{red}ALERT{reset}]: There is no api keys found for Chaos ") 562 | 563 | return 564 | 565 | 566 | else: 567 | 568 | pass 569 | 570 | url = f"https://dns.projectdiscovery.io/dns/{domain}/subdomains" 571 | 572 | headers= { 573 | 'Authorization': chaos_api_key 574 | } 575 | 576 | try: 577 | 578 | with httpx.Client() as requests: 579 | 580 | response = requests.get(url,headers=headers, timeout=15) 581 | 582 | if response.status_code == 200: 583 | 584 | data = response.json() 585 | 586 | if 'subdomains' in data: 587 | 588 | subdomains = data['subdomains'] 589 | 590 | for subdomain in subdomains: 591 | 592 | if not subdomain.endswith(f".{domain}"): 593 | 594 | subdomains_list.append(f"{subdomain}.{domain}") 595 | 596 | else: 597 | 598 | subdomains_list.append(f"{subdomain}") 599 | 600 | else: 601 | 602 | pass 603 | 604 | 605 | else: 606 | 607 | logging.info(f"[{bold}{red}ALERT{reset}]: Chaos blocking our requests check your api usage {chaos_api_key} ") 608 | 609 | 610 | 611 | except Exception as e: 612 | 613 | if args.show_req_error: 614 | 615 | logging.info(f"[{bold}{red}ALERT{reset}]: Chaos Blocking our requests") 616 | 617 | except Exception as e: 618 | 619 | logging.info(f"[{bold}{red}ALERT{reset}]: Please Check that You didnt messed up the Cofiguration files variables and it Values of Chaos") 620 | 621 | return 622 | 623 | 624 | #whoisxml works good 625 | 626 | 627 | def whoisxml_api(domain, filename): 628 | 629 | try: 630 | 631 | with open(filename, "r") as key: 632 | 633 | data = yaml.safe_load(key) 634 | 635 | 636 | whois_api_key = random.choice(data.get('Whoisxml', [])) 637 | 638 | if whois_api_key is None: 639 | 640 | if args.show_key_error: 641 | 642 | logging.info(f"[{bold}{red}ALERT{reset}]: There is no api keys found for whoisxml api ") 643 | 644 | pass 645 | else: 646 | 647 | pass 648 | 649 | 650 | 651 | try: 652 | 653 | url = f"https://subdomains.whoisxmlapi.com/api/v1?apiKey={whois_api_key}&domainName={domain}" 654 | 655 | 656 | with httpx.Client() as requests: 657 | 658 | response = requests.get(url, timeout=10) 659 | 660 | if response.status_code == 200: 661 | 662 | data = response.json() 663 | 664 | subdomains = data.get('result', {}).get('records', []) 665 | 666 | for subdomain in subdomains: 667 | 668 | subdomain_name = subdomain.get('domain') 669 | 670 | if subdomain_name: 671 | 672 | subdomains_list.append(subdomain_name) 673 | 674 | else: 675 | 676 | pass 677 | else: 678 | 679 | logging.info(f"[{bold}{red}ALERT{reset}]: Whoisxmlapi blocking our request check your api usage {whois_api_key}") 680 | 681 | except Exception as e: 682 | 683 | if args.show_req_error: 684 | 685 | logging.info(f"[{bold}{red}ALERT{reset}]: Whoisxmlapi blocking our request") 686 | 687 | 688 | except yaml.YAMLError as e: 689 | 690 | logging.info(f"[{bold}{red}ALERT{reset}]: Please Check that You didnt messed up the Cofiguration files variables and it Values of Whoisxml") 691 | 692 | 693 | except Exception as e: 694 | 695 | logging.info(f"[{bold}{red}ALERT{reset}]: Subdominator met with an Unknown Error due to: {e}") 696 | 697 | 698 | 699 | #security trails works good now 700 | def api_securitytrails(domain, filename): 701 | 702 | try: 703 | 704 | with open(filename, "r") as key: 705 | 706 | data = yaml.safe_load(key) 707 | 708 | 709 | security_api_key = random.choice(data.get('SecurityTrails', [])) 710 | 711 | if security_api_key is None: 712 | 713 | if args.show_key_error: 714 | 715 | logging.info(f"[{bold}{red}ALERT{reset}]: There is no api keys found for SecurityTrails ") 716 | 717 | return 718 | else: 719 | 720 | pass 721 | 722 | 723 | try: 724 | 725 | url = f"https://api.securitytrails.com/v1/domain/{domain}/subdomains?children_only=false&include_inactive=true" 726 | 727 | headers = { 728 | "accept": "application/json", 729 | "APIKEY": security_api_key 730 | } 731 | 732 | 733 | with httpx.Client() as requests: 734 | 735 | response = requests.get(url , headers=headers, timeout=10) 736 | 737 | if response.status_code == 200: 738 | 739 | data = response.json() 740 | 741 | subdomains = data.get("subdomains", []) 742 | 743 | for subdomain in subdomains: 744 | 745 | subdomains_list.append(f"{subdomain}.{domain}") 746 | 747 | elif response.status_code == 429: 748 | 749 | logging.info(f"[{bold}{red}ALERT{reset}]: SecurityTrails blocking our request check your api usage {security_api_key}") 750 | 751 | else: 752 | 753 | pass 754 | 755 | 756 | except Exception as e: 757 | 758 | if args.show_req_error: 759 | 760 | logging.info(f"[{bold}{red}ALERT{reset}]: SecurityTails blocking our request") 761 | 762 | 763 | 764 | except yaml.YAMLError as e: 765 | 766 | logging.info(f"[{bold}{red}ALERT{reset}]: Please Check that You didnt messed up the Cofiguration files variables and it Values of SecurityTrails") 767 | 768 | 769 | except Exception as e: 770 | 771 | logging.info(f"[{bold}{red}ALERT{reset}]: Subdominator met with an Unknown Error due to: {e}") 772 | 773 | 774 | #bevigil works good 775 | 776 | def api_bevigil(domain, filename): 777 | 778 | try: 779 | 780 | with open(filename, "r") as key: 781 | 782 | data = yaml.safe_load(key) 783 | 784 | bevigil_api_key = random.choice(data.get('Bevigil', [])) 785 | 786 | if bevigil_api_key is None: 787 | 788 | if args.show_key_error: 789 | 790 | logging.info(f"[{bold}{red}ALERT{reset}]: There is no api keys found for Bevigil ") 791 | 792 | return 793 | else: 794 | 795 | pass 796 | 797 | 798 | try: 799 | 800 | 801 | 802 | url = f"http://osint.bevigil.com/api/{domain}/subdomains" 803 | 804 | headers = { 805 | 'X-Access-Token': bevigil_api_key 806 | 807 | } 808 | 809 | 810 | response = requests.get(url, headers=headers, timeout=10) 811 | 812 | 813 | 814 | if response.status_code == 200: 815 | 816 | data = response.json() 817 | 818 | 819 | subdomains = data.get("subdomains", []) 820 | 821 | for subdomain in subdomains: 822 | 823 | subdomains_list.append(subdomain) 824 | 825 | elif response.status_code == 429: 826 | 827 | if args.show_key_error: 828 | 829 | logging.info(f"[{bold}{red}ALERT{reset}]: Bevigil blocking our request check your api usage {bevigil_api_key}") 830 | 831 | else: 832 | 833 | pass 834 | 835 | except Exception as e: 836 | 837 | if args.show_req_error: 838 | 839 | 840 | logging.info(f"[{bold}{red}ALERT{reset}]: Bevigil blocking our request ") 841 | 842 | except yaml.YAMLError as e: 843 | 844 | logging.info(f"[{bold}{red}ALERT{reset}]: Please Check that You didnt messed up the Cofiguration files variables and it Values of Bevigil") 845 | 846 | 847 | except Exception as e: 848 | 849 | logging.info(f"[{bold}{red}ALERT{reset}]: Subdominator met with an Unknown Error due to: {e}") 850 | 851 | 852 | #bufferover 853 | 854 | def api_bufferover(domain,filename): 855 | 856 | try: 857 | with open(filename, "r") as key: 858 | 859 | data = yaml.safe_load(key) 860 | 861 | bufferover_api_key = random.choice(data.get('Bufferover', [])) 862 | 863 | if bufferover_api_key is None: 864 | 865 | if args.show_key_error: 866 | 867 | logging.info(f"[{bold}{red}ALERT{reset}]: There is no api keys found for Bufferover ") 868 | 869 | return 870 | 871 | else: 872 | 873 | pass 874 | 875 | try: 876 | 877 | url = f"http://tls.bufferover.run/dns?q=.{domain}" 878 | 879 | headers = { 880 | 'x-api-key': f'{bufferover_api_key}' 881 | } 882 | 883 | with httpx.Client() as requests: 884 | 885 | response = requests.get(url,headers=headers, follow_redirects=True) 886 | 887 | 888 | if response.status_code == 200: 889 | 890 | data = response.json() 891 | 892 | if 'Results' in data: 893 | 894 | results = data['Results'] 895 | 896 | for result in results: 897 | 898 | elements = result.split(',') 899 | 900 | subdomain = elements[4].strip() 901 | 902 | subdomains_list.append(subdomain) 903 | 904 | elif response.status_code == 500: 905 | 906 | 907 | 908 | logging.info(f"[{bold}{red}INFO{reset}]: Buffer over Internal Error occured") 909 | 910 | else: 911 | 912 | logging.info(f"[{bold}{blue}INFO{reset}]: Bufferover not able to find subdomains for {domain}") 913 | 914 | 915 | except Exception as e: 916 | 917 | if args.show_req_error: 918 | 919 | logging.info(f"[{bold}{red}ALERT{reset}]: Bufferover blocking our requests") 920 | 921 | 922 | except yaml.YAMLError as e: 923 | 924 | logging.info(f"[{bold}{red}ALERT{reset}]: Please Check that You didnt messed up the Cofiguration files variables and it Values of Bufferover") 925 | 926 | 927 | except Exception as e: 928 | 929 | logging.info(f"[{bold}{red}ALERT{reset}]: Subdominator met with an Unknown Error due to: {e}") 930 | 931 | #missInteg binary edge works good 932 | 933 | def api_binaryegde(domain, binaryedge_api_key, page_number, pagesize): 934 | 935 | try: 936 | 937 | url = f"https://api.binaryedge.io/v2/query/domains/subdomain/{domain}?page={page_number}&pagesize={pagesize}" 938 | 939 | headers = { 940 | 'X-Key': f'{binaryedge_api_key}' 941 | } 942 | with httpx.Client() as requests: 943 | 944 | response = requests.get(url, headers=headers, timeout=10) 945 | 946 | if response.status_code == 200: 947 | 948 | data = response.json() 949 | 950 | subdomains = data.get("events", []) 951 | 952 | 953 | if not subdomains: 954 | 955 | 956 | return False 957 | 958 | for subdomain in subdomains: 959 | 960 | subdomains_list.append(subdomain) 961 | 962 | return True 963 | else: 964 | 965 | pass 966 | 967 | except yaml.YAMLError as e: 968 | 969 | logging.info(f"[{bold}{red}ALERT{reset}]: BinaryEdge blocking our requests") 970 | 971 | except Exception as e: 972 | 973 | logging.info(f"[{bold}{red}ALERT{reset}]: Subdominator met with an Unknown Error due to: {e}") 974 | 975 | def send_binaryedge(domain, filepath): 976 | 977 | try: 978 | 979 | with open(filepath, "r") as key: 980 | 981 | data = yaml.safe_load(key) 982 | 983 | binaryedge_api_key = random.choice(data.get('Binaryedge', [])) 984 | 985 | if binaryedge_api_key is None: 986 | 987 | if args.show_key_error: 988 | 989 | logging.info(f"[{bold}{red}ALERT{reset}]: There is no API key found for BinaryEdge ") 990 | 991 | return 992 | else: 993 | 994 | pass 995 | 996 | pagesize = 100 997 | 998 | page_number = 1 999 | 1000 | while True: 1001 | 1002 | if not api_binaryegde(domain, binaryedge_api_key, page_number, pagesize): 1003 | 1004 | break 1005 | 1006 | page_number += 1 1007 | 1008 | t.sleep(1) 1009 | 1010 | except yaml.YAMLError as e: 1011 | 1012 | logging.info(f"[{bold}{red}ALERT{reset}]: Please Check that You didn't mess up the Configuration files variables and their Values of BinaryEdge") 1013 | 1014 | except Exception as e: 1015 | 1016 | logging.info(f"[{bold}{red}ALERT{reset}]: Subdominator met with an Unknown Error due to: {e}") 1017 | 1018 | 1019 | #Certspotter works good 1020 | 1021 | def api_certspoter(domain, filename): 1022 | 1023 | try: 1024 | 1025 | with open(filename,"r") as keys: 1026 | 1027 | data = yaml.safe_load(keys) 1028 | 1029 | certspotter_api_key = random.choice(data.get('Certspotter', [])) 1030 | 1031 | if certspotter_api_key is None: 1032 | 1033 | if args.show_key_error: 1034 | 1035 | logging.info(f"[{bold}{red}ALERT{reset}]: There is no api keys found for Certspotter ") 1036 | 1037 | return 1038 | else: 1039 | 1040 | pass 1041 | 1042 | try: 1043 | 1044 | url = f"https://api.certspotter.com/v1/issuances?domain={domain}&expand=dns_names" 1045 | 1046 | headers = {"Authorization": f"Bearer {certspotter_api_key}"} 1047 | 1048 | with httpx.Client() as requests: 1049 | 1050 | response = requests.get(url, headers=headers, timeout=10) 1051 | 1052 | if response.status_code == 200: 1053 | 1054 | data = response.json() 1055 | 1056 | for entry in data : 1057 | 1058 | dns_names = entry.get('dns_names',[]) 1059 | 1060 | for dns_name in dns_names: 1061 | 1062 | if dns_name.startswith("*.") and dns_name.endswith(f".{domain}"): 1063 | 1064 | subdomain = dns_name[2:] 1065 | 1066 | subdomains_list.append(subdomain) 1067 | 1068 | elif dns_name.endswith(f".{domain}"): 1069 | 1070 | subdomains_list.append(dns_name) 1071 | else: 1072 | pass 1073 | 1074 | elif response.status_code >= 400: 1075 | 1076 | logging.info(f"[{bold}{red}ALERT{reset}]: Certspotter blocking our request check your api usage {certspotter_api_key}") 1077 | 1078 | 1079 | 1080 | else: 1081 | 1082 | pass 1083 | 1084 | except Exception as e: 1085 | 1086 | if args.show_req_error: 1087 | 1088 | logging.info(f"[{bold}{red}ALERT{reset}]: Certspotter blocking our requests") 1089 | 1090 | 1091 | except yaml.YAMLError as e: 1092 | 1093 | logging.info(f"[{bold}{red}ALERT{reset}]: Please Check that You didnt messed up the Cofiguration files variables and it Values of Certspotter") 1094 | 1095 | 1096 | except Exception as e: 1097 | 1098 | logging.info(f"[{bold}{red}ALERT{reset}]: Subdominator met with an Unknown Error due to: {e}") 1099 | 1100 | 1101 | #rapidwhois works execellent 1102 | 1103 | def rapid_whois(domain, filename): 1104 | 1105 | try : 1106 | 1107 | with open(filename, "r") as keys: 1108 | 1109 | data = yaml.safe_load(keys) 1110 | 1111 | rapid_api_key = random.choice(data.get('Rapidapi', [])) 1112 | 1113 | integrated_key = random.choice(data.get('Whoisxml', [])) 1114 | 1115 | if rapid_api_key is None or integrated_key is None: 1116 | 1117 | if args.show_key_error: 1118 | 1119 | logging.info(f"[{bold}{red}ALERT{reset}]: There is no api keys found for Rapidapi and Whoisxmlapi") 1120 | 1121 | return 1122 | 1123 | else: 1124 | 1125 | pass 1126 | 1127 | 1128 | try: 1129 | 1130 | url = "https://subdomains-lookup.p.rapidapi.com/api/v1" 1131 | 1132 | querystring = {"domainName": domain,"apiKey": integrated_key ,"outputFormat":"JSON"} 1133 | 1134 | headers = { 1135 | "X-RapidAPI-Key": rapid_api_key, 1136 | "X-RapidAPI-Host": "subdomains-lookup.p.rapidapi.com" 1137 | } 1138 | 1139 | with httpx.Client() as requests: 1140 | 1141 | response = requests.get(url, headers=headers, params=querystring, timeout=10) 1142 | 1143 | if response.status_code == 200: 1144 | 1145 | data = response.json() 1146 | 1147 | records = data.get('result', {}).get('records', []) 1148 | 1149 | for record in records: 1150 | 1151 | subdomain= record.get('domain') 1152 | 1153 | if subdomain: 1154 | 1155 | subdomains_list.append(subdomain) 1156 | else: 1157 | 1158 | pass 1159 | else: 1160 | 1161 | logging.info (f"[{red}Alert{reset}]: RapidWhois Blocking our requests check your api usage of Rapid {rapid_api_key} and Whoisxml {integrated_key} api keys ") 1162 | 1163 | 1164 | except Exception as e: 1165 | 1166 | if args.show_req_error: 1167 | 1168 | logging.info (f"[{red}Alert{reset}]: RapidWhois Blocking our requests") 1169 | 1170 | 1171 | except yaml.YAMLError as e: 1172 | 1173 | logging.info(f"[{bold}{red}ALERT{reset}]: Please Check that You didnt messed up the Cofiguration files variables and it Values of Rapidapi and Whoisxml") 1174 | 1175 | except Exception as e: 1176 | 1177 | logging.info(f"[{bold}{red}ALERT{reset}]: Subdominator met with an Unknown Error due to: {e}") 1178 | 1179 | 1180 | #Dnsdumpster works good 1181 | 1182 | def non_api_dnsdump(domain, filename): 1183 | 1184 | try: 1185 | 1186 | with open(filename, "r") as keys: 1187 | 1188 | data = yaml.safe_load(keys) 1189 | 1190 | data = random.choice(data.get("Dnsdumpter", [])) 1191 | 1192 | csrf_cookie , csrf_token = data.split(":") 1193 | 1194 | if csrf_cookie is None or csrf_token is None: 1195 | 1196 | if args.show_key_error: 1197 | 1198 | logging.info(f"[{bold}{red}ALERT{reset}]: There is no csrf token or csrf cookie found for the DnsDump ") 1199 | 1200 | return 1201 | 1202 | else: 1203 | 1204 | pass 1205 | 1206 | 1207 | 1208 | try: 1209 | 1210 | url = f"https://dnsdumpster.com/" 1211 | 1212 | headers = headers = { 1213 | 'Cookie': f'csrftoken={csrf_cookie}', 1214 | 'Referer': 'https://dnsdumpster.com/' 1215 | } 1216 | data = { 1217 | 'csrfmiddlewaretoken': f'{csrf_token}', 1218 | 'targetip': domain, 1219 | 'user': 'free' 1220 | } 1221 | try: 1222 | 1223 | with httpx.Client() as requests: 1224 | 1225 | response = requests.post(url, headers=headers, data=data, timeout=10) 1226 | 1227 | if response.status_code == 200: 1228 | 1229 | content = response.text 1230 | 1231 | subdomains_pattern = re.compile(rf"\b[a-zA-Z0-9]+\b\.{domain}\b") 1232 | 1233 | subdomains = subdomains_pattern.findall(content) 1234 | 1235 | for subdomain in subdomains: 1236 | 1237 | if subdomains.endswith(f".{domain}") : 1238 | 1239 | subdomains_list.append(subdomain) 1240 | else: 1241 | 1242 | logging.info(f"[{bold}{red}ALERT{reset}]: DnsDumpster Blocking our requests check the csrf token and csrf cookie") 1243 | 1244 | 1245 | except Exception as e: 1246 | 1247 | if args.show_req_error: 1248 | 1249 | logging.info(f"[{bold}{red}ALERT{reset}]: DnsDumpster Blocking our requests") 1250 | 1251 | except Exception as e: 1252 | 1253 | logging.info(f"[{bold}{red}ALERT{reset}]: There is no csrf cookie and csrf token found for DsnDumpster") 1254 | 1255 | except yaml.YAMLError as e: 1256 | 1257 | logging.info(f"[{bold}{red}ALERT{reset}]: Please Check that You didnt messed up the Cofiguration files variables and it Values of DnsDumpster") 1258 | 1259 | 1260 | except Exception as e: 1261 | 1262 | logging.info(f"[{bold}{red}ALERT{reset}]: Subdominator met with an Unknown Error due to: {e}") 1263 | 1264 | #leakix works good 1265 | 1266 | def api_leakix(domain, filename): 1267 | 1268 | 1269 | try: 1270 | 1271 | 1272 | with open(filename, "r") as keys: 1273 | 1274 | data = yaml.safe_load(keys) 1275 | 1276 | leakix_key = random.choice(data.get("Leakix", [])) 1277 | 1278 | 1279 | if leakix_key is None : 1280 | 1281 | if args.show_key_error: 1282 | 1283 | logging.info(f"[{bold}{red}ALERT{reset}]: There is no api keys found for leakix api ") 1284 | 1285 | return 1286 | 1287 | else: 1288 | 1289 | pass 1290 | 1291 | try: 1292 | 1293 | url = f"https://leakix.net/api/subdomains/{domain}" 1294 | 1295 | headers = {"accept": "application/json", 1296 | "api-key": f"{leakix_key}", 1297 | } 1298 | 1299 | with httpx.Client() as requests: 1300 | 1301 | response = requests.get(url, headers=headers, timeout=10) 1302 | 1303 | data = response.json() 1304 | 1305 | if response.status_code == 200: 1306 | 1307 | for subdomains in data: 1308 | 1309 | subdomain = subdomains.get('subdomain', {} ) 1310 | 1311 | subdomains_list.append(subdomain) 1312 | 1313 | elif response.status_code == 429: 1314 | 1315 | logging.info(f"[{bold}{red}ALERT{reset}]: Leakix blocking our requests check your api usage for this key: {leakix_key}") 1316 | 1317 | else: 1318 | 1319 | pass 1320 | 1321 | 1322 | 1323 | except Exception as e: 1324 | 1325 | if args.show_req_error: 1326 | 1327 | logging.info(f"[{bold}{red}ALERT{reset}]: Leakix blocking our requests") 1328 | 1329 | 1330 | except yaml.YAMLError as e: 1331 | 1332 | logging.info(f"[{bold}{red}ALERT{reset}]: Please Check that You didnt messed up the Cofiguration files variables and it Values of Leakix") 1333 | 1334 | except Exception as e: 1335 | 1336 | logging.info(f"[{bold}{red}ALERT{reset}]: Subdominator met with an Unknown Error due to: {e}") 1337 | 1338 | #The Censys api works execellent with it results 1339 | 1340 | def api_censys(domain,file_path): 1341 | 1342 | try: 1343 | 1344 | filename = file_path 1345 | 1346 | 1347 | with open(filename, "r") as keys: 1348 | 1349 | data = yaml.safe_load(keys) 1350 | 1351 | data = random.choice(data.get('Censys', [])) 1352 | 1353 | censys_id,censys_key = data.split(':') 1354 | 1355 | if censys_id is None or censys_key is None: 1356 | 1357 | if args.show_key_error: 1358 | 1359 | logging.info(f"[{bold}{red}ALERT{reset}]: May be There is no api key or api secret id found for Censys api ") 1360 | 1361 | return 1362 | 1363 | else: 1364 | 1365 | pass 1366 | 1367 | try: 1368 | 1369 | USER_agent=f"{CensysCerts.DEFAULT_USER_AGENT} Subdominator/1.1 (+https://github.com/sanjai-AK47/Subdominator)" 1370 | 1371 | censys_query = CensysCerts(api_id=censys_id,api_secret=censys_key, user_agent=USER_agent) 1372 | 1373 | get_domains = f"names: {domain}" 1374 | 1375 | max_limits = 100 1376 | 1377 | min_limits = 10 1378 | 1379 | censys_subdomains = censys_query.search(get_domains, per_page=max_limits, pages=min_limits) 1380 | 1381 | 1382 | data = censys_subdomains 1383 | 1384 | temp_list = [] 1385 | 1386 | for subdomains in data: 1387 | 1388 | for subdomain in subdomains: 1389 | 1390 | temp_list.extend(subdomain.get("names", [])) 1391 | 1392 | for subdomain in temp_list: 1393 | 1394 | if subdomain.startswith("*.") and subdomain.endswith(domain): 1395 | 1396 | 1397 | subdomain = subdomain[2:] 1398 | 1399 | subdomains_list.append(subdomain) 1400 | 1401 | elif subdomain.endswith(domain): 1402 | 1403 | subdomains_list.append(subdomain) 1404 | 1405 | else: 1406 | 1407 | pass 1408 | 1409 | 1410 | 1411 | 1412 | 1413 | 1414 | except CensysUnauthorizedException: 1415 | 1416 | 1417 | logging.info(f"[{bold}{red}ALERT{reset}]: Censys is blocking our requests check your api usage") 1418 | 1419 | except CensysRateLimitExceededException: 1420 | 1421 | 1422 | logging.info(f"[{bold}{red}ALERT{reset}]: Censys is blocking our requests check your api usage") 1423 | 1424 | 1425 | except Exception as e: 1426 | 1427 | if args.show_req_error: 1428 | 1429 | logging.info(f"[{bold}{red}ALERT{reset}]: Censys is blocking our requests ") 1430 | 1431 | except yaml.YAMLError as e: 1432 | 1433 | logging.info(f"[{bold}{red}ALERT{reset}]: Please Check that You didnt messed up the Cofiguration files variables and it Values of Censys") 1434 | 1435 | except Exception as e: 1436 | 1437 | logging.info(f"[{bold}{red}ALERT{reset}]: Subdominator met with an Unknown Error due to: {e}") 1438 | 1439 | #fullhunt api 1440 | 1441 | def api_fullhunt(domain,filename): 1442 | 1443 | try: 1444 | 1445 | 1446 | with open(filename, "r") as keys: 1447 | 1448 | data = yaml.safe_load(keys) 1449 | 1450 | fullhunt_key = random.choice(data.get("Fullhunt", [])) 1451 | 1452 | 1453 | if fullhunt_key is None : 1454 | 1455 | if args.show_key_error: 1456 | 1457 | logging.info(f"[{bold}{red}ALERT{reset}]: There is no api keys found for Fullhunt.io api ") 1458 | 1459 | return 1460 | 1461 | else: 1462 | 1463 | pass 1464 | 1465 | 1466 | 1467 | try: 1468 | 1469 | url = f"https://fullhunt.io/api/v1/domain/{domain}/subdomains" 1470 | 1471 | headers = {"X-API-KEY": f"{fullhunt_key}"} 1472 | 1473 | with httpx.Client() as requests: 1474 | 1475 | response = requests.get(url, headers=headers, timeout=10) 1476 | 1477 | data = response.json() 1478 | 1479 | if response.status_code == 200: 1480 | 1481 | subdomains = data.get('hosts', []) 1482 | 1483 | for subdomain in subdomains: 1484 | 1485 | subdomains_list.append(subdomain) 1486 | 1487 | 1488 | elif response.status_code == 429: 1489 | 1490 | logging.info(f"[{bold}{red}ALERT{reset}]: Fullhunt blocking our requests check your api usage {fullhunt_key}") 1491 | 1492 | else: 1493 | 1494 | pass 1495 | 1496 | 1497 | 1498 | except Exception as e: 1499 | 1500 | if args.show_req_error: 1501 | 1502 | logging.info(f"[{bold}{red}ALERT{reset}]: Fullhunt blocking our requests") 1503 | 1504 | 1505 | except yaml.YAMLError as e: 1506 | 1507 | logging.info(f"[{bold}{red}ALERT{reset}]: Please Check that You didnt messed up the Cofiguration files variables and it Values of Fullhunt") 1508 | 1509 | except Exception as e: 1510 | 1511 | logging.info(f"[{bold}{red}ALERT{reset}]: Subdominator met with an Unknown Error due to: {e}") 1512 | 1513 | 1514 | #netlas works good 1515 | 1516 | def api_netlas(domain, filename): 1517 | 1518 | 1519 | try: 1520 | 1521 | 1522 | with open(filename, "r") as keys: 1523 | 1524 | data = yaml.safe_load(keys) 1525 | 1526 | netlas_key = random.choice(data.get("Netlas", [])) 1527 | 1528 | 1529 | if netlas_key is None : 1530 | 1531 | if args.show_key_error: 1532 | 1533 | logging.info(f"[{bold}{red}ALERT{reset}]: There is no api keys found for Fullhunt api ") 1534 | 1535 | return 1536 | 1537 | else: 1538 | 1539 | pass 1540 | 1541 | try: 1542 | 1543 | url = f"https://app.netlas.io/api/domains/?q=(domain:*.{domain}+AND+NOT+domain:{domain})&host={domain}" 1544 | 1545 | headers = { 1546 | "X-API-Key": f"{netlas_key}", 1547 | } 1548 | 1549 | with httpx.Client() as requests: 1550 | 1551 | response = requests.get(url, headers=headers, timeout=10) 1552 | 1553 | 1554 | if response.status_code == 200: 1555 | 1556 | data = response.json() 1557 | 1558 | for item in data['items']: 1559 | 1560 | subdomains = item['data']['domain'] 1561 | 1562 | subdomains_list.append(subdomains) 1563 | 1564 | else: 1565 | 1566 | logging.info(f"[{bold}{red}ALERT{reset}]: Netlas api blocking our request, check your api usage of {netlas_key} ") 1567 | 1568 | 1569 | 1570 | 1571 | except Exception as e: 1572 | 1573 | if args.show_req_error: 1574 | 1575 | logging.info(f"[{bold}{red}ALERT{reset}]: Netlas blocking our requests") 1576 | 1577 | 1578 | except yaml.YAMLError as e: 1579 | 1580 | logging.info(f"[{bold}{red}ALERT{reset}]: Please Check that You didnt messed up the Cofiguration files variables and it Values of Netlas.io") 1581 | 1582 | except Exception as e: 1583 | 1584 | logging.info(f"[{bold}{red}ALERT{reset}]: Subdominator met with an Unknown Error due to: {e}") 1585 | 1586 | #zoomEYE Auth works good with access token and JWT 1587 | 1588 | def zoom_eye_login(filename): 1589 | 1590 | 1591 | try: 1592 | 1593 | with open(filename, "r") as keys: 1594 | 1595 | data = yaml.safe_load(keys) 1596 | 1597 | data = random.choice(data.get("Zoomeye-Auth", [])) 1598 | 1599 | zoom_username ,zoom_password = data.split(':') 1600 | 1601 | 1602 | if zoom_username is None or zoom_password is None: 1603 | 1604 | if args.show_key_error: 1605 | 1606 | logging.info(f"[{bold}{red}ALERT{reset}]: There is no email and password found for Zoomeye api ") 1607 | 1608 | return 1609 | 1610 | else: 1611 | 1612 | pass 1613 | 1614 | 1615 | url = "https://api.zoomeye.org/user/login" 1616 | data = { 1617 | "username": zoom_username, 1618 | "password": zoom_password 1619 | } 1620 | 1621 | try: 1622 | 1623 | with httpx.Client() as client: 1624 | response = client.post(url, json=data) 1625 | 1626 | if response.status_code == 200: 1627 | 1628 | return response.json().get("access_token") 1629 | 1630 | else: 1631 | 1632 | logging.info(f"[{bold}{red}ALERT{reset}]: Invalid Zoomeye login credentials Please check the Zoomeye email or password is correct") 1633 | 1634 | 1635 | return None 1636 | 1637 | except Exception as e: 1638 | 1639 | if args.show_req_error: 1640 | 1641 | logging.info(f"[{bold}{red}ALERT{reset}]: Zoomeye login blocking our requests") 1642 | 1643 | except yaml.YAMLError as e: 1644 | 1645 | logging.info(f"[{bold}{red}ALERT{reset}]: Please check your configuration file and values for Zoomeye API email and password") 1646 | 1647 | 1648 | except Exception as e: 1649 | 1650 | logging.info(f"[{bold}{red}ALERT{reset}]: Subdominator met with an Unknown Error due to: {e}") 1651 | 1652 | 1653 | 1654 | def api_zoomeye_jwt(domain,token): 1655 | 1656 | 1657 | try: 1658 | zoom_jwt = token 1659 | 1660 | current_page = 2 1661 | 1662 | 1663 | url=f"https://api.zoomeye.org/domain/search?q={domain}&type=1&page={current_page}" 1664 | 1665 | headers = { 1666 | "Authorization": f"JWT {zoom_jwt}", 1667 | "Accept": "application/json", 1668 | "Content-Type": "application/json", 1669 | } 1670 | 1671 | 1672 | with httpx.Client() as requests: 1673 | 1674 | response = requests.get(url, headers=headers) 1675 | 1676 | data = response.json() 1677 | 1678 | if response.status_code == 200: 1679 | 1680 | for item in data['list']: 1681 | 1682 | subdomains_list.append(item['name']) 1683 | 1684 | elif response.status_code == 429: 1685 | 1686 | logging.info(f"[{bold}{red}ALERT{reset}]: Zoomeye JWT blocking our requests") 1687 | 1688 | elif response.status_code == 401: 1689 | 1690 | logging.info(f"[{bold}{red}ALERT{reset}]: Unauthorized Zoomeye JWT key please check your accesstoken") 1691 | 1692 | pass 1693 | 1694 | else: 1695 | 1696 | 1697 | logging.info(f"[{bold}{red}ALERT{reset}]: Zoomeye JWT blocking our requests check your api usage ") 1698 | 1699 | pass 1700 | 1701 | 1702 | 1703 | except Exception as e: 1704 | 1705 | if args.show_req_error: 1706 | 1707 | logging.info(f"[{bold}{red}ALERT{reset}]: Zoomeye JWT blocking our requests") 1708 | 1709 | 1710 | #zoom eye api works good 1711 | 1712 | def api_zoomeye(domain, filename): 1713 | 1714 | try: 1715 | with open(filename, "r") as keys: 1716 | 1717 | data = yaml.safe_load(keys) 1718 | 1719 | zoom_key = random.choice(data.get("Zoomeye-API", [])) 1720 | 1721 | if zoom_key is None: 1722 | 1723 | if args.show_key_error: 1724 | 1725 | logging.info(f"[{bold}{red}ALERT{reset}]: There is no API key found for Zoomeye API") 1726 | 1727 | return 1728 | else: 1729 | pass 1730 | 1731 | try: 1732 | 1733 | current_page = 1 1734 | 1735 | while True: 1736 | 1737 | url = f"https://api.zoomeye.org/domain/search?q={domain}&type=1&s=1000&page={current_page}" 1738 | 1739 | headers = { 1740 | "API-KEY": f"{zoom_key}", 1741 | "Accept": "application/json", 1742 | "Content-Type": "application/json", 1743 | } 1744 | 1745 | with httpx.Client() as requests: 1746 | 1747 | response = requests.get(url, headers=headers, timeout=10) 1748 | 1749 | data = response.json() 1750 | 1751 | 1752 | if response.status_code == 200: 1753 | 1754 | for item in data["list"]: 1755 | 1756 | if "API count exceeded - Increase Quota with Membership" in item: 1757 | 1758 | pass 1759 | 1760 | else: 1761 | 1762 | 1763 | subdomains_list.append(item["name"]) 1764 | 1765 | if data["total"] > current_page * data["size"]: 1766 | 1767 | current_page += 1 1768 | else: 1769 | 1770 | break 1771 | 1772 | elif response.status_code == 429: 1773 | 1774 | logging.info(f"[{bold}{red}ALERT{reset}]: Zoomeye api blocking our requests, check your API usage {zoom_key}") 1775 | 1776 | break 1777 | 1778 | elif response.status_code == 401: 1779 | 1780 | logging.info(f"[{bold}{red}ALERT{reset}]: Unauthorized Zoomeye API key, please check your API key {zoom_key}") 1781 | 1782 | break 1783 | 1784 | else: 1785 | 1786 | if args.show_key_error: 1787 | logging.info(f"[{bold}{red}ALERT{reset}]: Zoomeye api blocking our requests, check your API usage {zoom_key}") 1788 | 1789 | break 1790 | 1791 | except Exception as e: 1792 | 1793 | pass 1794 | 1795 | except yaml.YAMLError as e: 1796 | 1797 | logging.info(f"[{bold}{red}ALERT{reset}]: Please check your configuration file and values for Zoomeye API") 1798 | 1799 | except Exception as e: 1800 | 1801 | logging.info(f"[{bold}{red}ALERT{reset}]: Subdominator met with an Unknown Error due to: {e}") 1802 | 1803 | 1804 | def shodan_api(domain, filepath): 1805 | 1806 | 1807 | try: 1808 | 1809 | with open(filepath, "r") as keys: 1810 | 1811 | data = yaml.safe_load(keys) 1812 | 1813 | shodan_key = random.choice(data.get("Shodan", [])) 1814 | 1815 | if shodan_key is None: 1816 | 1817 | if args.show_key_error: 1818 | 1819 | logging.info(f"[{bold}{red}ALERT{reset}]: There is no api keys found for Hunter api") 1820 | 1821 | return 1822 | 1823 | except yaml.YAMLError as e: 1824 | 1825 | 1826 | logging.info(f"[{bold}{red}ALERT{reset}]: Please Check that You didnt messed up the Cofiguration files variables and it Values of Shodan") 1827 | 1828 | 1829 | except Exception as e: 1830 | 1831 | logging.info(f"[{bold}{red}ALERT{reset}]: Subdominator met with Unknown Error due to : {e}") 1832 | 1833 | 1834 | try: 1835 | 1836 | url = f"https://api.shodan.io/dns/domain/{domain}?key={shodan_key}" 1837 | 1838 | 1839 | response = requests.get(url, timeout=10) 1840 | 1841 | if response.status_code == 200: 1842 | 1843 | data = response.json() 1844 | 1845 | subdomains = data.get("subdomains", []) 1846 | 1847 | for subdomain in subdomains: 1848 | 1849 | subdomains_list.append(f"{subdomain}.{domain}") 1850 | 1851 | else: 1852 | 1853 | pass 1854 | 1855 | except Exception as e: 1856 | 1857 | if args.show_req_error: 1858 | 1859 | logging.info(f"[{bold}{red}ALERT{reset}]: Shodan blocking our request ") 1860 | 1861 | 1862 | def api_hunter(domain, filepath): 1863 | 1864 | try: 1865 | 1866 | with open(filepath, "r") as keys: 1867 | 1868 | data = yaml.safe_load(keys) 1869 | 1870 | hunter_key = random.choice(data.get("Hunter", [])) 1871 | 1872 | if hunter_key is None: 1873 | 1874 | if args.show_key_error: 1875 | 1876 | logging.info(f"[{bold}{red}ALERT{reset}]: There is no api keys found for Hunter api") 1877 | 1878 | return 1879 | 1880 | 1881 | try: 1882 | 1883 | end_time = datetime.now().strftime("%Y-%m-%d") 1884 | 1885 | temp_time = datetime.now() - timedelta(days=27.8*12) 1886 | 1887 | start_time = temp_time.strftime("%Y-%m-%d") 1888 | 1889 | 1890 | query = base64.urlsafe_b64encode(domain.encode("utf-8")).decode('ascii') 1891 | 1892 | page_size = 100 1893 | 1894 | temp_list = [] 1895 | 1896 | page = 1 1897 | 1898 | while True: 1899 | 1900 | with open(filepath, "r") as keys: 1901 | 1902 | data = yaml.safe_load(keys) 1903 | 1904 | hunter_key = random.choice(data.get("Hunter", [])) 1905 | 1906 | url = f"https://api.hunter.how/search?api-key={hunter_key}&query={query}&start_time={start_time}&end_time={end_time}&page={page}&page_size={page_size}" 1907 | 1908 | 1909 | with httpx.Client() as requests: 1910 | 1911 | response = requests.get(url, timeout=10) 1912 | 1913 | 1914 | 1915 | if response.status_code == 200: 1916 | 1917 | data = response.json() 1918 | 1919 | subdomains = data.get("data", {}).get("list", []) 1920 | 1921 | total = data.get("data", {}).get("total", 0) 1922 | 1923 | for subdomain in subdomains: 1924 | 1925 | subdomain = subdomain['domain'] 1926 | 1927 | if subdomain.endswith(domain): 1928 | 1929 | temp_list.append(subdomain) 1930 | 1931 | for subdomain in temp_list: 1932 | 1933 | subdomains_list.append(subdomain) 1934 | 1935 | 1936 | else: 1937 | 1938 | pass 1939 | 1940 | if total <= len(temp_list): 1941 | 1942 | for subdomain in temp_list: 1943 | 1944 | if subdomain.endswith(domain): 1945 | 1946 | temp_list.append(subdomain) 1947 | 1948 | for subdomain in temp_list: 1949 | 1950 | subdomains_list.append(domain) 1951 | 1952 | 1953 | break 1954 | 1955 | page += 1 1956 | 1957 | 1958 | except Exception as e: 1959 | 1960 | try: 1961 | 1962 | for subdomain in temp_list: 1963 | 1964 | if subdomain.endswith(f".{domain}"): 1965 | 1966 | subdomains_list.append(subdomain) 1967 | 1968 | except Exception as e: 1969 | 1970 | pass 1971 | 1972 | 1973 | 1974 | except yaml.YAMLError as e: 1975 | 1976 | logging.info(f"[{bold}{red}ALERT{reset}]: Please Check that You didnt messed up the Cofiguration files variables and it Values of Hunter api") 1977 | 1978 | except Exception as e: 1979 | 1980 | logging.info(f"[{bold}{red}ALERT{reset}]: Subdominator met with an Unknown Error due to: {e}") 1981 | 1982 | 1983 | def api_redhunt(domain, filepath): 1984 | 1985 | try: 1986 | 1987 | with open(filepath, "r") as keys: 1988 | 1989 | data = yaml.safe_load(keys) 1990 | 1991 | redhunt_key = random.choice(data.get("Redhunt", [])) 1992 | 1993 | if redhunt_key is None: 1994 | 1995 | logging.info(f"[{bold}{red}ALERT{reset}]: There is no API key found for Redhunt API") 1996 | 1997 | return 1998 | else: 1999 | pass 2000 | 2001 | page_number = 1 2002 | 2003 | while True: 2004 | 2005 | page_subdomains = send_request(domain,redhunt_key,page_number) 2006 | 2007 | if not page_subdomains: 2008 | 2009 | break 2010 | 2011 | subdomains_list.extend(page_subdomains) 2012 | 2013 | page_number += 1 2014 | 2015 | except yaml.YAMLError as e: 2016 | 2017 | logging.info(f"[{bold}{red}ALERT{reset}]: Please Check that You didnt messed up the Cofiguration files variables and it Values fo Redhunt api") 2018 | 2019 | except Exception as e: 2020 | 2021 | logging.info(f"[{bold}{red}ALERT{reset}]: Subdominator met with an Unknown Error due to: {e}") 2022 | 2023 | def send_request(domain, api_key, page_number): 2024 | 2025 | page_size = 1000 2026 | 2027 | url = f"https://reconapi.redhuntlabs.com/community/v1/domains/subdomains?domain={domain}&page_size={page_size}&page={page_number}" 2028 | 2029 | headers = { 2030 | "X-BLOBR-KEY": api_key 2031 | } 2032 | 2033 | with httpx.Client() as requests: 2034 | 2035 | response = requests.get(url, headers=headers, timeout=10) 2036 | 2037 | data = response.json() 2038 | 2039 | if response.status_code == 200: 2040 | 2041 | 2042 | 2043 | if 'subdomains' in data: 2044 | 2045 | return data['subdomains'] 2046 | 2047 | 2048 | 2049 | else: 2050 | 2051 | pass 2052 | 2053 | elif response.status_code == 403 or "The limit has been reached for this product, please contact your data provider" in data : 2054 | 2055 | 2056 | logging.info(f"[{bold}{red}ALERT{reset}]: Redhunt api blocking our requests Check your api usage: {api_key}") 2057 | 2058 | elif response.status_code == 404 or 'No data product found. Please contact your data provider' in data: 2059 | 2060 | logging.info(f"[{bold}{red}ALERT{reset}]: Check that you have subscriber to Redhunt api free access for this api key: {api_key}") 2061 | 2062 | else: 2063 | 2064 | pass 2065 | 2066 | 2067 | 2068 | 2069 | 2070 | 2071 | 2072 | 2073 | #=============================================================================NON API Start================================================================================================= 2074 | 2075 | 2076 | 2077 | def abuseipdb(domain): 2078 | 2079 | 2080 | try: 2081 | 2082 | url = f"https://www.abuseipdb.com/whois/{domain}" 2083 | 2084 | user_agent = UserAgent() 2085 | 2086 | headers = headers = { 2087 | "User-Agent": f"{user_agent}" 2088 | } 2089 | 2090 | with httpx.Client() as requests: 2091 | 2092 | response = requests.get(url, headers=headers, timeout=10) 2093 | 2094 | 2095 | if response.status_code == 200: 2096 | 2097 | tags = re.findall(r'