From ae973dec45c3f9d55bb491fe55d7a863557a8273 Mon Sep 17 00:00:00 2001 From: bkentopp Date: Thu, 9 Apr 2026 17:03:10 +0000 Subject: [PATCH] homelab_scanner.py scans my local vlan for web interfaces open. exports them to an excel sheet. --- homelab_scanner.py | 112 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 homelab_scanner.py diff --git a/homelab_scanner.py b/homelab_scanner.py new file mode 100644 index 0000000..702f59f --- /dev/null +++ b/homelab_scanner.py @@ -0,0 +1,112 @@ +import nmap +import pandas as pd +import os +import sys +import requests +from bs4 import BeautifulSoup +import urllib3 +from datetime import datetime + +# Suppress SSL warnings for self-signed certificates +urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) + +def probe_for_web_interface(host, port): + """ + Zero-trust probe: Manually tries HTTPS and HTTP on EVERY open port. + Captures webpage title and software version banners. + """ + for protocol in ["https", "http"]: + url = f"{protocol}://{host}:{port}" + try: + headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)'} + response = requests.get(url, timeout=3, verify=False, allow_redirects=True, headers=headers) + + # We accept any response < 500 (200, 302, 401, 403) + if response.status_code < 500: + soup = BeautifulSoup(response.text, 'html.parser') + title = soup.title.string.strip() if soup.title else "Web Page (No Title)" + # Grab the 'Server' header to identify the software stack + server_banner = response.headers.get('Server', 'Hidden/Unknown') + return True, url, title, server_banner + except: + continue + return False, None, None, None + +def run_exhaustive_scan(target_range): + nm = nmap.PortScanner() + + # PHASE 1: Rapid Discovery + print(f"[*] PHASE 1: Discovering live hosts on {target_range}...") + nm.scan(hosts=target_range, arguments='-sn') + live_hosts = nm.all_hosts() + + if not live_hosts: + print("[!] No devices found. Check your connection to the 192.168.12.x VLAN.") + return [] + + print(f"[+] Found {len(live_hosts)} active devices.") + print("[*] PHASE 2: Deep Scanning top 10,000 ports (this will take a few minutes)...") + + # Using synchronous scan for Windows stability + target_list = " ".join(live_hosts) + # -sV: Service version detection for hostnames and initial banners + nm_args = '-sV --open -T4 --top-ports 10000' + nm.scan(hosts=target_list, arguments=nm_args) + + # PHASE 3: Zero-Trust Web Verification & Banner Grabbing + scan_results = [] + print("\n[*] PHASE 3: Verifying web interfaces and grabbing software banners...") + + for host in nm.all_hosts(): + hostname = nm[host].hostname() + print(f"\n[+] Analyzing host: {host} ({hostname if hostname else 'No DNS Name'})") + + for proto in nm[host].all_protocols(): + lport = nm[host][proto].keys() + for port in lport: + print(f" - Probing port {port}...") + is_web, verified_url, web_title, banner = probe_for_web_interface(host, port) + + if is_web: + scan_results.append({ + 'IP Address': host, + 'Hostname': hostname, + 'Port': port, + 'Service Identity': web_title, + 'Software Banner': banner, + 'Verified Login URL': verified_url, + 'Discovery Date': datetime.now().strftime("%Y-%m-%d %H:%M") + }) + + return scan_results + +def save_to_excel(data, output_path): + if not data: + print("\n[!] No web services detected on the identified hosts.") + return + + df = pd.DataFrame(data) + # XlsxWriter is used to ensure URLs are formatted as clickable blue links + writer = pd.ExcelWriter(output_path, engine='xlsxwriter') + df.to_excel(writer, index=False, sheet_name='Homelab_Inventory') + + workbook = writer.book + worksheet = writer.sheets['Homelab_Inventory'] + + # Formatting for better readability + for i, col in enumerate(df.columns): + width = max(df[col].astype(str).map(len).max(), len(col)) + 2 + worksheet.set_column(i, i, width) + + writer.close() + print(f"\n[SUCCESS] Discovery Finished! Your documentation is at: {output_path}") + +if __name__ == "__main__": + # Settings + TARGET_VLAN = "192.168.12.0/24" + # Storing in your requested directory + OUTPUT_FILE = r"D:\hackerstuff\scripts\my_scripts\ai-code\Full_Homelab_Recovery.xlsx" + + os.makedirs(os.path.dirname(OUTPUT_FILE), exist_ok=True) + results = run_exhaustive_scan(TARGET_VLAN) + save_to_excel(results, OUTPUT_FILE) \ No newline at end of file