├── requirements.txt ├── pysho.png ├── README.md └── pysho.py /requirements.txt: -------------------------------------------------------------------------------- 1 | shodan 2 | termcolor -------------------------------------------------------------------------------- /pysho.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kr0ff/pysho/master/pysho.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pysho 2 | ------ 3 | - Python based tool to perform Shodan queries via the Shodan API 4 | 5 | ![Preview Image](pysho.png) 6 | 7 | ------ 8 | Get the tool: 9 | ``` 10 | git clone https://github.com/Kr0ff/pysho 11 | python -m pip install -r requirements.txt 12 | chmod +x pysho.py 13 | ./pysho 14 | ``` 15 | ------ 16 | Example usage: 17 | ``` 18 | # Perform a check on your Shodan API key 19 | python pysho.py --info 20 | ``` 21 | [![pysho-keyinfo](https://asciinema.org/a/321757.png)](https://asciinema.org/a/321757) 22 | 23 | ``` 24 | # Perform search for a service or keyword 25 | python pysho.py -s/--search "apache"/"google" 26 | ``` 27 | [![pysho-search](https://asciinema.org/a/321799.png)](https://asciinema.org/a/321799) 28 | 29 | ``` 30 | # Perform search for an IP address 31 | python pysho.py -i/--ip_address "8.8.8.8" 32 | ``` 33 | [![pysho-ip](https://asciinema.org/a/321765.png)](https://asciinema.org/a/321765) 34 | 35 | ------ 36 | -------------------------------------------------------------------------------- /pysho.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import os 4 | import shodan 5 | import sys 6 | import argparse 7 | from termcolor import colored 8 | from time import sleep 9 | # from pathlib import Path 10 | 11 | def artistic_view(): 12 | 13 | art = ''' 14 | @@@@@@@ @@@ @@@ @@@@@@ @@@ @@@ @@@@@@ 15 | @@@@@@@@ @@@ @@@ @@@@@@@ @@@ @@@ @@@@@@@@ 16 | @@! @@@ @@! !@@ !@@ @@! @@@ @@! @@@ 17 | !@! @!@ !@! @!! !@! !@! @!@ !@! @!@ 18 | @!@@!@! !@!@! !!@@!! @!@!@!@! @!@ !@! 19 | !!@!!! @!!! !!@!!! !!!@!!!! !@! !!! 20 | !!: !!: !:! !!: !!! !!: !!! 21 | :!: :!: !:! :!: !:! :!: !:! 22 | :: :: :::: :: :: ::: ::::: :: 23 | : : :: : : : : : : : : 24 | 25 | v0.1 @Kr0ff 26 | ''' 27 | disclaimer = colored(" [!] Disclaimer [!]", "yellow") 28 | 29 | advice = colored(''' 30 | [X] The author is not responsible how this tool is used ! 31 | [X] You agree to take full responsibility for your actions ! 32 | [X] This tool is to be used for educational purposes only ! 33 | [X] Pentesting a service without written permissions is ILLEGAL ! 34 | ''', "red") 35 | 36 | print(colored(art, "blue")) 37 | print(disclaimer) 38 | print(advice) 39 | 40 | #initiate API key check 41 | try: 42 | init_key = f"{os.getcwd()}/API_KEY" 43 | if not os.path.exists(init_key): 44 | # if os.path.isfile(init_key) and os.stat(init_key).st_size < 2: 45 | print(colored("[!] 'API_KEY' doesn't exist", "yellow")) 46 | 47 | k = input("[*] Enter your Shodan.io API Key: ") 48 | while len(k) == 0 or len(k) < 32: 49 | k = input("[*] Enter your Shodan.io API Key: ") 50 | 51 | with open(f"{os.getcwd()}/API_KEY", "w") as key_file: 52 | key_file.write(str(k)) 53 | key_file.close() 54 | 55 | print(colored("[+] API key saved !", "green")) 56 | sleep(0.5) 57 | 58 | else: 59 | print(colored("\r\n[+] API key exists in file 'API_KEY', Continuing...", "green")) 60 | # sleep(1) 61 | with open(f"{os.getcwd()}/API_KEY", "r") as key_file: 62 | k = key_file.readline().rstrip('\n') 63 | 64 | except KeyboardInterrupt: 65 | print(colored("\r\n[!] KeyboardInterrupt: Exitting !", "yellow")) 66 | sys.exit(0) 67 | 68 | #Clear screen after API_KEY check 69 | os.system('cls' if os.name == 'nt' else 'clear') 70 | 71 | #Initiate connection to Shodan.io 72 | connect = shodan.Shodan(k) 73 | 74 | #Check api key info 75 | def key_info(): 76 | try: 77 | key = connect.info() 78 | print(f"[*] Scan Credits: {colored(key['scan_credits'], 'green')}") 79 | print(f"[*] Query Credits: {colored(key['query_credits'], 'green')}") 80 | print(f"[*] Monitored IPs: {colored(key['monitored_ips'], 'green')}") 81 | print(f"[*] Plan: {colored(key['plan'], 'green')}") 82 | print(f"[*] HTTPS ?: {colored(key['https'], 'white')}") 83 | print(f"[*] Unlocked ?: {colored(key['unlocked'], 'white')}") 84 | print(f"[*] Telnet ?: {colored(key['telnet'], 'white')}") 85 | print(f"[*] Unlocked Left: {colored(key['unlocked_left'], 'green')}") 86 | except shodan.APIError as e: 87 | print(colored(f'[-] API Error: {e}', "red")) 88 | 89 | #Lookup by IP 90 | def host(i): 91 | try: 92 | try: 93 | print("[+] Looking up {}\r\n".format(colored(str(i), "cyan"))) 94 | 95 | #Lookup the host 96 | findings = connect.host(str(i)) 97 | 98 | #Print general info 99 | print(f"[#] Organization: {colored(findings['org'], 'green')}") 100 | print(f"[#] Operating System: {colored(findings['os'], 'green')}") 101 | for result in findings['data']: 102 | print(f"[#] Port: {colored(result['port'], 'green')}") 103 | print("[>>] Banner:") 104 | print(f"\r\n{colored(result['data'], 'magenta')}") 105 | print(colored("-+"*50, "white")) 106 | 107 | except shodan.APIError as e: 108 | print(colored(f'[-] API Error: {e}', 'red')) 109 | sleep(0.5) 110 | 111 | except KeyboardInterrupt: 112 | print(colored("\r\n[!] KeyboardInterrupt: Exitting !", "yellow")) 113 | sys.exit(0) 114 | 115 | #Lookup by service (smb, apache, nginx ,etc) 116 | def ip_lookup(s): 117 | try: 118 | try: 119 | print(f"[+] Searching for: {colored(s, 'cyan')}\r\n") 120 | 121 | # Search Shodan 122 | findings = connect.search(str(s)) 123 | 124 | # Show the results, if None raise exception 125 | print(f'Results found: {colored(findings["total"], "red", attrs=["bold"])}\r\n') 126 | sleep(1.5) #Leave a moment to check total number of results found 127 | 128 | for result in findings['matches']: 129 | print(f'[#] IP: {colored(result["ip_str"], "green")}') 130 | print(f'[#] Port: {colored(result["port"], "green")}') 131 | print(f'[#] Organization: {colored(result["org"], "green")}') 132 | print(f'[#] Location: {colored(result["location"], "green")}') 133 | print(f'[#] Layer: {colored(result["transport"], "green")}') 134 | print(f'[#] Domains: {colored(result["domains"], "green")}') 135 | print(f'[#] Hostnames: {colored(result["hostnames"], "green")}') 136 | print("[>>] Banner: ") 137 | print(colored(result['data'], "magenta")) 138 | print(colored('-+'*50, "white") + "\r\n") 139 | 140 | except shodan.APIError as e: 141 | print(colored(f'[-] API Error: {e}', "red")) 142 | sleep(0.5) 143 | 144 | except KeyboardInterrupt: 145 | print(colored("\r\n[!] KeyboardInterrupt: Exitting !", "yellow")) 146 | sys.exit(0) 147 | 148 | #Initialize "pysho" :) 149 | if __name__ == "__main__": 150 | 151 | #Print the beautiful art above :) 152 | # print(colored(art, "blue")) 153 | artistic_view() 154 | #Setup the argument parser 155 | parser = argparse.ArgumentParser(description='Search Shodan.io using the Shodan API') 156 | parser.add_argument("-i", "--ip_address", help="Host to search by IP", type=str) 157 | parser.add_argument("-s", "--search", help="Service to search (apache, nginx, smb, etc...)", type=str) 158 | parser.add_argument("--info", help="Get information about your API key", action="store_true") 159 | args = parser.parse_args(args=None if sys.argv[1:] else ['--help']) 160 | 161 | s = args.search 162 | i = args.ip_address 163 | keyinfo = args.info 164 | ###Check which arg is used 165 | if s: 166 | ip_lookup(s) 167 | if i: 168 | host(i) 169 | if keyinfo: 170 | key_info() 171 | --------------------------------------------------------------------------------