Saturday, September 12, 2026

Auditor top 10 owasp en python usando modelo gemma4:e2b

 # 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


import sys

import socket

import requests

import ollama

import json

import urllib3

import re

import time

import os

from urllib.parse import urlparse

 

# --- IMPORTACIÓN DE SENSORES NVIDIA ---

try:

    import pynvml

    pynvml.nvmlInit()

    HAS_GPU = True

except Exception:

    HAS_GPU = False

 

# Desactivar advertencias de certificados SSL no válidos

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

 

MODEL_NAME = "gemma4:e2b"

 

# --- MÉTRICAS GLOBALES ---

METRICAS_LLM = {

    "total_tokens_eval": 0,

    "total_tokens_gen": 0,

    "total_tiempo_ollama": 0.0,

    "vram_muestras": []

}

 

def obtener_vram_actual() -> float:

    """Obtiene el consumo de VRAM actual de la primera GPU Nvidia en Gigabytes (GB)."""

    if not HAS_GPU:

        return 0.0

    try:

        handle = pynvml.nvmlDeviceGetHandleByIndex(0)

        info = pynvml.nvmlDeviceGetMemoryInfo(handle)

        return info.used / (1024 ** 3)

    except Exception:

        return 0.0

 

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]

        return socket.gethostbyname(dominio)

    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]

    dominio = dominio.split(':')[0]

    return re.sub(r'[^\w\.-]', '_', dominio)

 

def consultar_al_modelo(prompt: str) -> str:

    """Envía un prompt a gemma4:e2b y acumula métricas de rendimiento."""

    try:

        response = ollama.generate(

            model=MODEL_NAME,

            prompt=prompt,

            options={

                "temperature": 0.1,

                "top_p": 0.9

            }

        )

       

        METRICAS_LLM["total_tokens_eval"] += response.get("prompt_eval_count", 0)

        METRICAS_LLM["total_tokens_gen"] += response.get("eval_count", 0)

       

        tiempo_segundos = response.get("total_duration", 0) / 1_000_000_000

        METRICAS_LLM["total_tiempo_ollama"] += tiempo_segundos

       

        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}")

           

            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"

 

    vram_actual = obtener_vram_actual()

    if HAS_GPU:

        print(f"    [GPU Info]: VRAM en uso actual: {vram_actual:.2f} GB")

        METRICAS_LLM["vram_muestras"].append(vram_actual)

 

    lista_resumen.append({

        "categoria": categoria_owasp,

        "endpoint": endpoint,

        "estado": vulnerable_en_categoria,

        "vram_alcanzada": vram_actual if HAS_GPU else None

    })

 

if __name__ == "__main__":

    if len(sys.argv) < 2:

        print("\n[!] Error: No especificaste el sitio web objetivo.")

        print("Uso correcto: python3 audit.py <URL_DEL_SITIO>")

        print("Ejemplo:      python3 audit.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)

   

    user_home = os.path.expanduser("~")

    report_file = os.path.join(user_home, 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}")

   

    if not HAS_GPU:

        print("[!] Advertencia: No se detectó GPU Nvidia compatible. Monitoreo VRAM desactivado.")

   

    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"}

    ]

   

    inicio_proceso = time.time()

   

    for prueba in pruebas:

        auditar_punto_owasp(target_url, prueba["categoria"], prueba["endpoint"], resumen_final)

       

    tiempo_total_proceso = time.time() - inicio_proceso

   

    tps_generacion = 0.0

    if METRICAS_LLM["total_tiempo_ollama"] > 0:

        tps_generacion = METRICAS_LLM["total_tokens_gen"] / METRICAS_LLM["total_tiempo_ollama"]

 

    vram_promedio = 0.0

    if METRICAS_LLM["vram_muestras"]:

        vram_promedio = sum(METRICAS_LLM["vram_muestras"]) / len(METRICAS_LLM["vram_muestras"])

 

    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']}")

        if item['vram_alcanzada'] is not None:

            lineas_reporte.append(f"   - VRAM Usada: {item['vram_alcanzada']:.2f} GB")

        lineas_reporte.append("-" * 50)

       

    lineas_reporte.append("\n" + "="*50)

    lineas_reporte.append(" MÉTRICAS DE RENDIMIENTO Y PROCESAMIENTO")

    lineas_reporte.append("="*50)

    lineas_reporte.append(f" Tiempo total del proceso:       {tiempo_total_proceso:.2f} segundos")

    lineas_reporte.append(f" Tiempo neto en Ollama (LLM):   {METRICAS_LLM['total_tiempo_ollama']:.2f} segundos")

    lineas_reporte.append(f" Tokens de entrada procesados:  {METRICAS_LLM['total_tokens_eval']} tokens")

    lineas_reporte.append(f" Tokens de salida generados:    {METRICAS_LLM['total_tokens_gen']} tokens")

    lineas_reporte.append(f" Velocidad de respuesta (LLM):  {tps_generacion:.2f} tokens/seg")

    if HAS_GPU:

        lineas_reporte.append(f" Consumo de VRAM Promedio:      {vram_promedio:.2f} GB")

    lineas_reporte.append("="*50)

   

    texto_final = "\n".join(lineas_reporte)

    print(texto_final)

   

    try:

        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")

    except Exception as error_guardado:

        print(f"\n[!] Error inesperado al escribir el reporte en disco: {error_guardado}")

   

    if HAS_GPU:

        try:

            pynvml.nvmlShutdown()

        except Exception:

            pass


#para ejecutar
python3 auditor.py https://tusitio



No comments:

Post a Comment