1+ # -*- coding: binary -*-
2+
3+ #
4+ # A Malware simulation module with time bomb functionality
5+ #
6+ class Msf ::Malware < Msf ::Module
7+
8+ class Complete < RuntimeError
9+ end
10+
11+ class Failed < RuntimeError
12+ end
13+
14+ class TimeBombExpired < RuntimeError
15+ end
16+
17+ include Msf ::PostMixin
18+
19+ # Track files and artifacts for cleanup
20+ attr_accessor :needs_cleanup
21+ attr_accessor :cleanup_artifacts
22+ attr_accessor :start_time
23+ attr_accessor :duration_seconds
24+
25+ def initialize ( info = { } )
26+ super
27+
28+ # Initialize cleanup tracking
29+ @cleanup_artifacts = [ ]
30+ @needs_cleanup = false
31+ @start_time = nil
32+ @duration_seconds = nil
33+
34+ # Register common malware simulation options
35+ register_options ( [
36+ OptInt . new ( 'DURATION' , [ true , 'Duration in seconds before auto-cleanup (time bomb)' , 300 ] ) ,
37+ OptBool . new ( 'AUTO_CLEANUP' , [ true , 'Automatically cleanup artifacts when time expires' , true ] ) ,
38+ OptBool . new ( 'SIMULATE_ONLY' , [ true , 'Only simulate malware behavior without actual persistence' , true ] ) ,
39+ OptString . new ( 'CLEANUP_SIGNAL' , [ false , 'Custom signal file to trigger immediate cleanup' , '' ] ) ,
40+ ] )
41+ end
42+
43+ def setup
44+ m = replicant
45+
46+ if m . actions . length > 0 && !m . action
47+ raise Msf ::MissingActionError , "Please use: #{ m . actions . collect { |e | e . name } * ", " } "
48+ end
49+
50+ # Initialize time bomb
51+ @start_time = Time . now
52+ @duration_seconds = datastore [ 'DURATION' ] . to_i
53+ @needs_cleanup = datastore [ 'AUTO_CLEANUP' ]
54+
55+ print_status ( "Malware simulation started at #{ @start_time } " )
56+ print_status ( "Time bomb set for #{ @duration_seconds } seconds" )
57+ print_warning ( "Auto-cleanup #{ @needs_cleanup ? 'ENABLED' : 'DISABLED' } " )
58+
59+ # Msf::Module(Msf::PostMixin)#setup
60+ super
61+ end
62+
63+ def type
64+ Msf ::MODULE_MALWARE
65+ end
66+
67+ def self . type
68+ Msf ::MODULE_MALWARE
69+ end
70+
71+ #
72+ # Create an anonymous module not tied to a file. Only useful for IRB.
73+ #
74+ def self . create ( session )
75+ mod = new
76+ mod . instance_variable_set ( :@session , session )
77+ # Have to override inspect because for whatever reason, +type+ is coming
78+ # from the wrong scope and i can't figure out how to fix it.
79+ mod . instance_eval do
80+ def inspect
81+ "#<Msf::Malware anonymous>"
82+ end
83+ end
84+ mod . class . refname = "anonymous"
85+
86+ mod
87+ end
88+
89+ # This method returns the ID of the Mdm::Session that the malware module
90+ # is currently running against.
91+ #
92+ # @return [NilClass] if there is no database record for the session
93+ # @return [Integer] if there is a database record to get the id for
94+ def session_db_id
95+ if session . db_record
96+ session . db_record . id
97+ else
98+ nil
99+ end
100+ end
101+
102+ # Override Msf::Module#fail_with for Msf::Simple::Malware::job_run_proc
103+ def fail_with ( reason , msg = nil )
104+ cleanup_artifacts if @needs_cleanup
105+ raise Msf ::Malware ::Failed , "#{ reason . to_s } : #{ msg } "
106+ end
107+
108+ #
109+ # Time bomb functionality
110+ #
111+
112+ # Check if the time bomb has expired
113+ def time_bomb_expired?
114+ return false unless @start_time && @duration_seconds
115+ ( Time . now - @start_time ) >= @duration_seconds
116+ end
117+
118+ # Get remaining time in seconds
119+ def time_remaining
120+ return 0 unless @start_time && @duration_seconds
121+ remaining = @duration_seconds - ( Time . now - @start_time )
122+ [ remaining , 0 ] . max
123+ end
124+
125+ # Check for cleanup signal file
126+ def cleanup_signal_present?
127+ signal_file = datastore [ 'CLEANUP_SIGNAL' ]
128+ return false if signal_file . blank?
129+
130+ begin
131+ if session . type == 'meterpreter'
132+ return session . fs . file . stat ( signal_file ) rescue false
133+ elsif session . type == 'shell'
134+ result = session . shell_command_token ( "test -f #{ signal_file } && echo exists" )
135+ return result . include? ( 'exists' )
136+ end
137+ rescue
138+ return false
139+ end
140+ false
141+ end
142+
143+ # Check if module should terminate (time bomb or signal)
144+ def should_terminate?
145+ time_bomb_expired? || cleanup_signal_present?
146+ end
147+
148+ # Add artifact for cleanup tracking
149+ def register_artifact ( path , type = :file )
150+ @cleanup_artifacts << { path : path , type : type , created_at : Time . now }
151+ print_good ( "Registered artifact for cleanup: #{ path } " )
152+ end
153+
154+ # Cleanup all registered artifacts
155+ def cleanup_artifacts
156+ return unless @cleanup_artifacts && @cleanup_artifacts . any?
157+
158+ print_status ( "Time bomb expired! Cleaning up #{ @cleanup_artifacts . length } artifacts..." )
159+
160+ @cleanup_artifacts . each do |artifact |
161+ begin
162+ case artifact [ :type ]
163+ when :file
164+ cleanup_file ( artifact [ :path ] )
165+ when :directory
166+ cleanup_directory ( artifact [ :path ] )
167+ when :registry
168+ cleanup_registry ( artifact [ :path ] )
169+ when :service
170+ cleanup_service ( artifact [ :path ] )
171+ when :process
172+ cleanup_process ( artifact [ :path ] )
173+ else
174+ print_warning ( "Unknown artifact type: #{ artifact [ :type ] } " )
175+ end
176+ rescue => e
177+ print_error ( "Failed to cleanup #{ artifact [ :path ] } : #{ e . message } " )
178+ end
179+ end
180+
181+ @cleanup_artifacts . clear
182+ print_good ( "Malware simulation cleanup completed" )
183+ end
184+
185+ # Cleanup a file
186+ def cleanup_file ( path )
187+ if session . type == 'meterpreter'
188+ session . fs . file . rm ( path )
189+ elsif session . type == 'shell'
190+ if session . platform == 'windows'
191+ session . shell_command_token ( "del /f /q \" #{ path } \" " )
192+ else
193+ session . shell_command_token ( "rm -f \" #{ path } \" " )
194+ end
195+ end
196+ print_status ( "Removed file: #{ path } " )
197+ end
198+
199+ # Cleanup a directory
200+ def cleanup_directory ( path )
201+ if session . type == 'meterpreter'
202+ session . fs . dir . rmdir ( path )
203+ elsif session . type == 'shell'
204+ if session . platform == 'windows'
205+ session . shell_command_token ( "rmdir /s /q \" #{ path } \" " )
206+ else
207+ session . shell_command_token ( "rm -rf \" #{ path } \" " )
208+ end
209+ end
210+ print_status ( "Removed directory: #{ path } " )
211+ end
212+
213+ # Cleanup registry entry (Windows only)
214+ def cleanup_registry ( path )
215+ return unless session . platform == 'windows'
216+
217+ if session . type == 'meterpreter'
218+ session . sys . registry . delete_key ( path )
219+ elsif session . type == 'shell'
220+ session . shell_command_token ( "reg delete \" #{ path } \" /f" )
221+ end
222+ print_status ( "Removed registry key: #{ path } " )
223+ end
224+
225+ # Cleanup service (placeholder)
226+ def cleanup_service ( name )
227+ print_status ( "Stopping and removing service: #{ name } " )
228+ # Implementation depends on platform and service type
229+ end
230+
231+ # Cleanup process (placeholder)
232+ def cleanup_process ( pid_or_name )
233+ print_status ( "Terminating process: #{ pid_or_name } " )
234+ # Implementation depends on platform
235+ end
236+
237+ #
238+ # Safe simulation helpers
239+ #
240+
241+ # Simulate file creation without actual persistence
242+ def simulate_file_drop ( path , content = nil )
243+ if datastore [ 'SIMULATE_ONLY' ]
244+ print_status ( "SIMULATION: Would create file at #{ path } " )
245+ return true
246+ end
247+
248+ # Actually create the file but register for cleanup
249+ content ||= generate_fake_malware_content
250+
251+ if session . type == 'meterpreter'
252+ session . fs . file . upload_file ( path , content )
253+ elsif session . type == 'shell'
254+ encoded_content = Rex ::Text . encode_base64 ( content )
255+ if session . platform == 'windows'
256+ session . shell_command_token ( "echo #{ encoded_content } | certutil -decode - \" #{ path } \" " )
257+ else
258+ session . shell_command_token ( "echo '#{ encoded_content } ' | base64 -d > \" #{ path } \" " )
259+ end
260+ end
261+
262+ register_artifact ( path , :file )
263+ print_good ( "Created malware file: #{ path } " )
264+ true
265+ end
266+
267+ # Simulate registry persistence (Windows)
268+ def simulate_registry_persistence ( key , value , data )
269+ if datastore [ 'SIMULATE_ONLY' ]
270+ print_status ( "SIMULATION: Would create registry entry #{ key } \\ #{ value } " )
271+ return true
272+ end
273+
274+ return false unless session . platform == 'windows'
275+
276+ if session . type == 'meterpreter'
277+ session . sys . registry . set_value ( key , value , data )
278+ elsif session . type == 'shell'
279+ session . shell_command_token ( "reg add \" #{ key } \" /v \" #{ value } \" /d \" #{ data } \" /f" )
280+ end
281+
282+ register_artifact ( "#{ key } \\ #{ value } " , :registry )
283+ print_good ( "Created registry persistence: #{ key } \\ #{ value } " )
284+ true
285+ end
286+
287+ # Generate fake malware content for simulation
288+ def generate_fake_malware_content
289+ content = "#!/bin/bash\n " if session . platform != 'windows'
290+ content ||= "@echo off\n "
291+
292+ content += <<~EOF
293+ REM Metasploit Malware Simulation
294+ REM This is a HARMLESS simulation for penetration testing
295+ REM Created: #{ Time . now }
296+ REM Duration: #{ @duration_seconds } seconds
297+ REM Auto-cleanup: #{ @needs_cleanup }
298+
299+ echo "Malware simulation running..."
300+ echo "This is NOT real malware - it's a penetration testing simulation"
301+ echo "Time remaining: #{ time_remaining } seconds"
302+ EOF
303+
304+ content
305+ end
306+
307+ # Main execution wrapper with time bomb checking
308+ def run_with_time_bomb
309+ begin
310+ # Start the malware simulation
311+ run_malware_simulation
312+
313+ # Monitor for time bomb expiration
314+ while !should_terminate?
315+ sleep ( 5 ) # Check every 5 seconds
316+
317+ if time_remaining <= 30 && time_remaining > 25
318+ print_warning ( "Time bomb warning: #{ time_remaining } seconds remaining" )
319+ end
320+ end
321+
322+ if time_bomb_expired?
323+ print_error ( "Time bomb expired!" )
324+ raise Msf ::Malware ::TimeBombExpired , "Malware simulation time limit reached"
325+ elsif cleanup_signal_present?
326+ print_status ( "Cleanup signal detected" )
327+ end
328+
329+ rescue Msf ::Malware ::TimeBombExpired => e
330+ print_error ( "Time bomb detonated: #{ e . message } " )
331+ rescue => e
332+ print_error ( "Malware simulation error: #{ e . message } " )
333+ ensure
334+ cleanup_artifacts if @needs_cleanup
335+ end
336+ end
337+
338+ # Override this method in specific malware modules
339+ def run_malware_simulation
340+ print_status ( "Base malware simulation - override this method in specific modules" )
341+
342+ # Example simulation behavior
343+ simulate_file_drop ( "/tmp/malware_sim.txt" ) if session . platform != 'windows'
344+ simulate_file_drop ( "C:\\ temp\\ malware_sim.txt" ) if session . platform == 'windows'
345+
346+ # Simulate some activity
347+ ( 1 ..10 ) . each do |i |
348+ break if should_terminate?
349+ print_status ( "Malware simulation activity #{ i } /10" )
350+ sleep ( 2 )
351+ end
352+ end
353+
354+ # Main run method - calls the time bomb wrapper
355+ def run
356+ print_status ( "Starting malware simulation with time bomb functionality" )
357+ run_with_time_bomb
358+ end
359+
360+ end
0 commit comments