├── 2.png ├── README.md └── phish_detector.py /2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ccyl13/PhishDetector/HEAD/2.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PhishDetector 2 | 3 | PhishDetector es una herramienta para detectar correos electrónicos de phishing mediante análisis DKIM y SPF. 4 | 5 | ## Captura de Pantalla 6 | 7 | ![PhishDetector Screenshot](https://github.com/ccyl13/PhishDetector/blob/main/2.png) 8 | 9 | > **Nota:** Asegúrate de reemplazar `ruta/a/tu/imagen.png` con la URL correcta de la imagen en tu repositorio o en la web. 10 | 11 | ## Instalación 12 | Dependencias 13 | 14 | Antes de ejecutar el script, instala las siguientes dependencias de Python: 15 | 16 | pip install dkimpy termcolor python-spf whois requests dnspython 17 | 18 | Uso 19 | 20 | Para ejecutar el análisis de un correo electrónico: 21 | 22 | ./phish_detector.py /ruta/al/correo/malwarebytes.eml 23 | 24 | Reemplaza /ruta/al/correo/malwarebytes.eml con la ruta real al archivo .eml que deseas analizar. 25 | 26 | 1. **Clonar el Repositorio** 27 | 28 | ```bash 29 | git clone https://github.com/ccyl13/PhishDetector.git 30 | cd new_phish_detector 31 | chmod +x phish_detector.py 32 | ./phish_detector.py /ruta/detucorreo/nombredelcorreodescargado.eml 33 | -------------------------------------------------------------------------------- /phish_detector.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import re 4 | import sys 5 | import os 6 | import whois 7 | import requests 8 | import dkim 9 | import spf 10 | from email import message_from_binary_file 11 | from email.header import decode_header 12 | from urllib.parse import urlparse 13 | import dns.resolver 14 | from termcolor import colored 15 | 16 | # Configuración de API para VirusTotal y Google Safe Browsing 17 | VIRUSTOTAL_API_KEY = 'your_virustotal_api_key' 18 | GOOGLE_SAFE_BROWSING_API_KEY = 'your_google_safe_browsing_api_key' 19 | 20 | def decode_header_value(header_value): 21 | decoded_parts = decode_header(header_value) 22 | decoded_str = ''.join(part.decode(encoding or 'utf-8') if isinstance(part, bytes) else part for part, encoding in decoded_parts) 23 | return decoded_str 24 | 25 | def analyze_whois_info(domain): 26 | try: 27 | whois_info = whois.whois(domain) 28 | if whois_info.domain_name: 29 | return f"Dominio registrado. Información WHOIS: Registrador: {whois_info.registrar}, Fecha de creación: {whois_info.creation_date}, Fecha de expiración: {whois_info.expiration_date}" 30 | else: 31 | return "Dominio no registrado." 32 | except Exception as e: 33 | return f"Error al obtener WHOIS: {e}" 34 | 35 | def check_url_reputation(url): 36 | headers = {'x-apikey': VIRUSTOTAL_API_KEY} 37 | try: 38 | encoded_url = requests.utils.quote(url) 39 | response = requests.get(f'https://www.virustotal.com/api/v3/urls/{encoded_url}', headers=headers) 40 | data = response.json() 41 | if data.get('data', {}).get('attributes', {}).get('last_analysis_stats', {}).get('malicious', 0) > 0: 42 | return "URL maliciosa en VirusTotal." 43 | except Exception as e: 44 | return f"Error en consulta VirusTotal: {e}" 45 | return None 46 | 47 | def check_google_safe_browsing(url): 48 | payload = { 49 | "client": {"clientId": "your_client_id", "clientVersion": "1.0"}, 50 | "threatInfo": { 51 | "threatTypes": ["MALWARE", "SOCIAL_ENGINEERING"], 52 | "platformTypes": ["ANY_PLATFORM"], 53 | "threatEntryTypes": ["URL"], 54 | "threatEntries": [{"url": url}] 55 | } 56 | } 57 | try: 58 | response = requests.post(f'https://safebrowsing.googleapis.com/v4/threatMatches:find?key={GOOGLE_SAFE_BROWSING_API_KEY}', json=payload) 59 | data = response.json() 60 | if 'matches' in data: 61 | return "URL maliciosa en Google Safe Browsing." 62 | except Exception as e: 63 | return f"Error en consulta Google Safe Browsing: {e}" 64 | return None 65 | 66 | def check_dkim(email): 67 | dkim_signature = email.get('DKIM-Signature', '') 68 | if dkim_signature: 69 | try: 70 | dkim_status = dkim.verify(email.as_bytes()) 71 | return "DKIM válido." if dkim_status else "DKIM inválido." 72 | except Exception as e: 73 | return f"Error en verificación DKIM: {e}" 74 | return "No se encontró DKIM." 75 | 76 | def check_spf(email_from): 77 | domain = email_from.split('@')[-1] 78 | try: 79 | result, explanation = spf.check2('192.0.2.1', domain, 'recipient@example.com') # Reemplaza con la IP del servidor de correo real 80 | if result == 'pass': 81 | return "SPF válido." 82 | elif result == 'fail': 83 | return f"Error en verificación SPF: {explanation}" 84 | elif result == 'neutral': 85 | return "SPF neutral: El dominio no tiene una política clara." 86 | elif result == 'temperror': 87 | return "Error temporal en verificación SPF." 88 | elif result == 'permerror': 89 | return "Error permanente en verificación SPF." 90 | else: 91 | return f"Resultado SPF desconocido: {result}" 92 | except Exception as e: 93 | return f"Error en verificación SPF: {e}" 94 | 95 | def analyze_headers(headers): 96 | anomalies = [] 97 | from_header = headers.get('From', '') 98 | from_address = re.findall(r'<(.*?)>', from_header) 99 | if from_address: 100 | from_domain = from_address[0].split('@')[-1] 101 | trusted_domains = ['trusted.com', 'example.com'] 102 | if from_domain not in trusted_domains: 103 | anomalies.append(colored(f"Dominio del remitente sospechoso: {from_domain}", 'yellow')) 104 | 105 | spf_result = check_spf(from_address[0]) 106 | if 'Error' in spf_result: 107 | anomalies.append(colored(spf_result, 'red')) 108 | elif "sospechoso" in spf_result.lower(): 109 | anomalies.append(colored(spf_result, 'yellow')) 110 | 111 | return anomalies 112 | 113 | def analyze_attachments(email): 114 | suspicious_attachments = [] 115 | for part in email.walk(): 116 | if part.get_content_maintype() == 'multipart': 117 | continue 118 | filename = part.get_filename() 119 | if filename and filename.lower().endswith(('.exe', '.bat')): 120 | suspicious_attachments.append(colored(f"Adjunto peligroso detectado: {filename}", 'red')) 121 | return suspicious_attachments 122 | 123 | def es_phishing(email_file_path): 124 | report = [] 125 | 126 | try: 127 | with open(email_file_path, 'rb') as f: 128 | email = message_from_binary_file(f) 129 | 130 | headers = dict(email.items()) 131 | 132 | # Información adicional del correo 133 | subject = decode_header_value(headers.get('Subject', 'No Subject')) 134 | date = headers.get('Date', 'No Date') 135 | size = os.path.getsize(email_file_path) 136 | 137 | # Verifica si hay contenido en el mensaje 138 | if email.is_multipart(): 139 | content = '' 140 | for part in email.walk(): 141 | if part.get_content_type() == 'text/plain': 142 | content = part.get_payload(decode=True) 143 | break 144 | else: 145 | content = email.get_payload(decode=True) 146 | 147 | if content: 148 | content = content.decode('utf-8', errors='ignore') 149 | else: 150 | content = "" 151 | 152 | urls = re.findall(r'http[s]?://\S+', content) 153 | 154 | # Añadir encabezado y detalles 155 | report.append(colored(" _____ _ _ _ _____ _ _ ", 'cyan')) 156 | report.append(colored("| __ \\| | (_) | | | __ \\ | | | |", 'cyan')) 157 | report.append(colored("| |__) | |__ _ ___| |__ | | | | ___| |_ ___ ___| |_ ___ _ __", 'cyan')) 158 | report.append(colored("| ___/| '_ \\| / __| '_ \\| | | |/ _ \\ __/ _ \\/ __| __/ _ \\| '__|", 'cyan')) 159 | report.append(colored("| | | | | | \\__ \\ | | | |__| | __/ || __/ (__| || (_) | |", 'cyan')) 160 | report.append(colored("|_| |_| |_|_|___/_| |_|_____/ \\___|\\__\\___|\\___|\\__\\___/|_|", 'cyan')) 161 | report.append(colored("", 'cyan')) 162 | report.append(colored("Created by Thomas O'Neil", 'cyan')) 163 | report.append(colored("", 'cyan')) 164 | report.append(colored("Iniciando el análisis del correo electrónico...", 'cyan')) 165 | report.append(colored(f" - Asunto: {subject}", 'blue')) 166 | report.append(colored(f" - Fecha: {date}", 'blue')) 167 | report.append(colored(f" - Tamaño: {size} bytes", 'blue')) 168 | 169 | # Análisis DKIM 170 | dkim_status = check_dkim(email) 171 | report.append(colored(f"- DKIM: {dkim_status}", 'green')) 172 | 173 | # Análisis SPF 174 | spf_result = check_spf(headers.get('From', '')) 175 | if 'Error' in spf_result: 176 | report.append(colored(f"- SPF: {spf_result}", 'red')) 177 | elif "sospechoso" in spf_result.lower(): 178 | report.append(colored(f"- SPF: {spf_result}", 'yellow')) 179 | 180 | # Análisis WHOIS 181 | from_domain = headers.get('From', '').split('@')[-1] 182 | whois_result = analyze_whois_info(from_domain) 183 | report.append(colored(f"- WHOIS: {whois_result}", 'green')) 184 | 185 | # Análisis de URL 186 | for url in urls: 187 | url_check = check_url_reputation(url) or check_google_safe_browsing(url) 188 | if url_check: 189 | report.append(colored(url_check, 'red')) 190 | 191 | # Análisis de archivos adjuntos 192 | attachments = analyze_attachments(email) 193 | if attachments: 194 | report.extend(attachments) 195 | 196 | # Resultados del análisis 197 | header_anomalies = analyze_headers(headers) 198 | if header_anomalies: 199 | report.extend(header_anomalies) 200 | 201 | if not any(["sospechoso" in line.lower() for line in report]): 202 | report.append(colored("No se encontraron problemas graves en el análisis del correo.", 'green')) 203 | else: 204 | report.append(colored("¡ALERTA: Posible correo de phishing detectado!", 'red')) 205 | 206 | except Exception as e: 207 | report.append(colored(f"Error al analizar el correo: {e}", 'red')) 208 | 209 | return '\n'.join(report) 210 | 211 | if __name__ == '__main__': 212 | if len(sys.argv) != 2: 213 | print(colored("Uso: ./phish_detector.py ", 'red')) 214 | sys.exit(1) 215 | 216 | email_file_path = sys.argv[1] 217 | if not os.path.isfile(email_file_path): 218 | print(colored(f"El archivo {email_file_path} no existe.", 'red')) 219 | sys.exit(1) 220 | 221 | print(es_phishing(email_file_path)) 222 | --------------------------------------------------------------------------------