# 1. Install the full python3 suite (needed for virtual environments)
sudo apt update && sudo apt install python3-full -y
# 2. Create a virtual environment named "venv" in your current directory
python3 -m venv venv
# 3. Activate the virtual environment
source venv/bin/activate
# 4. Install your packages safely inside this isolated environment
pip install ollama requests
# 5. Run your script
python3 auditor.py
import sys
import socket
import requests
import ollama
import json
import urllib3
import re
from urllib.parse import urlparse
# Desactivar advertencias de certificados SSL no válidos
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
MODEL_NAME = "gemma4:e2b"
def obtener_ip(url: str) -> str:
"""Extrae el dominio de la URL y resuelve su dirección IP."""
try:
parsed_url = urlparse(url)
dominio = parsed_url.netloc if parsed_url.netloc else parsed_url.path.split('/')[0]
if ':' in dominio:
dominio = dominio.split(':')[0]
ip = socket.gethostbyname(dominio)
return ip
except Exception:
return "No se pudo resolver la IP"
def limpiar_nombre_dominio(url: str) -> str:
"""Limpia la URL para dejar un nombre de archivo válido basado en el dominio."""
parsed_url = urlparse(url)
dominio = parsed_url.netloc if parsed_url.netloc else parsed_url.path.split('/')[0]
# Remover puertos o caracteres extraños para el sistema de archivos
dominio = dominio.split(':')[0]
return re.sub(r'[^\w\.-]', '_', dominio)
def consultar_al_modelo(prompt: str) -> str:
"""Envía un prompt a gemma4:e2b para obtener instrucciones o análisis."""
try:
response = ollama.generate(
model=MODEL_NAME,
prompt=prompt,
options={
"temperature": 0.1,
"top_p": 0.9
}
)
return response['response']
except Exception as e:
return f"Error al conectar con el modelo: {e}"
def auditar_punto_owasp(base_url: str, categoria_owasp: str, endpoint: str, lista_resumen: list):
print(f"\n[+] Analizando {categoria_owasp} en {base_url}{endpoint}...")
prompt_payload = f"""
Actúa como un experto en ciberseguridad. Para la categoría '{categoria_owasp}',
genera una lista de 3 payloads comunes en formato JSON plano (ej. ["payload1", "payload2", "payload3"]).
Solo devuelve la lista JSON, nada de texto adicional.
"""
respuesta_payloads = consultar_al_modelo(prompt_payload)
try:
payloads = json.loads(respuesta_payloads)
except:
payloads = ["' OR 1=1 --", "<script>alert(1)</script>", "../etc/passwd"]
vulnerable_en_categoria = "NO"
for payload in payloads:
url_prueba = f"{base_url}{endpoint}"
params = {"input": payload, "search": payload, "id": payload, "url": payload}
try:
print(f" [*] Probando payload: {payload}")
response = requests.get(url_prueba, params=params, timeout=5, verify=False)
if response.status_code == 404:
print(f" [!] Advertencia: El endpoint devuelve 404 (No encontrado).")
elif response.status_code == 403:
print(f" [!] Advertencia: Acceso denegado 403 (WAF / Cloudflare activo).")
prompt_analisis = f"""
Analiza la siguiente respuesta HTTP del servidor para determinar si el payload '{payload}'
explotó con éxito una vulnerabilidad de la categoría {categoria_owasp}.
Código de Estado: {response.status_code}
Cuerpo de la respuesta (primeros 500 caracteres):
{response.text[:500] if response.text else '[Cuerpo Vacío]'}
Responde estrictamente con este formato:
DIAMETRO: [SÍ o NO o SOSPECHOSO]
RAZÓN: (Tu breve explicación aquí)
"""
analisis = consultar_al_modelo(prompt_analisis)
print(f" [Resultado AI]:\n{analisis}")
# Búsqueda estricta por línea para evitar falsos positivos
lineas_analisis = analisis.upper().split('\n')
for linea in lineas_analisis:
if "DIAMETRO:" in linea:
if "SÍ" in linea or "SI" in linea:
vulnerable_en_categoria = "SÍ"
break
elif "SOSPECHOSO" in linea and vulnerable_en_categoria != "SÍ":
vulnerable_en_categoria = "SOSPECHOSO"
except requests.exceptions.RequestException as e:
print(f" [-] Error de conexión en este payload: {e}")
vulnerable_en_categoria = "ERROR DE CONEXIÓN"
lista_resumen.append({
"categoria": categoria_owasp,
"endpoint": endpoint,
"estado": vulnerable_en_categoria
})
if __name__ == "__main__":
if len(sys.argv) < 2:
print("\n[!] Error: No especificaste el sitio web objetivo.")
print("Uso correcto: python3 auditor.py <URL_DEL_SITIO>")
print("Ejemplo: python3 auditor.py https://n1g.cl\n")
sys.exit(1)
target_url = sys.argv[1].rstrip("/")
target_ip = obtener_ip(target_url)
nombre_limpio = limpiar_nombre_dominio(target_url)
report_file = f"reporte_{nombre_limpio}.txt"
print(f"Iniciando escáner OWASP asistido por AI ({MODEL_NAME})")
print(f"Objetivo base: {target_url}")
print(f"IP objetivo: {target_ip}")
print(f"Archivo de salida asignado: {report_file}")
resumen_final = []
pruebas = [
{"categoria": "A01:2021-Broken Access Control", "endpoint": "/view.php"},
{"categoria": "A02:2021-Cryptographic Failures", "endpoint": "/config.json"},
{"categoria": "A03:2021-Injection", "endpoint": "/login.php"},
{"categoria": "A04:2021-Insecure Design", "endpoint": "/checkout"},
{"categoria": "A05:2021-Security Misconfiguration", "endpoint": "/admin/"},
{"categoria": "A06:2021-Vulnerable and Outdated Components", "endpoint": "/api/v1/"},
{"categoria": "A07:2021-Identification and Authentication Failures", "endpoint": "/reset-password"},
{"categoria": "A08:2021-Software and Data Integrity Failures", "endpoint": "/update"},
{"categoria": "A09:2021-Security Logging and Monitoring Failures", "endpoint": "/logs/"},
{"categoria": "A10:2021-Server-Side Request Forgery (SSRF)", "endpoint": "/webhook"}
]
for prueba in pruebas:
auditar_punto_owasp(target_url, prueba["categoria"], prueba["endpoint"], resumen_final)
# --- SECCIÓN DEL RESUMEN FINAL ---
lineas_reporte = []
lineas_reporte.append("\n" + "="*50)
lineas_reporte.append(" RESUMEN DE AUDITORÍA OWASP TOP 10")
lineas_reporte.append(f" Objetivo: {target_url}")
lineas_reporte.append(f" IP: {target_ip}")
lineas_reporte.append("="*50)
for i, item in enumerate(resumen_final, start=1):
lineas_reporte.append(f"{i}. {item['categoria']}")
lineas_reporte.append(f" - Objetivo: {item['endpoint']}")
lineas_reporte.append(f" - Estado: {item['estado']}")
lineas_reporte.append("-" * 50)
# Imprimir por consola
texto_final = "\n".join(lineas_reporte)
print(texto_final)
# Guardar en archivo dinámico
with open(report_file, "w", encoding="utf-8") as f:
f.write(texto_final)
print(f"\n[+] El reporte ha sido guardado exitosamente en: {report_file}\n")
#para ejecutar
python3 auditor.py https://tusitio