import shodan import tkinter as tk from tkinter import messagebox, filedialog, scrolledtext import logging import socket import csv # Replace with your own Shodan API key API_KEY = 'MGuIDeniFASV30RvVkg1GHZXKHgx4RBX' api = shodan.Shodan(API_KEY) # Configure logging logging.basicConfig(filename='shodan_app.log', level=logging.ERROR) # Load user preferences preferences = { 'include_org': True, 'include_country': True, 'include_city': False, 'include_isp': False, 'include_lat_lon': False, 'include_hostnames': False, 'include_last_update': False } def load_preferences(): # Load saved preferences (if applicable) pass # Implement loading from a file if needed def save_preferences(): # Save current preferences preferences['include_org'] = var_org.get() preferences['include_country'] = var_country.get() preferences['include_city'] = var_city.get() preferences['include_isp'] = var_isp.get() preferences['include_lat_lon'] = var_lat_lon.get() preferences['include_hostnames'] = var_hostnames.get() preferences['include_last_update'] = var_last_update.get() def resolve_domain(): domain = entry_ip.get() try: ip_address = socket.gethostbyname(domain) return ip_address except socket.gaierror: messagebox.showerror("Error", "Invalid domain name.") return None def search_ip(): ip_address = entry_ip.get() if not ip_address: messagebox.showerror("Error", "Please enter an IP address or domain.") return if not ip_address.replace('.', '').isdigit(): ip_address = resolve_domain() if not ip_address: return print(f"Searching for IP: {ip_address}") # Debug print try: result = api.host(ip_address) output = f"IP: {result['ip_str']}\n" if preferences['include_org']: output += f"Organization: {result.get('org', 'N/A')}\n" if preferences['include_country']: output += f"Country: {result.get('country_name', 'N/A')}\n" if preferences['include_city']: output += f"City: {result.get('city', 'N/A')}\n" if preferences['include_isp']: output += f"ISP: {result.get('isp', 'N/A')}\n" if preferences['include_lat_lon']: output += f"Latitude: {result.get('latitude', 'N/A')}, Longitude: {result.get('longitude', 'N/A')}\n" if preferences['include_hostnames'] and 'hostnames' in result: output += f"Hostnames: {', '.join(result['hostnames']) if result['hostnames'] else 'N/A'}\n" if preferences['include_last_update']: output += f"Last Update: {result.get('last_update', 'N/A')}\n" output += "Services:\n" for service in result['data']: port = service.get('port', 'N/A') product = service.get('product', 'N/A') output += f" - Port: {port} - Service: {product}\n" result_box.delete(1.0, tk.END) result_box.insert(tk.END, output) search_history.append(ip_address) # Save to search history update_search_history_display() except shodan.APIError as e: logging.error(f"API Error: {str(e)}") messagebox.showerror("Error", str(e)) def search_keywords(): keyword = entry_keyword.get() if not keyword: messagebox.showerror("Error", "Please enter a keyword to search.") return try: results = api.search(keyword) output = f"Results for '{keyword}':\n" for result in results['matches']: output += f"IP: {result['ip_str']} - Port: {result['port']} - Product: {result.get('product', 'N/A')}\n" result_box.delete(1.0, tk.END) result_box.insert(tk.END, output) except shodan.APIError as e: logging.error(f"API Error: {str(e)}") messagebox.showerror("Error", str(e)) def search_by_port(): ip_address = entry_ip.get() port = entry_port.get() if not ip_address or not port: messagebox.showerror("Error", "Please enter an IP address and a port.") return try: result = api.host(ip_address) output = f"Searching services on {ip_address} for port {port}:\n" found = False for service in result['data']: if service.get('port') == int(port): found = True output += f" - Port: {service['port']} - Service: {service.get('product', 'N/A')}\n" if not found: output += "No services found for this port.\n" result_box.delete(1.0, tk.END) result_box.insert(tk.END, output) except shodan.APIError as e: logging.error(f"API Error: {str(e)}") messagebox.showerror("Error", str(e)) def export_to_csv(): output = result_box.get(1.0, tk.END) if not output.strip(): messagebox.showerror("Error", "No data to export.") return file_path = filedialog.asksaveasfilename(defaultextension=".csv", filetypes=[("CSV files", "*.csv"), ("All files", "*.*")]) if file_path: with open(file_path, 'w', newline='') as file: writer = csv.writer(file) writer.writerow(["Results"]) for line in output.splitlines(): writer.writerow([line]) messagebox.showinfo("Success", "Data exported successfully!") def view_device_details(ip_address): try: result = api.host(ip_address) output = f"Details for IP: {result['ip_str']}\n" output += f"Organization: {result.get('org', 'N/A')}\n" output += f"Country: {result.get('country_name', 'N/A')}\n" output += f"City: {result.get('city', 'N/A')}\n" output += f"ISP: {result.get('isp', 'N/A')}\n" output += f"Latitude: {result.get('latitude', 'N/A')}, Longitude: {result.get('longitude', 'N/A')}\n" output += "Services:\n" for service in result['data']: output += f" - Port: {service.get('port', 'N/A')} - Product: {service.get('product', 'N/A')}\n" messagebox.showinfo("Device Details", output) except shodan.APIError as e: logging.error(f"API Error: {str(e)}") messagebox.showerror("Error", str(e)) def update_search_history_display(): history_box.delete(0, tk.END) for ip in search_history: history_box.insert(tk.END, ip) def show_help(): help_text = ( "Shodan IP Scanner Help\n" "1. Enter an IP address or domain name to query.\n" "2. Use the keyword field to search for specific devices.\n" "3. Check the boxes to include additional information in your results.\n" "4. You can filter results by port and export them to CSV.\n" "5. Click on a device in the search history to view its details." ) messagebox.showinfo("Help", help_text) # Initialize search history search_history = [] # Set up the GUI root = tk.Tk() root.title("Shodan IP Scanner") # Input for IP Address or Domain Name label_ip = tk.Label(root, text="Enter IP Address or Domain Name:") label_ip.pack(pady=10) entry_ip = tk.Entry(root, width=40) entry_ip.pack(pady=5) # Input for Keyword Search label_keyword = tk.Label(root, text="Enter Keyword for Search:") label_keyword.pack(pady=10) entry_keyword = tk.Entry(root, width=40) entry_keyword.pack(pady=5) # Input for Port Search label_port = tk.Label(root, text="Enter Port for Search:") label_port.pack(pady=5) entry_port = tk.Entry(root, width=20) entry_port.pack(pady=5) # Checkboxes for output options var_org = tk.BooleanVar(value=preferences['include_org']) check_org = tk.Checkbutton(root, text="Include Organization", variable=var_org) check_org.pack(anchor=tk.W) var_country = tk.BooleanVar(value=preferences['include_country']) check_country = tk.Checkbutton(root, text="Include Country", variable=var_country) check_country.pack(anchor=tk.W) var_city = tk.BooleanVar(value=preferences['include_city']) check_city = tk.Checkbutton(root, text="Include City", variable=var_city) check_city.pack(anchor=tk.W) var_isp = tk.BooleanVar(value=preferences['include_isp']) check_isp = tk.Checkbutton(root, text="Include ISP", variable=var_isp) check_isp.pack(anchor=tk.W) var_lat_lon = tk.BooleanVar(value=preferences['include_lat_lon']) check_lat_lon = tk.Checkbutton(root, text="Include Latitude/Longitude", variable=var_lat_lon) check_lat_lon.pack(anchor=tk.W) var_hostnames = tk.BooleanVar(value=preferences['include_hostnames']) check_hostnames = tk.Checkbutton(root, text="Include Hostnames", variable=var_hostnames) check_hostnames.pack(anchor=tk.W) var_last_update = tk.BooleanVar(value=preferences['include_last_update']) check_last_update = tk.Checkbutton(root, text="Include Last Update", variable=var_last_update) check_last_update.pack(anchor=tk.W) # Buttons for actions button_search = tk.Button(root, text="Search IP", command=search_ip) button_search.pack(pady=10) button_keyword_search = tk.Button(root, text="Search by Keyword", command=search_keywords) button_keyword_search.pack(pady=5) button_search_port = tk.Button(root, text="Search by Port", command=search_by_port) button_search_port.pack(pady=5) button_export = tk.Button(root, text="Export to CSV", command=export_to_csv) button_export.pack(pady=5) button_help = tk.Button(root, text="Help", command=show_help) button_help.pack(pady=5) # Search history listbox history_box = tk.Listbox(root, height=5, width=50) history_box.pack(pady=10) history_box.bind('', lambda event: view_device_details(history_box.get(history_box.curselection()))) # Scrollable text box for results result_box = scrolledtext.ScrolledText(root, wrap='word', height=15, width=60) result_box.pack(pady=10) # Load preferences on startup load_preferences() root.mainloop()