improvement
This commit is contained in:
		
							parent
							
								
									a9addf7031
								
							
						
					
					
						commit
						5d0e095a81
					
				
							
								
								
									
										419
									
								
								dnsrecon.py
									
									
									
									
									
								
							
							
						
						
									
										419
									
								
								dnsrecon.py
									
									
									
									
									
								
							@ -77,15 +77,24 @@ class DNSReconTool:
 | 
			
		||||
        if output and not output.startswith("Error:"):
 | 
			
		||||
            for line in output.split('\n'):
 | 
			
		||||
                line = line.strip()
 | 
			
		||||
                if line and not line.startswith(';'):
 | 
			
		||||
                if line and not line.startswith(';') and not line.startswith('>>'):
 | 
			
		||||
                    # Split on whitespace, but preserve quoted strings
 | 
			
		||||
                    parts = line.split(None, 4)
 | 
			
		||||
                    if len(parts) >= 4:
 | 
			
		||||
                    if len(parts) >= 5:  # name, ttl, class, type, data
 | 
			
		||||
                        records.append({
 | 
			
		||||
                            'name': parts[0],
 | 
			
		||||
                            'name': parts[0].rstrip('.'),  # Remove trailing dot
 | 
			
		||||
                            'ttl': parts[1],
 | 
			
		||||
                            'class': parts[2], 
 | 
			
		||||
                            'type': parts[3],
 | 
			
		||||
                            'data': parts[4]
 | 
			
		||||
                        })
 | 
			
		||||
                    elif len(parts) == 4:  # Sometimes no data field
 | 
			
		||||
                        records.append({
 | 
			
		||||
                            'name': parts[0].rstrip('.'),
 | 
			
		||||
                            'ttl': parts[1],
 | 
			
		||||
                            'class': parts[2],
 | 
			
		||||
                            'type': parts[3],
 | 
			
		||||
                            'data': ' '.join(parts[4:]) if len(parts) > 4 else ''
 | 
			
		||||
                            'data': ''
 | 
			
		||||
                        })
 | 
			
		||||
        
 | 
			
		||||
        return {
 | 
			
		||||
@ -258,6 +267,254 @@ class DNSReconTool:
 | 
			
		||||
                'message': 'Shodan query failed'
 | 
			
		||||
            }
 | 
			
		||||
    
 | 
			
		||||
    def _write_dns_section(self, f, title: str, records: List[Dict], data_extractor):
 | 
			
		||||
        """Helper method to write DNS record sections."""
 | 
			
		||||
        if records:
 | 
			
		||||
            f.write(f"\n{title}:\n")
 | 
			
		||||
            for record in records:
 | 
			
		||||
                data = data_extractor(record)
 | 
			
		||||
                f.write(f"  {data}\n")
 | 
			
		||||
        else:
 | 
			
		||||
            f.write(f"\n{title}: None found\n")
 | 
			
		||||
 | 
			
		||||
    def _write_dns_server_comparison(self, f, dns_data: Dict):
 | 
			
		||||
        """Compare responses from different DNS servers."""
 | 
			
		||||
        servers = ['system', '1.1.1.1', '8.8.8.8', '9.9.9.9']
 | 
			
		||||
        record_types = ['A', 'AAAA', 'MX', 'NS']
 | 
			
		||||
        
 | 
			
		||||
        discrepancies_found = False
 | 
			
		||||
        
 | 
			
		||||
        for record_type in record_types:
 | 
			
		||||
            if record_type in dns_data:
 | 
			
		||||
                server_results = {}
 | 
			
		||||
                for server in servers:
 | 
			
		||||
                    if server in dns_data[record_type]:
 | 
			
		||||
                        records = dns_data[record_type][server].get('records', [])
 | 
			
		||||
                        server_results[server] = set(r.get('data', '') for r in records if r.get('data'))
 | 
			
		||||
                
 | 
			
		||||
                # Check for discrepancies
 | 
			
		||||
                if len(server_results) > 1:
 | 
			
		||||
                    all_results = list(server_results.values())
 | 
			
		||||
                    if not all(result == all_results[0] for result in all_results):
 | 
			
		||||
                        if not discrepancies_found:
 | 
			
		||||
                            discrepancies_found = True
 | 
			
		||||
                        f.write(f"  ⚠️  {record_type} records differ between DNS servers:\n")
 | 
			
		||||
                        for server, records in server_results.items():
 | 
			
		||||
                            f.write(f"    {server}: {', '.join(sorted(records)) if records else 'No records'}\n")
 | 
			
		||||
        
 | 
			
		||||
        if not discrepancies_found:
 | 
			
		||||
            f.write("  ✅ All DNS servers return consistent results\n")
 | 
			
		||||
 | 
			
		||||
    def create_summary_report(self, results: Dict[str, Any], filename: str) -> None:
 | 
			
		||||
        """Create comprehensive human-readable summary report."""
 | 
			
		||||
        with open(filename, 'w', encoding='utf-8') as f:
 | 
			
		||||
            f.write(f"DNS Reconnaissance Report\n")
 | 
			
		||||
            f.write(f"{'='*50}\n")
 | 
			
		||||
            f.write(f"Domain: {results['domain']}\n")
 | 
			
		||||
            f.write(f"Timestamp: {results['timestamp']}\n\n")
 | 
			
		||||
            
 | 
			
		||||
            dns_data = results.get('dns_records', {})
 | 
			
		||||
            
 | 
			
		||||
            # Helper function to get records from system DNS
 | 
			
		||||
            def get_system_records(record_type):
 | 
			
		||||
                return dns_data.get(record_type, {}).get('system', {}).get('records', [])
 | 
			
		||||
            
 | 
			
		||||
            # A Records (IPv4)
 | 
			
		||||
            self._write_dns_section(f, "A Records (IPv4)", get_system_records('A'), 
 | 
			
		||||
                                   lambda r: r.get('data', 'N/A'))
 | 
			
		||||
            
 | 
			
		||||
            # AAAA Records (IPv6)  
 | 
			
		||||
            self._write_dns_section(f, "AAAA Records (IPv6)", get_system_records('AAAA'),
 | 
			
		||||
                                   lambda r: r.get('data', 'N/A'))
 | 
			
		||||
            
 | 
			
		||||
            # MX Records (Mail Servers)
 | 
			
		||||
            mx_records = get_system_records('MX')
 | 
			
		||||
            if mx_records:
 | 
			
		||||
                f.write(f"\nMX Records (Mail Servers):\n")
 | 
			
		||||
                for record in mx_records:
 | 
			
		||||
                    data_parts = record.get('data', '').split()
 | 
			
		||||
                    priority = data_parts[0] if data_parts else 'N/A'
 | 
			
		||||
                    server = ' '.join(data_parts[1:]) if len(data_parts) > 1 else 'N/A'
 | 
			
		||||
                    f.write(f"  Priority {priority}: {server}\n")
 | 
			
		||||
            else:
 | 
			
		||||
                f.write(f"\nMX Records (Mail Servers): None found\n")
 | 
			
		||||
            
 | 
			
		||||
            # NS Records (Name Servers)
 | 
			
		||||
            self._write_dns_section(f, "NS Records (Name Servers)", get_system_records('NS'),
 | 
			
		||||
                                   lambda r: r.get('data', 'N/A'))
 | 
			
		||||
            
 | 
			
		||||
            # CNAME Records
 | 
			
		||||
            self._write_dns_section(f, "CNAME Records", get_system_records('CNAME'),
 | 
			
		||||
                                   lambda r: f"{r.get('name', 'N/A')} -> {r.get('data', 'N/A')}")
 | 
			
		||||
            
 | 
			
		||||
            # TXT Records
 | 
			
		||||
            txt_records = get_system_records('TXT')
 | 
			
		||||
            if txt_records:
 | 
			
		||||
                f.write(f"\nTXT Records:\n")
 | 
			
		||||
                for record in txt_records:
 | 
			
		||||
                    txt_data = record.get('data', '').strip()
 | 
			
		||||
                    # Clean up quoted text
 | 
			
		||||
                    if txt_data.startswith('"') and txt_data.endswith('"'):
 | 
			
		||||
                        txt_data = txt_data[1:-1]
 | 
			
		||||
                    
 | 
			
		||||
                    # Identify common TXT record types
 | 
			
		||||
                    if txt_data.startswith('v=spf1'):
 | 
			
		||||
                        f.write(f"  [SPF] {txt_data}\n")
 | 
			
		||||
                    elif txt_data.startswith('v=DMARC1'):
 | 
			
		||||
                        f.write(f"  [DMARC] {txt_data}\n")
 | 
			
		||||
                    elif txt_data.startswith('v=DKIM1'):
 | 
			
		||||
                        f.write(f"  [DKIM] {txt_data}\n")
 | 
			
		||||
                    elif 'google-site-verification' in txt_data:
 | 
			
		||||
                        f.write(f"  [Google Verification] {txt_data[:50]}...\n")
 | 
			
		||||
                    else:
 | 
			
		||||
                        f.write(f"  {txt_data}\n")
 | 
			
		||||
            else:
 | 
			
		||||
                f.write(f"\nTXT Records: None found\n")
 | 
			
		||||
            
 | 
			
		||||
            # CAA Records (Certificate Authority Authorization)
 | 
			
		||||
            caa_records = get_system_records('CAA')
 | 
			
		||||
            if caa_records:
 | 
			
		||||
                f.write(f"\nCAA Records (Certificate Authority Authorization):\n")
 | 
			
		||||
                for record in caa_records:
 | 
			
		||||
                    data_parts = record.get('data', '').split()
 | 
			
		||||
                    if len(data_parts) >= 3:
 | 
			
		||||
                        flags = data_parts[0]
 | 
			
		||||
                        tag = data_parts[1]
 | 
			
		||||
                        value = ' '.join(data_parts[2:]).strip('"')
 | 
			
		||||
                        f.write(f"  {flags} {tag} {value}\n")
 | 
			
		||||
                    else:
 | 
			
		||||
                        f.write(f"  {record.get('data', 'N/A')}\n")
 | 
			
		||||
            else:
 | 
			
		||||
                f.write(f"\nCAA Records: None found\n")
 | 
			
		||||
            
 | 
			
		||||
            # SRV Records
 | 
			
		||||
            srv_records = get_system_records('SRV')
 | 
			
		||||
            if srv_records:
 | 
			
		||||
                f.write(f"\nSRV Records (Service Records):\n")
 | 
			
		||||
                for record in srv_records:
 | 
			
		||||
                    data_parts = record.get('data', '').split()
 | 
			
		||||
                    if len(data_parts) >= 4:
 | 
			
		||||
                        priority, weight, port, target = data_parts[:4]
 | 
			
		||||
                        f.write(f"  {record.get('name', 'N/A')}\n")
 | 
			
		||||
                        f.write(f"    Priority: {priority}, Weight: {weight}\n")
 | 
			
		||||
                        f.write(f"    Port: {port}, Target: {target}\n")
 | 
			
		||||
                    else:
 | 
			
		||||
                        f.write(f"  {record.get('data', 'N/A')}\n")
 | 
			
		||||
            else:
 | 
			
		||||
                f.write(f"\nSRV Records: None found\n")
 | 
			
		||||
            
 | 
			
		||||
            # SOA Record (Start of Authority)
 | 
			
		||||
            soa_records = get_system_records('SOA')
 | 
			
		||||
            if soa_records:
 | 
			
		||||
                f.write(f"\nSOA Record (Zone Authority):\n")
 | 
			
		||||
                for record in soa_records:
 | 
			
		||||
                    data_parts = record.get('data', '').split()
 | 
			
		||||
                    if len(data_parts) >= 7:
 | 
			
		||||
                        primary_ns, admin_email = data_parts[:2]
 | 
			
		||||
                        serial, refresh, retry, expire, minimum = data_parts[2:7]
 | 
			
		||||
                        f.write(f"  Primary Name Server: {primary_ns}\n")
 | 
			
		||||
                        f.write(f"  Admin Email: {admin_email}\n")
 | 
			
		||||
                        f.write(f"  Serial: {serial}\n")
 | 
			
		||||
                        f.write(f"  Refresh: {refresh}s, Retry: {retry}s\n")
 | 
			
		||||
                        f.write(f"  Expire: {expire}s, Minimum TTL: {minimum}s\n")
 | 
			
		||||
                    else:
 | 
			
		||||
                        f.write(f"  {record.get('data', 'N/A')}\n")
 | 
			
		||||
            else:
 | 
			
		||||
                f.write(f"\nSOA Record: None found\n")
 | 
			
		||||
            
 | 
			
		||||
            # DNSSEC Information
 | 
			
		||||
            dnssec_data = dns_data.get('DNSSEC', {}).get('system', {})
 | 
			
		||||
            dnssec_output = dnssec_data.get('raw_output', '')
 | 
			
		||||
            if dnssec_output and not dnssec_output.startswith('Error:') and dnssec_output.strip():
 | 
			
		||||
                f.write(f"\nDNSSEC Status:\n")
 | 
			
		||||
                f.write("-" * 14 + "\n")
 | 
			
		||||
                if 'RRSIG' in dnssec_output or 'DNSKEY' in dnssec_output:
 | 
			
		||||
                    f.write(f"  ✅ DNSSEC is enabled\n")
 | 
			
		||||
                else:
 | 
			
		||||
                    f.write(f"  ❌ DNSSEC not detected\n")
 | 
			
		||||
            else:
 | 
			
		||||
                f.write(f"\nDNSSEC Status: Unable to determine\n")
 | 
			
		||||
            
 | 
			
		||||
            # DNS Server Comparison (show discrepancies)
 | 
			
		||||
            f.write(f"\nDNS Server Comparison:\n")
 | 
			
		||||
            f.write("-" * 21 + "\n")
 | 
			
		||||
            self._write_dns_server_comparison(f, dns_data)
 | 
			
		||||
            
 | 
			
		||||
            # Enhanced WHOIS Information
 | 
			
		||||
            whois_data = results.get('whois', {})
 | 
			
		||||
            if whois_data.get('parsed'):
 | 
			
		||||
                f.write(f"\nWHOIS Information\n")
 | 
			
		||||
                f.write("-" * 17 + "\n")
 | 
			
		||||
                parsed = whois_data['parsed']
 | 
			
		||||
                
 | 
			
		||||
                # Domain info
 | 
			
		||||
                for field in ['domain_name', 'domain']:
 | 
			
		||||
                    if field in parsed:
 | 
			
		||||
                        f.write(f"Domain: {parsed[field]}\n")
 | 
			
		||||
                        break
 | 
			
		||||
                
 | 
			
		||||
                # Registrar info
 | 
			
		||||
                for field in ['registrar', 'sponsoring_registrar']:
 | 
			
		||||
                    if field in parsed:
 | 
			
		||||
                        f.write(f"Registrar: {parsed[field]}\n")
 | 
			
		||||
                        break
 | 
			
		||||
                
 | 
			
		||||
                # Important dates
 | 
			
		||||
                for field in ['creation_date', 'created']:
 | 
			
		||||
                    if field in parsed:
 | 
			
		||||
                        f.write(f"Created: {parsed[field]}\n")
 | 
			
		||||
                        break
 | 
			
		||||
                        
 | 
			
		||||
                for field in ['expiration_date', 'registry_expiry_date', 'expires']:
 | 
			
		||||
                    if field in parsed:
 | 
			
		||||
                        f.write(f"Expires: {parsed[field]}\n")
 | 
			
		||||
                        break
 | 
			
		||||
                        
 | 
			
		||||
                for field in ['updated_date', 'changed', 'last_updated']:
 | 
			
		||||
                    if field in parsed:
 | 
			
		||||
                        f.write(f"Last Updated: {parsed[field]}\n")
 | 
			
		||||
                        break
 | 
			
		||||
                
 | 
			
		||||
                # Status
 | 
			
		||||
                for field in ['status', 'domain_status']:
 | 
			
		||||
                    if field in parsed:
 | 
			
		||||
                        f.write(f"Status: {parsed[field]}\n")
 | 
			
		||||
                        break
 | 
			
		||||
                
 | 
			
		||||
                # Name servers from WHOIS
 | 
			
		||||
                ns_fields = [k for k in parsed.keys() if 'name_server' in k.lower() or k.lower().startswith('nserver')]
 | 
			
		||||
                if ns_fields:
 | 
			
		||||
                    f.write(f"WHOIS Name Servers:\n")
 | 
			
		||||
                    for field in sorted(ns_fields)[:10]:  # Limit to 10
 | 
			
		||||
                        f.write(f"  {parsed[field]}\n")
 | 
			
		||||
            
 | 
			
		||||
            # Certificate transparency section
 | 
			
		||||
            cert_data = results.get('certificate_transparency', {})
 | 
			
		||||
            if cert_data.get('success'):
 | 
			
		||||
                subdomain_count = cert_data.get('subdomain_count', 0)
 | 
			
		||||
                f.write(f"\nSubdomains from Certificate Logs ({subdomain_count} total):\n")
 | 
			
		||||
                f.write("-" * 45 + "\n")
 | 
			
		||||
                subdomains = cert_data.get('unique_subdomains', [])
 | 
			
		||||
                
 | 
			
		||||
                display_count = min(50, len(subdomains))
 | 
			
		||||
                for subdomain in subdomains[:display_count]:
 | 
			
		||||
                    f.write(f"  {subdomain}\n")
 | 
			
		||||
                
 | 
			
		||||
                if len(subdomains) > display_count:
 | 
			
		||||
                    f.write(f"  ... and {len(subdomains) - display_count} more\n")
 | 
			
		||||
            
 | 
			
		||||
            # Shodan section
 | 
			
		||||
            shodan_data = results.get('shodan', {})
 | 
			
		||||
            if shodan_data.get('success') and shodan_data.get('total_results', 0) > 0:
 | 
			
		||||
                f.write(f"\nShodan Results ({shodan_data.get('total_results', 0)} total):\n")
 | 
			
		||||
                f.write("-" * 25 + "\n")
 | 
			
		||||
                for match in shodan_data.get('matches', [])[:5]:
 | 
			
		||||
                    f.write(f"  IP: {match.get('ip_str', 'N/A')}\n")
 | 
			
		||||
                    f.write(f"  Port: {match.get('port', 'N/A')}\n")
 | 
			
		||||
                    f.write(f"  Service: {match.get('product', 'N/A')}\n")
 | 
			
		||||
                    f.write(f"  Organization: {match.get('org', 'N/A')}\n")
 | 
			
		||||
                    f.write("  ---\n")
 | 
			
		||||
 | 
			
		||||
    def save_results(self, domain: str, results: Dict[str, Any]) -> None:
 | 
			
		||||
        """Save results in multiple formats."""
 | 
			
		||||
        if not os.path.exists(self.output_dir):
 | 
			
		||||
