from scapy.all import rdpcap, Raw, DNS, DNSQR try: from scapy.layers.tls.all import TLS except ImportError: # Fallback or mock if TLS not available, though we use a try-except block in usage TLS = None import re import os from IoTAnalyzer.models import UrlRaw, HashRaw def analyze_pcap_file(pcap_file, raw_dataset_id): """ Analyzes a PCAP file and stores found hashes and URLs in the database. """ print("Start analyzing...") # Adjust the path to the file # Check multiple locations for the file possible_paths = [ os.path.join('/app/files/uploads', pcap_file), # Mounted frontend uploads os.path.join('/app/files', pcap_file), # Shared files os.path.join('Frontend', 'iot-pre-tester-frontend', 'public', 'filesAttachment', pcap_file), # Local dev fallback ] filepath = None for path in possible_paths: if os.path.exists(path): filepath = path break if not filepath: print(f"Fehler: Datei {pcap_file} nicht gefunden in: {possible_paths}") return # Regular expressions for hashes and URLs hash_pattern = re.compile(r"\b[a-fA-F0-9]{32,64}\b") # MD5, SHA1, SHA256 # Stricter URL pattern: # 1. Requires http://, https://, or www. (Standard) # 2. OR Naked domain with AT LEAST 2 dots (e.g. sub.domain.com) to catch cloud URLs but avoid "J.mINT" url_pattern = re.compile( r"\b(?:" r"(?:https?://|www\.)(?:[a-zA-Z0-9.-]+\.[a-zA-Z]{2,6})" # Protocol/www required r"|" r"(?:[a-zA-Z0-9-]+\.){2,}[a-zA-Z]{2,6}" # Naked domain with >= 2 dots r"|" r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}" # IPv4 r")" r"(?:/[a-zA-Z0-9._%/-]*)?\b" ) # Load PCAP file try: packets = rdpcap(filepath) except Exception as e: print(f"Fehler beim Öffnen der PCAP-Datei: {e}") return found_hashes = set() found_urls = set() # Analyze packets for pkt in packets: # 1. DNS Queries (Reliable source for domains) if pkt.haslayer(DNS) and pkt[DNS].qd: try: qname = pkt[DNS].qd.qname.decode('utf-8', errors='ignore') if qname.endswith('.'): qname = qname[:-1] if qname: found_urls.add(qname) except Exception: pass # 2. TLS Server Name Indication (SNI) # Attempt to extract SNI if TLS layer is present if TLS and pkt.haslayer(TLS): try: # Iterate through TLS messages to find ClientHello and extensions if hasattr(pkt[TLS], 'msg'): for msg in pkt[TLS].msg: if hasattr(msg, 'ext'): for ext in msg.ext: if hasattr(ext, 'servernames'): for servername in ext.servernames: if hasattr(servername, 'servername'): sni = servername.servername.decode('utf-8', errors='ignore') if sni: found_urls.add(sni) except Exception: pass # 3. Raw Payload (Fallback with strict regex) if pkt.haslayer(Raw): # Check whether the packet has a payload payload = pkt[Raw].load.decode(errors='ignore') # Search for hashes found_hashes.update(hash_pattern.findall(payload)) # Search for URLs found_urls.update(url_pattern.findall(payload)) # Store results in the database save_urls_to_database(found_urls, raw_dataset_id) save_hashes_to_database(found_hashes, raw_dataset_id) print("Done analyzing.") def save_urls_to_database(urls, raw_dataset_id): """ Stores extracted URLs in the database. """ for url in urls: UrlRaw.objects.create( raw_dataset_id=raw_dataset_id, url=url ) def save_hashes_to_database(hashes, raw_dataset_id): """ Stores extracted hashes in the database. """ for hash_value in hashes: HashRaw.objects.create( raw_dataset_id=raw_dataset_id, hash_value=hash_value )