Last active
July 21, 2025 22:51
-
-
Save dstnat/951f258861ea3fa534df8948db3e8c5f to your computer and use it in GitHub Desktop.
Revisions
-
dstnat revised this gist
Jul 21, 2025 . 1 changed file with 2 additions and 183 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -12,9 +12,7 @@ from langchain_core.agents import AgentAction, AgentFinish # --- Configuración SSH para Kali --- KALI_SSH_HOST = "192.168.56.181" # ¡IP de tu máquina Kali actualizada y verificada! KALI_SSH_USER = "dstnat" KALI_SSH_PASS = "semeter*410" @@ -120,183 +118,4 @@ def searchsploit_lookup(query: str) -> str: """ Busca exploits y shellcodes en la base de datos de Exploit-DB usando searchsploit. La 'query' puede ser el nombre de un software, un servicio, o una versión específica (ej. "vsftpd 2.3.4", "openssh 7.9p1", "apache 2.4"). Ejemplo de uso: searchsploit_ -
dstnat revised this gist
Jul 21, 2025 . 1 changed file with 119 additions and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -181,4 +181,122 @@ def generate_security_report(nmap_output: str = "", nuclei_output: str = "", sea "target": "", "scan_summary": "No se encontraron hallazgos significativos.", "open_ports": [], "nmap_vulnerabilities": [], "nuclei_vulnerabilities": [], "searchsploit_findings": [], "full_nmap_output": nmap_output, "full_nuclei_output": nuclei_output, "full_searchsploit_output": searchsploit_output, "report_generated_by": "Agente de Ciberseguridad" } # --- Procesar Nmap Output --- if nmap_output: lines = nmap_output.split('\n') port_service_version_pattern = re.compile(r"^(\d+)/tcp\s+(\S+)\s+([^\s]+)\s*(.*)$") script_output_pattern = re.compile(r"^\S+\-([^:]+):\s*(.*)") target_match = re.search(r"Nmap scan report for (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})", nmap_output) if target_match: report_data["target"] = target_match.group(1) for line in lines: line = line.strip() match_port_service_version = port_service_version_pattern.match(line) if match_port_service_version: port = match_port_service_version.group(1) state = match_port_service_version.group(2) service = match_port_service_version.group(3) version_info = match_port_service_version.group(4).strip() if state == "open": port_entry = {"port": port, "service": service, "state": state} if version_info: port_entry["version"] = version_info report_data["open_ports"].append(port_entry) match_script = script_output_pattern.match(line) if match_script: script_name = match_script.group(1).strip() script_output = match_script.group(2).strip() if len(script_output) > 10 and not any(kw in script_output.lower() for kw in ["no results", "not found", "nothing found", "no issues"]): report_data["nmap_vulnerabilities"].append({"script": script_name, "finding": script_output}) elif "VULNERABLE:" in script_output or "VULN:" in script_output or "vulnerable:" in script_output: report_data["nmap_vulnerabilities"].append({"script": script_name, "finding": script_output}) if report_data["open_ports"] or report_data["nmap_vulnerabilities"]: report_data["nmap_scan_summary"] = "Escaneo Nmap completado con hallazgos de puertos y/o vulnerabilidades NSE." else: report_data["nmap_scan_summary"] = "Escaneo Nmap completado, no se encontraron puertos abiertos o vulnerabilidades NSE." # --- Procesar Nuclei Output --- if nuclei_output: lines = nuclei_output.split('\n') for line in lines: line = line.strip() nuclei_match = re.match(r"^\[([^\]]+)\]\s*\[([^\]]+)\]\s*([^\s]+)\s*(.*)", line) if nuclei_match: template_id = nuclei_match.group(1) severity = nuclei_match.group(2) url = nuclei_match.group(3) info = nuclei_match.group(4).strip() report_data["nuclei_vulnerabilities"].append({ "template": template_id, "severity": severity, "url": url, "info": info }) elif line: if not any(kw in line.lower() for kw in ["no results", "found 0", "all templates loaded"]): report_data["nuclei_vulnerabilities"].append({"raw_output": line}) # --- Procesar Searchsploit Output --- if searchsploit_output: try: # Searchsploit JSON output can be tricky. Try to load as JSON first. # If searchsploit returns multiple JSON objects (e.g., --json output), it's a list. searchsploit_json_array = json.loads(searchsploit_output) if isinstance(searchsploit_json_array, list): report_data["searchsploit_findings"].extend(searchsploit_json_array) else: # If it's a single JSON object or other unexpected JSON report_data["searchsploit_findings"].append({"query": "multiple_queries_or_unknown", "results": searchsploit_output}) except json.JSONDecodeError: # If not a JSON, treat as raw text output report_data["searchsploit_findings"].append({"query": "unknown_or_single_query", "results": searchsploit_output}) # Update general scan summary if report_data["open_ports"] or report_data["nmap_vulnerabilities"] or report_data["nuclei_vulnerabilities"] or report_data["searchsploit_findings"]: report_data["scan_summary"] = "Escaneo de seguridad completado con hallazgos importantes." else: report_data["scan_summary"] = "No se encontraron hallazgos significativos en los escaneos." # Si no se encontró absolutamente nada, devolver un JSON más simple. if not report_data["open_ports"] and not report_data["nmap_vulnerabilities"] and not report_data["nuclei_vulnerabilities"] and not report_data["searchsploit_findings"]: return json.dumps({"status": "No se encontraron hallazgos significativos en los escaneos.", "target": report_data["target"] if report_data["target"] else "Desconocido", "report_generated_by": report_data["report_generated_by"]}, indent=2) return json.dumps(report_data, indent=2) # --- Configuración del Agente de LangChain --- class CustomOutputParser(AgentOutputParser): def parse(self, llm_output: str) -> Union[AgentAction, AgentFinish]: if "Final Answer:" in llm_output: return AgentFinish( return_values={"output": llm_output.split("Final Answer:")[-1].strip()}, log=llm_output, ) regex = r"Action:\s*(.*)\nAction Input:\s*(.*)" match = re.search(regex, llm_output) if not match: raise ValueError(f"Could not parse LLM output: `{llm_output}`") action = match.group(1).strip() action_input = match.group(2).strip() return AgentAction(tool=action, tool_input=action_input, log=llm_output) # Inicializar el modelo Ollama (por ejemplo, con 'llama3') # Asegúrate de tener el modelo 'llama3' descargado en tu Ollama: ollama pull llama3 -
dstnat revised this gist
Jul 21, 2025 . 1 changed file with 94 additions and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -88,4 +88,97 @@ def nmap_vulnerability_scan(target: str, ports: str, script_category_or_names: s @tool def nuclei_scan(target_url: str) -> str: """ Realiza un escaneo de vulnerabilidades web utilizando Nuclei en la URL especificada. La URL debe incluir el esquema (http:// o https://) y el puerto si no es el predeterminado (ej. http://192.168.56.180:80). Utiliza plantillas de vulnerabilidades comunes de Nuclei. Ejemplo de uso: nuclei_scan("http://192.168.56.180:80") """ try: client = paramiko.SSHClient() client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) client.connect(hostname=KALI_SSH_HOST, username=KALI_SSH_USER, password=KALI_SSH_PASS) command = f"nuclei -u {target_url} -t cves/ -t exposures/ -t http/ -t vulnerabilities/ -silent -no-color" stdin, stdout, stderr = client.exec_command(command) output = stdout.read().decode().strip() error = stderr.read().decode().strip() client.close() if error and "No results found" not in error and "No targets specified" not in error: return f"Error al ejecutar nuclei_scan remoto en {target_url}: {error}" if not output: return f"No se encontraron hallazgos de Nuclei para {target_url}." return output except Exception as e: return f"Error al intentar conectar a Kali o ejecutar nuclei_scan: {e}. Asegúrate de que Kali esté encendida, sea accesible por SSH, y las credenciales sean correctas." @tool def searchsploit_lookup(query: str) -> str: """ Busca exploits y shellcodes en la base de datos de Exploit-DB usando searchsploit. La 'query' puede ser el nombre de un software, un servicio, o una versión específica (ej. "vsftpd 2.3.4", "openssh 7.9p1", "apache 2.4"). Ejemplo de uso: searchsploit_lookup("Apache httpd 2.4.38") """ try: client = paramiko.SSHClient() client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) client.connect(hostname=KALI_SSH_HOST, username=KALI_SSH_USER, password=KALI_SSH_PASS) command = f"searchsploit {query}" stdin, stdout, stderr = client.exec_command(command) output = stdout.read().decode().strip() error = stderr.read().decode().strip() client.close() if error and "No results" not in error: return f"Error al ejecutar searchsploit_lookup remoto con query '{query}': {error}" if "No results" in output or not output: return f"No se encontraron exploits para la query '{query}' en Searchsploit." return output except Exception as e: return f"Error al intentar conectar a Kali o ejecutar searchsploit_lookup: {e}. Asegúrate de que Kali esté encendida, sea accesible por SSH, y las credenciales sean correctas." @tool def generate_security_report(nmap_output: str = "", nuclei_output: str = "", searchsploit_output: str = "") -> str: """ Analiza la salida de los escaneos de Nmap, Nuclei y Searchsploit y genera un reporte de seguridad unificado en formato JSON. Toma como entrada las cadenas de texto completas de la salida de Nmap, Nuclei y Searchsploit. Identifica puertos abiertos, servicios, hallazgos de vulnerabilidades generales, vulnerabilidades web y exploits conocidos. La salida es un objeto JSON con la estructura: { "target": "IP_del_objetivo", "scan_summary": "Resumen general del escaneo", "open_ports": [ {"port": "22", "service": "ssh", "version": "OpenSSH 7.9p1", "state": "open"}, ... ], "nmap_vulnerabilities": [ {"script": "ssh-hostkey", "finding": "2048 SHA256:abcd... (RSA)"}, ... ], "nuclei_vulnerabilities": [ {"template": "cves/2017/CVE-2017-xxxx", "severity": "critical", "url": "http://...", "info": "Apache Struts RCE"}, ... ], "searchsploit_findings": [ {"query": "vsftpd 2.3.4", "results": "vsftpd 2.3.4 - Backdoor Command Execution (Metasploit)\n..."}, ... ], "full_nmap_output": "Texto completo de la salida de Nmap (si aplica)", "full_nuclei_output": "Texto completo de la salida de Nuclei (si aplica)", "full_searchsploit_output": "Texto completo de la salida de Searchsploit (si aplica)", "report_generated_by": "Agente de Ciberseguridad" } Ejemplo de uso: generate_security_report(nmap_output="...", nuclei_output="...", searchsploit_output="...") """ report_data = { "target": "", "scan_summary": "No se encontraron hallazgos significativos.", "open_ports": [], "nmap -
dstnat revised this gist
Jul 21, 2025 . 1 changed file with 2 additions and 151 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -14,7 +14,7 @@ # --- Configuración SSH para Kali --- # Credenciales proporcionadas por el usuario, integradas directamente para simplificar el despliegue. # Para mayor seguridad en producción, estas deberían ser variables de entorno o gestionadas de forma más robusta. KALI_SSH_HOST = "192.166.56.101" # IP de tu máquina Kali (ajustar si es diferente) KALI_SSH_USER = "dstnat" KALI_SSH_PASS = "semeter*410" @@ -88,153 +88,4 @@ def nmap_vulnerability_scan(target: str, ports: str, script_category_or_names: s @tool def nuclei_scan(target_url: str) -> str: """ Realiza un escaneo de -
dstnat revised this gist
Jul 21, 2025 . 1 changed file with 1 addition and 141 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -237,144 +237,4 @@ def generate_security_report(nmap_output: str = "", nuclei_output: str = "", sea for line in lines: line = line.strip() nuclei_match = re.match(r"^\[([^\]]+)\]\s*\[([^\]]+)\]\s*([^\s]+)\s*(.*)", line) if nuclei_match: -
dstnat created this gist
Jul 21, 2025 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,380 @@ import os import re import paramiko import json from typing import Union, List, Dict from langchain_community.llms import Ollama from langchain_community.tools import tool from langchain.agents import AgentExecutor, create_react_agent from langchain_core.prompts import PromptTemplate from langchain.agents.agent import AgentOutputParser from langchain_core.agents import AgentAction, AgentFinish # --- Configuración SSH para Kali --- # Credenciales proporcionadas por el usuario, integradas directamente para simplificar el despliegue. # Para mayor seguridad en producción, estas deberían ser variables de entorno o gestionadas de forma más robusta. KALI_SSH_HOST = "192.168.56.101" # IP de tu máquina Kali (ajustar si es diferente) KALI_SSH_USER = "dstnat" KALI_SSH_PASS = "semeter*410" # --- Definir Herramientas --- @tool def nmap_recon_scan(target: str) -> str: """ Realiza un escaneo de reconocimiento exhaustivo usando nmap en el objetivo especificado. Escanea los puertos del 1 al 1000, detecta versiones de servicios (-sV), ejecuta scripts por defecto (-sC), y es muy verboso (-vvv). El objetivo puede ser una IP, un rango de IPs, o un hostname. Ejemplo de uso: nmap_recon_scan("192.168.1.1") """ try: client = paramiko.SSHClient() client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) client.connect(hostname=KALI_SSH_HOST, username=KALI_SSH_USER, password=KALI_SSH_PASS) command = f"nmap -p 1-1000 --open -sS -sC -sV -n -vvv -Pn {target}" stdin, stdout, stderr = client.exec_command(command) output = stdout.read().decode().strip() error = stderr.read().decode().strip() client.close() if error: return f"Error al ejecutar nmap_recon_scan remoto en {target}: {error}" if not output: return f"No se encontraron resultados para {target}. Asegúrate de que el objetivo esté activo y sea accesible desde Kali." return output except Exception as e: return f"Error al intentar conectar a Kali o ejecutar nmap_recon_scan: {e}. Asegúrate de que Kali esté encendida, sea accesible por SSH, y las credenciales sean correctas." @tool def nmap_vulnerability_scan(target: str, ports: str, script_category_or_names: str = "vuln") -> str: """ Realiza un escaneo de vulnerabilidades utilizando scripts de Nmap NSE en los puertos específicos de un objetivo. Los 'ports' deben ser una lista de puertos separados por comas (ej. "22,80,443"). 'script_category_or_names' puede ser una categoría de scripts Nmap (ej. "vuln", "discovery") o una lista de nombres de scripts específicos separados por comas (ej. "smb-enum-shares,smb-vuln-ms17-010"). Ejemplo de uso: - Escaneo general: nmap_vulnerability_scan("192.168.1.1", "22,80", "vuln") - Escaneo SMB específico: nmap_vulnerability_scan("192.168.1.1", "445", "smb-enum-shares,smb-vuln-ms17-010") """ try: client = paramiko.SSHClient() client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) client.connect(hostname=KALI_SSH_HOST, username=KALI_SSH_USER, password=KALI_SSH_PASS) command = f"nmap -p {ports} --script={script_category_or_names} {target}" stdin, stdout, stderr = client.exec_command(command) output = stdout.read().decode().strip() error = stderr.read().decode().strip() client.close() if error: return f"Error al ejecutar nmap_vulnerability_scan remoto en {target} en puertos {ports} con scripts {script_category_or_names}: {error}" if not output or "Host is up" not in output: return f"No se encontraron resultados de vulnerabilidades para {target}. Asegúrate de que el objetivo esté activo y sea accesible desde Kali." return output except Exception as e: return f"Error al intentar conectar a Kali o ejecutar nmap_vulnerability_scan: {e}. Asegúrate de que Kali esté encendida, sea accesible por SSH, y las credenciales sean correctas." @tool def nuclei_scan(target_url: str) -> str: """ Realiza un escaneo de vulnerabilidades web utilizando Nuclei en la URL especificada. La URL debe incluir el esquema (http:// o https://) y el puerto si no es el predeterminado (ej. http://192.168.56.180:80). Utiliza plantillas de vulnerabilidades comunes de Nuclei. Ejemplo de uso: nuclei_scan("http://192.168.56.180:80") """ try: client = paramiko.SSHClient() client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) client.connect(hostname=KALI_SSH_HOST, username=KALI_SSH_USER, password=KALI_SSH_PASS) command = f"nuclei -u {target_url} -t cves/ -t exposures/ -t http/ -t vulnerabilities/ -silent -no-color" stdin, stdout, stderr = client.exec_command(command) output = stdout.read().decode().strip() error = stderr.read().decode().strip() client.close() if error and "No results found" not in error and "No targets specified" not in error: return f"Error al ejecutar nuclei_scan remoto en {target_url}: {error}" if not output: return f"No se encontraron hallazgos de Nuclei para {target_url}." return output except Exception as e: return f"Error al intentar conectar a Kali o ejecutar nuclei_scan: {e}. Asegúrate de que Kali esté encendida, sea accesible por SSH, y las credenciales sean correctas." @tool def searchsploit_lookup(query: str) -> str: """ Busca exploits y shellcodes en la base de datos de Exploit-DB usando searchsploit. La 'query' puede ser el nombre de un software, un servicio, o una versión específica (ej. "vsftpd 2.3.4", "openssh 7.9p1", "apache 2.4"). Ejemplo de uso: searchsploit_lookup("Apache httpd 2.4.38") """ try: client = paramiko.SSHClient() client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) client.connect(hostname=KALI_SSH_HOST, username=KALI_SSH_USER, password=KALI_SSH_PASS) command = f"searchsploit {query}" stdin, stdout, stderr = client.exec_command(command) output = stdout.read().decode().strip() error = stderr.read().decode().strip() client.close() if error and "No results" not in error: return f"Error al ejecutar searchsploit_lookup remoto con query '{query}': {error}" if "No results" in output or not output: return f"No se encontraron exploits para la query '{query}' en Searchsploit." return output except Exception as e: return f"Error al intentar conectar a Kali o ejecutar searchsploit_lookup: {e}. Asegúrate de que Kali esté encendida, sea accesible por SSH, y las credenciales sean correctas." @tool def generate_security_report(nmap_output: str = "", nuclei_output: str = "", searchsploit_output: str = "") -> str: """ Analiza la salida de los escaneos de Nmap, Nuclei y Searchsploit y genera un reporte de seguridad unificado en formato JSON. Toma como entrada las cadenas de texto completas de la salida de Nmap, Nuclei y Searchsploit. Identifica puertos abiertos, servicios, hallazgos de vulnerabilidades generales, vulnerabilidades web y exploits conocidos. La salida es un objeto JSON con la estructura: { "target": "IP_del_objetivo", "scan_summary": "Resumen general del escaneo", "open_ports": [ {"port": "22", "service": "ssh", "version": "OpenSSH 7.9p1", "state": "open"}, ... ], "nmap_vulnerabilities": [ {"script": "ssh-hostkey", "finding": "2048 SHA256:abcd... (RSA)"}, ... ], "nuclei_vulnerabilities": [ {"template": "cves/2017/CVE-2017-xxxx", "severity": "critical", "url": "http://...", "info": "Apache Struts RCE"}, ... ], "searchsploit_findings": [ {"query": "vsftpd 2.3.4", "results": "vsftpd 2.3.4 - Backdoor Command Execution (Metasploit)\n..."}, ... ], "full_nmap_output": "Texto completo de la salida de Nmap (si aplica)", "full_nuclei_output": "Texto completo de la salida de Nuclei (si aplica)", "full_searchsploit_output": "Texto completo de la salida de Searchsploit (si aplica)", "report_generated_by": "Agente de Ciberseguridad" } Ejemplo de uso: generate_security_report(nmap_output="...", nuclei_output="...", searchsploit_output="...") """ report_data = { "target": "", "scan_summary": "No se encontraron hallazgos significativos.", "open_ports": [], "nmap_vulnerabilities": [], "nuclei_vulnerabilities": [], "searchsploit_findings": [], "full_nmap_output": nmap_output, "full_nuclei_output": nuclei_output, "full_searchsploit_output": searchsploit_output, "report_generated_by": "Agente de Ciberseguridad" } # --- Procesar Nmap Output --- if nmap_output: lines = nmap_output.split('\n') port_service_version_pattern = re.compile(r"^(\d+)/tcp\s+(\S+)\s+([^\s]+)\s*(.*)$") script_output_pattern = re.compile(r"^\S+\-([^:]+):\s*(.*)") target_match = re.search(r"Nmap scan report for (\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})", nmap_output) if target_match: report_data["target"] = target_match.group(1) for line in lines: line = line.strip() match_port_service_version = port_service_version_pattern.match(line) if match_port_service_version: port = match_port_service_version.group(1) state = match_port_service_version.group(2) service = match_port_service_version.group(3) version_info = match_port_service_version.group(4).strip() if state == "open": port_entry = {"port": port, "service": service, "state": state} if version_info: port_entry["version"] = version_info report_data["open_ports"].append(port_entry) match_script = script_output_pattern.match(line) if match_script: script_name = match_script.group(1).strip() script_output = match_script.group(2).strip() if len(script_output) > 10 and not any(kw in script_output.lower() for kw in ["no results", "not found", "nothing found", "no issues"]): report_data["nmap_vulnerabilities"].append({"script": script_name, "finding": script_output}) elif "VULNERABLE:" in script_output or "VULN:" in script_output or "vulnerable:" in script_output: report_data["nmap_vulnerabilities"].append({"script": script_name, "finding": script_output}) if report_data["open_ports"] or report_data["nmap_vulnerabilities"]: report_data["nmap_scan_summary"] = "Escaneo Nmap completado con hallazgos de puertos y/o vulnerabilidades NSE." else: report_data["nmap_scan_summary"] = "Escaneo Nmap completado, no se encontraron puertos abiertos o vulnerabilidades NSE." # --- Procesar Nuclei Output --- if nuclei_output: lines = nuclei_output.split('\n') for line in lines: line = line.strip() nuclei_match = re.match(r"^\[([^\]]+)\]\s*\[([^\]]+)\]\s*([^\s]+)\s*(.*)", line) if nuclei_match: template_id = nuclei_match.group(1) severity = nuclei_match.group(2) url = nuclei_match.group(3) info = nuclei_match.group(4).strip() report_data["nuclei_vulnerabilities"].append({ "template": template_id, "severity": severity, "url": url, "info": info }) elif line: if not any(kw in line.lower() for kw in ["no results", "found 0", "all templates loaded"]): report_data["nuclei_vulnerabilities"].append({"raw_output": line}) # --- Procesar Searchsploit Output --- if searchsploit_output: try: # Searchsploit JSON output can be tricky. Try to load as JSON first. # If searchsploit returns multiple JSON objects (e.g., --json output), it's a list. searchsploit_json_array = json.loads(searchsploit_output) if isinstance(searchsploit_json_array, list): report_data["searchsploit_findings"].extend(searchsploit_json_array) else: # If it's a single JSON object or other unexpected JSON report_data["searchsploit_findings"].append({"query": "multiple_queries_or_unknown", "results": searchsploit_output}) except json.JSONDecodeError: # If not a JSON, treat as raw text output report_data["searchsploit_findings"].append({"query": "unknown_or_single_query", "results": searchsploit_output}) # Update general scan summary if report_data["open_ports"] or report_data["nmap_vulnerabilities"] or report_data["nuclei_vulnerabilities"] or report_data["searchsploit_findings"]: report_data["scan_summary"] = "Escaneo de seguridad completado con hallazgos importantes." else: report_data["scan_summary"] = "No se encontraron hallazgos significativos en los escaneos." # Si no se encontró absolutamente nada, devolver un JSON más simple. if not report_data["open_ports"] and not report_data["nmap_vulnerabilities"] and not report_data["nuclei_vulnerabilities"] and not report_data["searchsploit_findings"]: return json.dumps({"status": "No se encontraron hallazgos significativos en los escaneos.", "target": report_data["target"] if report_data["target"] else "Desconocido", "report_generated_by": report_data["report_generated_by"]}, indent=2) return json.dumps(report_data, indent=2) # --- Configuración del Agente de LangChain --- class CustomOutputParser(AgentOutputParser): def parse(self, llm_output: str) -> Union[AgentAction, AgentFinish]: if "Final Answer:" in llm_output: return AgentFinish( return_values={"output": llm_output.split("Final Answer:")[-1].strip()}, log=llm_output, ) regex = r"Action:\s*(.*)\nAction Input:\s*(.*)" match = re.search(regex, llm_output) if not match: raise ValueError(f"Could not parse LLM output: `{llm_output}`") action = match.group(1).strip() action_input = match.group(2).strip() return AgentAction(tool=action, tool_input=action_input, log=llm_output) # Inicializar el modelo Ollama (por ejemplo, con 'llama3') # Asegúrate de tener el modelo 'llama3' descargado en tu Ollama: ollama pull llama3 llm = Ollama(model="llama3", temperature=0.0) # Lista de herramientas disponibles para el agente tools = [ nmap_recon_scan, nmap_vulnerability_scan, nuclei_scan, searchsploit_lookup, generate_security_report ] # Plantilla de Prompt para el agente # Aquí puedes ajustar las instrucciones para el agente. # Es crucial que las instrucciones sean claras y específicas sobre cuándo usar cada herramienta. # El prompt debe guiar al LLM a seguir el patrón ReAct (Thought, Action, Action Input, Observation, ...) prompt = PromptTemplate.from_template(""" Eres un asistente de ciberseguridad experto. Tu objetivo es ayudar a los usuarios a realizar análisis de seguridad. Debes utilizar las herramientas disponibles para recopilar información, identificar vulnerabilidades y generar un reporte. Responde en español y sigue el siguiente formato: Thought: Siempre debes pensar en qué hacer a continuación. Action: La acción a realizar, debe ser una de las herramientas [{tool_names}] Action Input: Los parámetros de entrada para la acción. Observation: El resultado de la acción. ... (Este Thought/Action/Action Input/Observation se puede repetir varias veces) Thought: He terminado mi tarea y tengo la respuesta final. Final Answer: La respuesta final a la pregunta original del usuario, incluyendo el reporte de seguridad si se solicitó. Aquí hay un ejemplo: Question: Escanea 192.168.1.1 en busca de puertos abiertos y luego busca exploits para los servicios encontrados. Thought: El usuario quiere escanear un objetivo para puertos y servicios. Usaré nmap_recon_scan para el reconocimiento inicial. Action: nmap_recon_scan Action Input: 192.168.1.1 Observation: Nmap scan report for 192.168.1.1... (Aquí iría la salida real de Nmap) Thought: He obtenido puertos y servicios. Ahora necesito buscar exploits para estos servicios. Por ejemplo, si encontré un servicio FTP vsftpd 2.3.4, buscaré exploits para eso. Action: searchsploit_lookup Action Input: vsftpd 2.3.4 Observation: (Aquí iría la salida de Searchsploit) Thought: He recolectado la información de reconocimiento y exploits. Ahora debo generar un reporte de seguridad combinando toda la información. Action: generate_security_report Action Input: nmap_output="...", searchsploit_output="..." Observation: (Aquí iría el reporte JSON) Thought: El reporte de seguridad ha sido generado exitosamente. Estoy listo para dar la respuesta final al usuario. Final Answer: Aquí tienes el reporte de seguridad completo en formato JSON: {...} Comienza! Question: {input} {agent_scratchpad} """) # Crear el agente # Necesitamos pasar tools y tool_names al prompt agent = create_react_agent(llm, tools, prompt, tools_arg=tools, tool_names_arg=", ".join([t.name for t in tools])) # Crear el ejecutor del agente agent_executor = AgentExecutor( agent=agent, tools=tools, verbose=True, # Establecer en True para ver los pensamientos y acciones del agente handle_parsing_errors=True # Maneja errores de parsing si el LLM no sigue el formato ) if __name__ == "__main__": print("¡Agente de Ciberseguridad iniciado! Escribe 'exit' para salir.") while True: user_input = input("¿En qué puedo ayudarte? ") if user_input.lower() == 'exit': break try: # Usa .invoke para ejecutar el agente con la entrada del usuario result = agent_executor.invoke({"input": user_input}) print("\nResultado Final:") print(result["output"]) except Exception as e: print(f"\n¡Se produjo un error al ejecutar el agente!: {e}") print("Por favor, intenta reformular tu pregunta o revisa la configuración.")