@ -278,159 +535,7 @@ class DNSReconTool:
 | 
			
		||||
        print(f"\n📄 Results saved:")
 | 
			
		||||
        print(f"   JSON: {json_file}")
 | 
			
		||||
        print(f"   Summary: {txt_file}")
 | 
			
		||||
    
 | 
			
		||||
    def create_summary_report(self, results: Dict[str, Any], filename: str) -> None:
 | 
			
		||||
        """Create human-readable summary report."""
 | 
			
		||||
        with open(filename, 'w', encoding='utf-8') as f:
 | 
			
		||||
            f.write(f"DNS Reconnaissance Report\n")
 | 
			
		||||
            f.write(f"{'='*50}\n")
 | 
			
		||||
            f.write(f"Domain: {results['domain']}\n")
 | 
			
		||||
            f.write(f"Timestamp: {results['timestamp']}\n\n")
 | 
			
		||||
            
 | 
			
		||||
            # DNS Summary - improved parsing
 | 
			
		||||
            f.write("DNS Records Summary\n")
 | 
			
		||||
            f.write("-" * 20 + "\n")
 | 
			
		||||
            
 | 
			
		||||
            dns_data = results.get('dns_records', {})
 | 
			
		||||
            
 | 
			
		||||
            # A Records
 | 
			
		||||
            if 'A' in dns_data:
 | 
			
		||||
                system_records = dns_data['A'].get('system', {}).get('records', [])
 | 
			
		||||
                if system_records:
 | 
			
		||||
                    f.write(f"\nA Records (IPv4):\n")
 | 
			
		||||
                    for record in system_records:
 | 
			
		||||
                        ip = record.get('data') or record.get('type', 'N/A')
 | 
			
		||||
                        f.write(f"  {ip}\n")
 | 
			
		||||
                else:
 | 
			
		||||
                    f.write(f"\nA Records (IPv4): None found\n")
 | 
			
		||||
            
 | 
			
		||||
            # AAAA Records
 | 
			
		||||
            if 'AAAA' in dns_data:
 | 
			
		||||
                system_records = dns_data['AAAA'].get('system', {}).get('records', [])
 | 
			
		||||
                if system_records:
 | 
			
		||||
                    f.write(f"\nAAAA Records (IPv6):\n")
 | 
			
		||||
                    for record in system_records:
 | 
			
		||||
                        ipv6 = record.get('data') or record.get('type', 'N/A')
 | 
			
		||||
                        f.write(f"  {ipv6}\n")
 | 
			
		||||
                else:
 | 
			
		||||
                    f.write(f"\nAAAA Records (IPv6): None found\n")
 | 
			
		||||
            
 | 
			
		||||
            # MX Records
 | 
			
		||||
            if 'MX' in dns_data:
 | 
			
		||||
                system_records = dns_data['MX'].get('system', {}).get('records', [])
 | 
			
		||||
                if system_records:
 | 
			
		||||
                    f.write(f"\nMX Records (Mail Servers):\n")
 | 
			
		||||
                    for record in system_records:
 | 
			
		||||
                        priority = record.get('type', '')
 | 
			
		||||
                        server = record.get('data', 'N/A')
 | 
			
		||||
                        f.write(f"  Priority {priority}: {server}\n")
 | 
			
		||||
                else:
 | 
			
		||||
                    f.write(f"\nMX Records (Mail Servers): None found\n")
 | 
			
		||||
            
 | 
			
		||||
            # NS Records
 | 
			
		||||
            if 'NS' in dns_data:
 | 
			
		||||
                system_records = dns_data['NS'].get('system', {}).get('records', [])
 | 
			
		||||
                if system_records:
 | 
			
		||||
                    f.write(f"\nNS Records (Name Servers):\n")
 | 
			
		||||
                    for record in system_records:
 | 
			
		||||
                        ns = record.get('data') or record.get('type', 'N/A')
 | 
			
		||||
                        f.write(f"  {ns}\n")
 | 
			
		||||
                else:
 | 
			
		||||
                    f.write(f"\nNS Records (Name Servers): None found\n")
 | 
			
		||||
            
 | 
			
		||||
            # TXT Records
 | 
			
		||||
            if 'TXT' in dns_data:
 | 
			
		||||
                system_records = dns_data['TXT'].get('system', {}).get('records', [])
 | 
			
		||||
                if system_records:
 | 
			
		||||
                    f.write(f"\nTXT Records:\n")
 | 
			
		||||
                    for record in system_records:
 | 
			
		||||
                        txt_data = record.get('data', '')
 | 
			
		||||
                        txt_type = record.get('type', '')
 | 
			
		||||
                        full_txt = f"{txt_type} {txt_data}".strip()
 | 
			
		||||
                        if full_txt.startswith('"') and full_txt.endswith('"'):
 | 
			
		||||
                            full_txt = full_txt[1:-1]  # Remove quotes
 | 
			
		||||
                        f.write(f"  {full_txt}\n")
 | 
			
		||||
                else:
 | 
			
		||||
                    f.write(f"\nTXT Records: None found\n")
 | 
			
		||||
            
 | 
			
		||||
            # SOA Record
 | 
			
		||||
            if 'SOA' in dns_data:
 | 
			
		||||
                system_records = dns_data['SOA'].get('system', {}).get('records', [])
 | 
			
		||||
                if system_records:
 | 
			
		||||
                    f.write(f"\nSOA Record (Zone Authority):\n")
 | 
			
		||||
                    for record in system_records:
 | 
			
		||||
                        primary_ns = record.get('type', 'N/A')
 | 
			
		||||
                        soa_data = record.get('data', 'N/A')
 | 
			
		||||
                        f.write(f"  Primary NS: {primary_ns}\n")
 | 
			
		||||
                        f.write(f"  Details: {soa_data}\n")
 | 
			
		||||
                else:
 | 
			
		||||
                    f.write(f"\nSOA Record: None found\n")
 | 
			
		||||
            
 | 
			
		||||
            # WHOIS Summary
 | 
			
		||||
            whois_data = results.get('whois', {})
 | 
			
		||||
            if whois_data.get('parsed'):
 | 
			
		||||
                f.write(f"\nWHOIS Information\n")
 | 
			
		||||
                f.write("-" * 17 + "\n")
 | 
			
		||||
                parsed = whois_data['parsed']
 | 
			
		||||
                if 'domain' in parsed:
 | 
			
		||||
                    f.write(f"Domain: {parsed['domain']}\n")
 | 
			
		||||
                if 'changed' in parsed:
 | 
			
		||||
                    f.write(f"Last Updated: {parsed['changed']}\n")
 | 
			
		||||
                if 'status' in parsed:
 | 
			
		||||
                    f.write(f"Status: {parsed['status']}\n")
 | 
			
		||||
            
 | 
			
		||||
            # Certificate Transparency - show more subdomains
 | 
			
		||||
            cert_data = results.get('certificate_transparency', {})
 | 
			
		||||
            if cert_data.get('success'):
 | 
			
		||||
                subdomain_count = cert_data.get('subdomain_count', 0)
 | 
			
		||||
                f.write(f"\nSubdomains from Certificate Logs ({subdomain_count} total):\n")
 | 
			
		||||
                f.write("-" * 45 + "\n")
 | 
			
		||||
                subdomains = cert_data.get('unique_subdomains', [])
 | 
			
		||||
                
 | 
			
		||||
                # Show more subdomains, not just 20
 | 
			
		||||
                display_count = min(50, len(subdomains))  # Show up to 50
 | 
			
		||||
                for subdomain in subdomains[:display_count]:
 | 
			
		||||
                    f.write(f"  {subdomain}\n")
 | 
			
		||||
                
 | 
			
		||||
                if len(subdomains) > display_count:
 | 
			
		||||
                    f.write(f"  ... and {len(subdomains) - display_count} more\n")
 | 
			
		||||
                
 | 
			
		||||
                # Show recent certificates
 | 
			
		||||
                certs = cert_data.get('certificates', [])
 | 
			
		||||
                if certs:
 | 
			
		||||
                    f.write(f"\nRecent SSL Certificates:\n")
 | 
			
		||||
                    f.write("-" * 23 + "\n")
 | 
			
		||||
                    for cert in certs[:5]:  # Show first 5 certificates
 | 
			
		||||
                        f.write(f"  {cert.get('common_name', 'N/A')}\n")
 | 
			
		||||
                        f.write(f"    Issuer: {cert.get('issuer', 'N/A')}\n")
 | 
			
		||||
                        f.write(f"    Valid: {cert.get('not_before', 'N/A')} to {cert.get('not_after', 'N/A')}\n\n")
 | 
			
		||||
            
 | 
			
		||||
            # Shodan Summary - more detailed
 | 
			
		||||
            shodan_data = results.get('shodan', {})
 | 
			
		||||
            if shodan_data.get('success') and shodan_data.get('total_results', 0) > 0:
 | 
			
		||||
                f.write(f"Shodan Results ({shodan_data.get('total_results', 0)} total):\n")
 | 
			
		||||
                f.write("-" * 25 + "\n")
 | 
			
		||||
                for match in shodan_data.get('matches', [])[:10]:  # Show up to 10 matches
 | 
			
		||||
                    f.write(f"  IP: {match.get('ip_str', 'N/A')}\n")
 | 
			
		||||
                    f.write(f"  Port: {match.get('port', 'N/A')}\n")
 | 
			
		||||
                    f.write(f"  Transport: {match.get('transport', 'N/A')}\n")
 | 
			
		||||
                    f.write(f"  ISP: {match.get('isp', 'N/A')}\n")
 | 
			
		||||
                    f.write(f"  Organization: {match.get('org', 'N/A')}\n")
 | 
			
		||||
                    f.write(f"  Location: {match.get('location', {}).get('city', 'N/A')}, {match.get('location', {}).get('country_name', 'N/A')}\n")
 | 
			
		||||
                    
 | 
			
		||||
                    # SSL info if available
 | 
			
		||||
                    if 'ssl' in match and match['ssl'].get('cert'):
 | 
			
		||||
                        cert = match['ssl']['cert']
 | 
			
		||||
                        f.write(f"  SSL Subject: {cert.get('subject', {}).get('CN', 'N/A')}\n")
 | 
			
		||||
                        f.write(f"  SSL Expires: {cert.get('expires', 'N/A')}\n")
 | 
			
		||||
                    
 | 
			
		||||
                    f.write(f"  ---\n")
 | 
			
		||||
            else:
 | 
			
		||||
                f.write(f"\nShodan Results: No data available\n")
 | 
			
		||||
                if not shodan_data.get('success'):
 | 
			
		||||
                    error_msg = shodan_data.get('message', 'Unknown error')
 | 
			
		||||
                    f.write(f"  Error: {error_msg}\n")
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    def run_reconnaissance(self, domain: str) -> Dict[str, Any]:
 | 
			
		||||
        """Run complete DNS reconnaissance."""
 | 
			
		||||
        print(f"\n🚀 Starting DNS reconnaissance for: {domain}")
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user