def main(options): if options.replay_file is not None: cap_reader = CaptureReader(options.replay_file) for (ts, data) in cap_reader: print "Time: ", ts, "s" print MemorySensorPacket(data) return if options.sensor_type == G.MACHINE_TYPES.PHYSICAL: client = MemorySensorPhysical(options.target, cache_timeout=0, use_threading=False) else: client = MemorySensorVirtual(options.target) READ_SIZE = int(options.read_size) start_addr = options.startaddr # Create our output file try: os.makedirs(os.path.dirname(options.output)) except: pass try: mcap_writer = None if options.loop_forever == True: logger.debug("Creating capture file.") options.output += ".mcap" mcap_writer = CaptureWriter(options.output) mcap_writer.start() else: logger.debug("Creating dump file.") options.output += ".mfd" output_file = open(options.output, "w+") except: print "ERROR: Could not open output file." sys.exit(0) # Read memory count = 0 start = time.time() sensor_packet = MemorySensorPacket() while True: try: # Get memory from remote system # Read memory data = client.read(start_addr, READ_SIZE) # Write to file? if not options.loop_forever: output_file.write(data) else: sensor_packet.address = start_addr sensor_packet.data = data sensor_packet.length = READ_SIZE mcap_writer.put(sensor_packet) # Just read once? if not options.loop_forever: break else: print "Completed read #%d" % count count += 1 except: # Just finish up break end = time.time() # Do we have an mcap file to close? if mcap_writer is not None: mcap_writer.stop() else: # Close output file output_file.close() print "Memory dump (%d bytes) written to %s. Took %s seconds." % ( len(data), options.output, end - start)
def analysis_start(self): """ Commands to execute when starting analysis. Once this returns the analysis will wait for commands from the user. NOTE: Any threads will continue execute until a stop command is received """ # Analysis is done after this function returns self.CONTINUE_EXECUTION = False # Extract some important variables volatility_profile = self.lophi_command.volatility_profile lophi_command = self.lophi_command machine = self.machine sample_doc_id = lophi_command.sample_doc_id db_analysis_id = lophi_command.db_analysis_id # Initialize our database DB_samples = DatastoreSamples(lophi_command.services_host) DB_analysis = DatastoreAnalysis(lophi_command.services_host) # Copy the sample to the ftp server temporarily so that the SUA can # download it # store the temp directory name local_path = DB_samples.copy_sample_to_ftp(sample_doc_id) remote_path = os.path.relpath(local_path, G.FTP_ROOT) lophi_command.ftp_info['dir'] = remote_path # Create a tmp directory tmp_dir = G.dir_create_tmp() # Keep retrying in case any step fails while True: # Make sure that our machine is in the state that we expect. # Reversion can fail, make sure we actually revert the disk! timestamps = [] print "* %s: Timestamp: %f"%(self.machine.config.name,time.time()) print "* %s: Resetting machine..."%self.machine.config.name reset_start = time.time() if not machine.machine_reset(): continue reset_stop = time.time() timestamps.append((reset_start, reset_stop)) # Start our machine up # print "* %s: Timestamp: %f"%(self.machine.config.name,time.time()) print "* %s: Powering on machine..."%self.machine.config.name boot_start = time.time() machine.power_on() if machine.type == G.MACHINE_TYPES.PHYSICAL: print "* %s: Ensuring that the disk sensor is up. (Bugfix)"%( self.machine.config.name) while True: time.sleep(5) if machine.disk.is_up(): break machine.power_off() time.sleep(5) machine.power_on() # Wait for the machine to appear on the network print "* %s: Timestamp: %f"%(self.machine.config.name, time.time()) print "* %s: Waiting for OS to boot..."%self.machine.config.name bad_disk_image = False for os_attempt in xrange(self.OS_BOOT_ATTEMPTS+1): if os_attempt == self.OS_BOOT_ATTEMPTS: bad_disk_image = True break start = time.time() os_timed_out = False while not self.machine.network_get_status(): time.sleep(1) if time.time() - start > self.OS_TIMEOUT: os_timed_out = True break # Did we timeout? if os_timed_out: logger.error("%s: OS boot timeout! (%d/%d)" % ( self.machine.config.name, os_attempt+1, self.OS_BOOT_ATTEMPTS)) self.machine.power_reset() continue else: break # Do we have a bad image on the disk? if bad_disk_image: logger.error("%s: Bad disk image! (Starting over)" % self.machine.config.name) continue boot_stop = time.time() timestamps.append((boot_start,boot_stop)) # Wait a bit before doing stuff (Allow the OS to finish booting print "* %s: Timestamp: %f"%(self.machine.config.name, time.time()) print "* %s: Waiting for the OS to stabilize" % \ self.machine.config.name osstable_start = time.time() time.sleep(self.OS_BOOT_WAIT) osstable_stop = time.time() timestamps.append((osstable_start,osstable_stop)) # Start our disk capturing # print "* %s: Timestamp: %f"%(self.machine.config.name,time.time()) print "* %s: Starting disk capture..."%self.machine.config.name disk_pcap_file = os.path.join(tmp_dir,"sut_disk_io.dcap") disk_queue = multiprocessing.Queue() dcap_writer = CaptureWriter(disk_pcap_file, disk_queue) disk_tap = DiskCaptureEngine(machine, disk_queue) # Start disk capture disk_tap.start() dcap_writer.start() # Send keypresses to download binary print "* %s: Timestamp: %f"%(self.machine.config.name,time.time()) print "* %s: Sending keypresses..."%self.machine.config.name # Get our keypress generator kpg = machine.keypress_get_generator() # Check ftp info, and send commands to execute malware keypress_start = time.time() if lophi_command.ftp_info['ip'] is not None and \ lophi_command.ftp_info['dir'] is not None: print "* %s: Executing ftp commands..."%self.machine.config.name ftp_script = kpg.get_ftp_script(volatility_profile, lophi_command.ftp_info, hit_enter=False) machine.keypress_send(ftp_script) else: print "* %s:* No ftp info given."%self.machine.config.name keypress_stop = time.time() timestamps.append((keypress_start,keypress_stop)) # At this the point machine has the binary on it, and is one # ENTER key away from executing it. # Dump our memory print "* %s: Timestamp: %f"%(self.machine.config.name,time.time()) print "* %s: Dumping memory (Clean)..."%self.machine.config.name memory_file_clean = os.path.join(tmp_dir,"sut_memory_clean.mfd") cleandump_start = time.time() if not machine.memory_dump(memory_file_clean): # Stop everything, and start over. dcap_writer.stop() disk_tap.stop() logger.error("%s: Memory Dump Failed! (Starting over)"% self.machine.config.name) continue cleandump_stop = time.time() timestamps.append((cleandump_start, cleandump_stop)) # Compress clean file memory_file_clean_gz = os.path.join(tmp_dir, "sut_memory_clean.tar.gz") memory_file_clean_tmp = memory_file_clean+".tmp" shutil.copy(memory_file_clean, memory_file_clean_tmp) memory_clean_compress = multiprocessing.Process( target=self.compress_file, args=(memory_file_clean, memory_file_clean_gz)) memory_clean_compress.start() timestamps.append((0, 0)) # Place holder for mem compression # Start our network capturing # Setup a capture thread and thread to write the pcap print "* %s: Timestamp: %f"%(self.machine.config.name,time.time()) print "* %s: Starting network capture"%self.machine.config.name network_pcap_file = os.path.join(tmp_dir,"sut_network.pcap") network_queue = multiprocessing.Queue() pcap_writer = PcapWriter(network_pcap_file, network_queue) net_tap = NetworkCaptureEngine(machine, network_queue) # Start network capture pcap_writer.start() net_tap.start() print "* %s: Getting a list of current buttons" % \ self.machine.config.name start_time = time.time() # Start binary and click buttons try: # Initialize our button clicker instance on our clean mem. image vol_uri = "file://"+memory_file_clean_tmp bc = ButtonClicker(vol_uri, machine.config.volatility_profile, machine.memory_get_size(), machine.control) # Get our current button list cleanbuttons_start = time.time() bc.update_buttons() cleanbuttons_stop = time.time() timestamps.append((cleanbuttons_start, cleanbuttons_stop)) # # Start our binary! # print "* %s: Timestamp: %f"%(self.machine.config.name, time.time()) print "* %s: Running binary!"%self.machine.config.name machine.keypress_send(kpg.text_to_script("SPECIAL:RETURN")) # Start wiggling our mouse to emulate a human print "* %s: Wiggling mouse."%self.machine.config.name self.machine.control.mouse_wiggle(True) start_time = time.time() # Wait a bit for it to open executewait_start = time.time() time.sleep(60) executewait_stop = time.time() timestamps.append((executewait_start, executewait_stop)) # Take another memory dump print "* %s: Timestamp: %f"%(self.machine.config.name, time.time()) print "* %s: Dumping memory (Interim)..." % \ self.machine.config.name interimdump_start = time.time() if not machine.memory_dump(memory_file_clean_tmp): raise Exception("Bad memory read.") interimdump_stop = time.time() timestamps.append((interimdump_start,interimdump_stop)) # Let's take a screenshot screenshot1_start = time.time() try: print "* %s: Timestamp: %f"%(self.machine.config.name, time.time()) print "* %s: Taking a screenshot."%self.machine.config.name screenshot_file = os.path.join(tmp_dir,"sut_screenshot") screenshot_file = self.machine.screenshot( screenshot_file, vol_uri=vol_uri) DB_analysis.append_analysis_file(db_analysis_id, screenshot_file, "screenshot") except: import traceback traceback.print_exc() logger.error("Could not take a screenshot.") pass screenshot1_stop = time.time() timestamps.append((screenshot1_start, screenshot1_stop)) # Click any new buttons that appeared print "* %s: Timestamp: %f"%(self.machine.config.name, time.time()) print "* %s: Clicking buttons..."%self.machine.config.name dirtybuttons_start = time.time() clicked = bc.click_buttons(new_only=True) for c in clicked: print "* %s: Clicked: %s:%s"%(self.machine.config.name, c['process'],c['name']) dirtybuttons_stop = time.time() timestamps.append((dirtybuttons_start, dirtybuttons_stop)) # Clean up the file on disk os.remove(memory_file_clean_tmp) # Save which buttons that we clicked DB_analysis.update_analysis(db_analysis_id, "buttons_clicked", clicked) except: logger.error("%s: Failed to start binary and click buttons. " "(Starting over)"% self.machine.config.name) import traceback traceback.print_exc() self.machine.control.mouse_wiggle(False) dcap_writer.stop() disk_tap.stop() pcap_writer.stop() net_tap.stop() continue # Run binary for as long as we see fit sleep_time = self.MALWARE_EXECUTION_TIME-(time.time()-start_time) print "* %s: Timestamp: %f"%(self.machine.config.name,time.time()) executeend_start = time.time() if sleep_time > 0: print "* %s: Sleeping for %d seconds." % ( self.machine.config.name, sleep_time) time.sleep(sleep_time) executeend_stop = time.time() timestamps.append((executeend_start,executeend_stop)) # Dump our memory again print "* %s: Timestamp: %f"%(self.machine.config.name,time.time()) print "* %s: Dumping memory..."%self.machine.config.name memory_file_dirty = os.path.join(tmp_dir,"sut_memory_dirty.mfd") dirtydump_start = time.time() if not machine.memory_dump(memory_file_dirty): # Stop everything, and start over. self.machine.control.mouse_wiggle(False) dcap_writer.stop() disk_tap.stop() pcap_writer.stop() net_tap.stop() logger.error("%s: Memory Dump Failed! (Starting over)"% self.machine.config.name) continue dirtydump_stop = time.time() timestamps.append((dirtydump_start, dirtydump_stop)) # Let's take a screenshot screenshot2_start = time.time() try: print "* %s: Timestamp: %f"%(self.machine.config.name, time.time()) print "* %s: Taking a screenshot."%self.machine.config.name screenshot_file_final = os.path.join(tmp_dir, "sut_screenshot_final") vol_uri = "file://"+memory_file_dirty screenshot_file_final = self.machine.screenshot( screenshot_file_final, vol_uri=vol_uri) DB_analysis.append_analysis_file(db_analysis_id, screenshot_file_final, "screenshot_final") except: logger.error("Could not take a screenshot.") pass screenshot2_stop = time.time() timestamps.append((screenshot2_start, screenshot2_stop)) # Join our clean compression memory_clean_compress.join() memory_clean_compress.terminate() # Compress dirty file dirtycompress_start = time.time() memory_file_dirty_gz = os.path.join(tmp_dir, "sut_memory_dirty.tar.gz") self.compress_file(memory_file_dirty, memory_file_dirty_gz) dirtycompress_stop = time.time() timestamps.append((dirtycompress_start, dirtycompress_stop)) # Power down the machine (Will also flush disk caches) print "* %s: Timestamp: %f"%(self.machine.config.name, time.time()) print "* Shutting down machine." shutdown_start = time.time() self.machine.power_shutdown() # Wait for machine to power off start = time.time() offs= 0 while True: # power status status = self.machine.power_status() if status != G.SENSOR_CONTROL.POWER_STATUS.ON: offs += 1 else: offs = 0 # Make sure the machien is really off if offs > 3: # machine is powered off print "* Shutdown successful." break if time.time()-start > 60: print "* Shutdown failed." break shutdown_stop = time.time() timestamps.append((shutdown_start, shutdown_stop)) # Stop wiggeling our mouse self.machine.control.mouse_wiggle(False) # Stop Disk Capture dcap_writer.stop() disk_tap.stop() # Stop network capture pcap_writer.stop() net_tap.stop() storeresults_start = time.time() # Save all of our generated fields to the database print "* %s: Timestamp: %f"%(self.machine.config.name,time.time()) print "* %s: Storing results in database..." % \ self.machine.config.name DB_analysis.append_analysis_file(db_analysis_id, memory_file_clean_gz, "memory_dump_clean") DB_analysis.append_analysis_file(db_analysis_id, memory_file_dirty_gz, "memory_dump_dirty") # Save pcap and dcap files DB_analysis.append_analysis_file(db_analysis_id, network_pcap_file, "network_capture") DB_analysis.append_analysis_file(db_analysis_id, disk_pcap_file, "disk_capture") storeresults_stop = time.time() timestamps.append((storeresults_start, storeresults_stop)) # Clean up files on disk G.dir_remove(local_path) G.dir_remove(tmp_dir) print "* %s: Timestamp: %f"%(self.machine.config.name, time.time()) print "* %s: Done!"%self.machine.config.name print "** %s: Times "%self.machine.config.name, timestamps # Break out of our "try forever" loop break
def main(options): """ This script will connect to the LO-PHI Disk Sensor and log all of the activity to both a dcap file with RAW data capture """ # Should we automatically set a output dir? OUTPUT_DIR = options.output_dir if OUTPUT_DIR is None: OUTPUT_DIR = "lophi_data_" + datetime.datetime.now().strftime("%m%d") # Make sure we can create the output directory if not os.path.exists(OUTPUT_DIR): try: os.makedirs(OUTPUT_DIR) except: logger.error("Could not create output directory. (%s)" % OUTPUT_DIR) return # Auto-generate our dcap filename log_dcap_filename = os.path.join( OUTPUT_DIR, "lophi_disk_" + datetime.datetime.now().strftime("%m-%d-%H:%M") + ".dcap") print "* Initializing SATA sensor..." # Initialize our disk sensor if options.sensor_type == G.MACHINE_TYPES.PHYSICAL: disk_sensor = DiskSensorPhysical(G.SENSOR_DISK.DEFAULT_IP, bind_ip=default_dest_ip, name="SATA_Sensor") if not disk_sensor.is_up(): logger.error("Disk sensor appears to be down.") return else: disk_sensor = DiskSensorVirtual(options.target) print "* Logging data to: %s" % log_dcap_filename print "* Setting up DCAP logger..." # Setup our dcap logger # We use a queue so that we don't hold up the socket. log_dcap_queue = multiprocessing.Queue() log_dcap_writer = CaptureWriter(log_dcap_filename, log_dcap_queue) log_dcap_writer.start() print "* Connecting to our sensor..." # Get data forever and report it back disk_sensor._connect() if options.sensor_type == G.MACHINE_TYPES.PHYSICAL: print "* Enabling SATA extraction..." disk_sensor.sata_enable_all() print "* Reading SATA Frame packets..." else: print "* Reading Disk Sensor Packets..." UPDATE_INTERVAL = 5 # Seconds last_print_time = 0 while 1: try: # Get our packet # Returns a SATAFrame for physical and DiskSensorPacket for virtual. packet = disk_sensor.get_disk_packet() # Log to if log_dcap_queue is not None: log_dcap_queue.put(packet) # Should we print something to screen? now = time.time() if now - last_print_time > UPDATE_INTERVAL: size = sizeof_fmt(os.path.getsize(log_dcap_filename)) print "* Captured %s." % size last_print_time = now except: logger.error("Problem getting disk packet.") G.print_traceback() break if log_dcap_queue is not None: log_dcap_writer.stop() if options.sensor_type == G.MACHINE_TYPES.PHYSICAL: disk_sensor.sata_disable() return
def main(options): """ This script will connect to the LO-PHI Disk Sensor and log all of the activity to both a dcap file with RAW data capture """ # Should we automatically set a output dir? OUTPUT_DIR = options.output_dir if OUTPUT_DIR is None: OUTPUT_DIR = "lophi_data_"+datetime.datetime.now().strftime("%m%d") # Make sure we can create the output directory if not os.path.exists(OUTPUT_DIR): try: os.makedirs(OUTPUT_DIR) except: logger.error("Could not create output directory. (%s)"%OUTPUT_DIR) return # Auto-generate our dcap filename log_dcap_filename = os.path.join(OUTPUT_DIR, "lophi_disk_"+datetime.datetime.now().strftime("%m-%d-%H:%M")+".dcap") print "* Initializing SATA sensor..." # Initialize our disk sensor if options.sensor_type == G.MACHINE_TYPES.PHYSICAL: disk_sensor = DiskSensorPhysical(G.SENSOR_DISK.DEFAULT_IP, bind_ip=default_dest_ip, name="SATA_Sensor") if not disk_sensor.is_up(): logger.error("Disk sensor appears to be down.") return else: disk_sensor = DiskSensorVirtual(options.target) print "* Logging data to: %s" % log_dcap_filename print "* Setting up DCAP logger..." # Setup our dcap logger # We use a queue so that we don't hold up the socket. log_dcap_queue = multiprocessing.Queue() log_dcap_writer = CaptureWriter(log_dcap_filename, log_dcap_queue) log_dcap_writer.start() print "* Connecting to our sensor..." # Get data forever and report it back disk_sensor._connect() if options.sensor_type == G.MACHINE_TYPES.PHYSICAL: print "* Enabling SATA extraction..." disk_sensor.sata_enable_all() print "* Reading SATA Frame packets..." else: print "* Reading Disk Sensor Packets..." UPDATE_INTERVAL = 5 # Seconds last_print_time = 0 while 1: try: # Get our packet # Returns a SATAFrame for physical and DiskSensorPacket for virtual. packet = disk_sensor.get_disk_packet() # Log to if log_dcap_queue is not None: log_dcap_queue.put( packet ) # Should we print something to screen? now = time.time() if now - last_print_time > UPDATE_INTERVAL: size = sizeof_fmt(os.path.getsize(log_dcap_filename)) print "* Captured %s."%size last_print_time = now except: logger.error("Problem getting disk packet.") G.print_traceback() break if log_dcap_queue is not None: log_dcap_writer.stop() if options.sensor_type == G.MACHINE_TYPES.PHYSICAL: disk_sensor.sata_disable() return
def analysis_start(self): """ Commands to execute when starting analysis. Once this returns the analysis will wait for commands from the user. NOTE: Any threads will continue execute until a stop command is received """ # Analysis is done after this function returns self.CONTINUE_EXECUTION = False # Extract some important variables volatility_profile = self.lophi_command.volatility_profile lophi_command = self.lophi_command machine = self.machine sample_doc_id = lophi_command.sample_doc_id db_analysis_id = lophi_command.db_analysis_id # Initialize our database DB_samples = DatastoreSamples(lophi_command.services_host) DB_analysis = DatastoreAnalysis(lophi_command.services_host) # Copy the sample to the ftp server temporarily so that the SUA can # download it # store the temp directory name local_path = DB_samples.copy_sample_to_ftp(sample_doc_id) remote_path = os.path.relpath(local_path, G.FTP_ROOT) lophi_command.ftp_info['dir'] = remote_path # Create a tmp directory tmp_dir = G.dir_create_tmp() # Keep retrying in case any step fails while True: # Make sure that our machine is in the state that we expect. # Reversion can fail, make sure we actually revert the disk! timestamps = [] print "* %s: Timestamp: %f" % (self.machine.config.name, time.time()) print "* %s: Resetting machine..." % self.machine.config.name reset_start = time.time() if not machine.machine_reset(): continue reset_stop = time.time() timestamps.append((reset_start, reset_stop)) # Start our machine up # print "* %s: Timestamp: %f"%(self.machine.config.name,time.time()) print "* %s: Powering on machine..." % self.machine.config.name boot_start = time.time() machine.power_on() if machine.type == G.MACHINE_TYPES.PHYSICAL: print "* %s: Ensuring that the disk sensor is up. (Bugfix)" % ( self.machine.config.name) while True: time.sleep(5) if machine.disk.is_up(): break machine.power_off() time.sleep(5) machine.power_on() # Wait for the machine to appear on the network print "* %s: Timestamp: %f" % (self.machine.config.name, time.time()) print "* %s: Waiting for OS to boot..." % self.machine.config.name bad_disk_image = False for os_attempt in xrange(self.OS_BOOT_ATTEMPTS + 1): if os_attempt == self.OS_BOOT_ATTEMPTS: bad_disk_image = True break start = time.time() os_timed_out = False while not self.machine.network_get_status(): time.sleep(1) if time.time() - start > self.OS_TIMEOUT: os_timed_out = True break # Did we timeout? if os_timed_out: logger.error("%s: OS boot timeout! (%d/%d)" % (self.machine.config.name, os_attempt + 1, self.OS_BOOT_ATTEMPTS)) self.machine.power_reset() continue else: break # Do we have a bad image on the disk? if bad_disk_image: logger.error("%s: Bad disk image! (Starting over)" % self.machine.config.name) continue boot_stop = time.time() timestamps.append((boot_start, boot_stop)) # Wait a bit before doing stuff (Allow the OS to finish booting print "* %s: Timestamp: %f" % (self.machine.config.name, time.time()) print "* %s: Waiting for the OS to stabilize" % \ self.machine.config.name osstable_start = time.time() time.sleep(self.OS_BOOT_WAIT) osstable_stop = time.time() timestamps.append((osstable_start, osstable_stop)) # Start our disk capturing # print "* %s: Timestamp: %f"%(self.machine.config.name,time.time()) print "* %s: Starting disk capture..." % self.machine.config.name disk_pcap_file = os.path.join(tmp_dir, "sut_disk_io.dcap") disk_queue = multiprocessing.Queue() dcap_writer = CaptureWriter(disk_pcap_file, disk_queue) disk_tap = DiskCaptureEngine(machine, disk_queue) # Start disk capture disk_tap.start() dcap_writer.start() # Send keypresses to download binary print "* %s: Timestamp: %f" % (self.machine.config.name, time.time()) print "* %s: Sending keypresses..." % self.machine.config.name # Get our keypress generator kpg = machine.keypress_get_generator() # Check ftp info, and send commands to execute malware keypress_start = time.time() if lophi_command.ftp_info['ip'] is not None and \ lophi_command.ftp_info['dir'] is not None: print "* %s: Executing ftp commands..." % self.machine.config.name ftp_script = kpg.get_ftp_script(volatility_profile, lophi_command.ftp_info, hit_enter=False) machine.keypress_send(ftp_script) else: print "* %s:* No ftp info given." % self.machine.config.name keypress_stop = time.time() timestamps.append((keypress_start, keypress_stop)) # At this the point machine has the binary on it, and is one # ENTER key away from executing it. # Dump our memory print "* %s: Timestamp: %f" % (self.machine.config.name, time.time()) print "* %s: Dumping memory (Clean)..." % self.machine.config.name memory_file_clean = os.path.join(tmp_dir, "sut_memory_clean.mfd") cleandump_start = time.time() if not machine.memory_dump(memory_file_clean): # Stop everything, and start over. dcap_writer.stop() disk_tap.stop() logger.error("%s: Memory Dump Failed! (Starting over)" % self.machine.config.name) continue cleandump_stop = time.time() timestamps.append((cleandump_start, cleandump_stop)) # Compress clean file memory_file_clean_gz = os.path.join(tmp_dir, "sut_memory_clean.tar.gz") memory_file_clean_tmp = memory_file_clean + ".tmp" shutil.copy(memory_file_clean, memory_file_clean_tmp) memory_clean_compress = multiprocessing.Process( target=self.compress_file, args=(memory_file_clean, memory_file_clean_gz)) memory_clean_compress.start() timestamps.append((0, 0)) # Place holder for mem compression # Start our network capturing # Setup a capture thread and thread to write the pcap print "* %s: Timestamp: %f" % (self.machine.config.name, time.time()) print "* %s: Starting network capture" % self.machine.config.name network_pcap_file = os.path.join(tmp_dir, "sut_network.pcap") network_queue = multiprocessing.Queue() pcap_writer = PcapWriter(network_pcap_file, network_queue) net_tap = NetworkCaptureEngine(machine, network_queue) # Start network capture pcap_writer.start() net_tap.start() print "* %s: Getting a list of current buttons" % \ self.machine.config.name start_time = time.time() # Start binary and click buttons try: # Initialize our button clicker instance on our clean mem. image vol_uri = "file://" + memory_file_clean_tmp bc = ButtonClicker(vol_uri, machine.config.volatility_profile, machine.memory_get_size(), machine.control) # Get our current button list cleanbuttons_start = time.time() bc.update_buttons() cleanbuttons_stop = time.time() timestamps.append((cleanbuttons_start, cleanbuttons_stop)) # # Start our binary! # print "* %s: Timestamp: %f" % (self.machine.config.name, time.time()) print "* %s: Running binary!" % self.machine.config.name machine.keypress_send(kpg.text_to_script("SPECIAL:RETURN")) # Start wiggling our mouse to emulate a human print "* %s: Wiggling mouse." % self.machine.config.name self.machine.control.mouse_wiggle(True) start_time = time.time() # Wait a bit for it to open executewait_start = time.time() time.sleep(60) executewait_stop = time.time() timestamps.append((executewait_start, executewait_stop)) # Take another memory dump print "* %s: Timestamp: %f" % (self.machine.config.name, time.time()) print "* %s: Dumping memory (Interim)..." % \ self.machine.config.name interimdump_start = time.time() if not machine.memory_dump(memory_file_clean_tmp): raise Exception("Bad memory read.") interimdump_stop = time.time() timestamps.append((interimdump_start, interimdump_stop)) # Let's take a screenshot screenshot1_start = time.time() try: print "* %s: Timestamp: %f" % (self.machine.config.name, time.time()) print "* %s: Taking a screenshot." % self.machine.config.name screenshot_file = os.path.join(tmp_dir, "sut_screenshot") screenshot_file = self.machine.screenshot(screenshot_file, vol_uri=vol_uri) DB_analysis.append_analysis_file(db_analysis_id, screenshot_file, "screenshot") except: import traceback traceback.print_exc() logger.error("Could not take a screenshot.") pass screenshot1_stop = time.time() timestamps.append((screenshot1_start, screenshot1_stop)) # Click any new buttons that appeared print "* %s: Timestamp: %f" % (self.machine.config.name, time.time()) print "* %s: Clicking buttons..." % self.machine.config.name dirtybuttons_start = time.time() clicked = bc.click_buttons(new_only=True) for c in clicked: print "* %s: Clicked: %s:%s" % (self.machine.config.name, c['process'], c['name']) dirtybuttons_stop = time.time() timestamps.append((dirtybuttons_start, dirtybuttons_stop)) # Clean up the file on disk os.remove(memory_file_clean_tmp) # Save which buttons that we clicked DB_analysis.update_analysis(db_analysis_id, "buttons_clicked", clicked) except: logger.error("%s: Failed to start binary and click buttons. " "(Starting over)" % self.machine.config.name) import traceback traceback.print_exc() self.machine.control.mouse_wiggle(False) dcap_writer.stop() disk_tap.stop() pcap_writer.stop() net_tap.stop() continue # Run binary for as long as we see fit sleep_time = self.MALWARE_EXECUTION_TIME - (time.time() - start_time) print "* %s: Timestamp: %f" % (self.machine.config.name, time.time()) executeend_start = time.time() if sleep_time > 0: print "* %s: Sleeping for %d seconds." % ( self.machine.config.name, sleep_time) time.sleep(sleep_time) executeend_stop = time.time() timestamps.append((executeend_start, executeend_stop)) # Dump our memory again print "* %s: Timestamp: %f" % (self.machine.config.name, time.time()) print "* %s: Dumping memory..." % self.machine.config.name memory_file_dirty = os.path.join(tmp_dir, "sut_memory_dirty.mfd") dirtydump_start = time.time() if not machine.memory_dump(memory_file_dirty): # Stop everything, and start over. self.machine.control.mouse_wiggle(False) dcap_writer.stop() disk_tap.stop() pcap_writer.stop() net_tap.stop() logger.error("%s: Memory Dump Failed! (Starting over)" % self.machine.config.name) continue dirtydump_stop = time.time() timestamps.append((dirtydump_start, dirtydump_stop)) # Let's take a screenshot screenshot2_start = time.time() try: print "* %s: Timestamp: %f" % (self.machine.config.name, time.time()) print "* %s: Taking a screenshot." % self.machine.config.name screenshot_file_final = os.path.join(tmp_dir, "sut_screenshot_final") vol_uri = "file://" + memory_file_dirty screenshot_file_final = self.machine.screenshot( screenshot_file_final, vol_uri=vol_uri) DB_analysis.append_analysis_file(db_analysis_id, screenshot_file_final, "screenshot_final") except: logger.error("Could not take a screenshot.") pass screenshot2_stop = time.time() timestamps.append((screenshot2_start, screenshot2_stop)) # Join our clean compression memory_clean_compress.join() memory_clean_compress.terminate() # Compress dirty file dirtycompress_start = time.time() memory_file_dirty_gz = os.path.join(tmp_dir, "sut_memory_dirty.tar.gz") self.compress_file(memory_file_dirty, memory_file_dirty_gz) dirtycompress_stop = time.time() timestamps.append((dirtycompress_start, dirtycompress_stop)) # Power down the machine (Will also flush disk caches) print "* %s: Timestamp: %f" % (self.machine.config.name, time.time()) print "* Shutting down machine." shutdown_start = time.time() self.machine.power_shutdown() # Wait for machine to power off start = time.time() offs = 0 while True: # power status status = self.machine.power_status() if status != G.SENSOR_CONTROL.POWER_STATUS.ON: offs += 1 else: offs = 0 # Make sure the machien is really off if offs > 3: # machine is powered off print "* Shutdown successful." break if time.time() - start > 60: print "* Shutdown failed." break shutdown_stop = time.time() timestamps.append((shutdown_start, shutdown_stop)) # Stop wiggeling our mouse self.machine.control.mouse_wiggle(False) # Stop Disk Capture dcap_writer.stop() disk_tap.stop() # Stop network capture pcap_writer.stop() net_tap.stop() storeresults_start = time.time() # Save all of our generated fields to the database print "* %s: Timestamp: %f" % (self.machine.config.name, time.time()) print "* %s: Storing results in database..." % \ self.machine.config.name DB_analysis.append_analysis_file(db_analysis_id, memory_file_clean_gz, "memory_dump_clean") DB_analysis.append_analysis_file(db_analysis_id, memory_file_dirty_gz, "memory_dump_dirty") # Save pcap and dcap files DB_analysis.append_analysis_file(db_analysis_id, network_pcap_file, "network_capture") DB_analysis.append_analysis_file(db_analysis_id, disk_pcap_file, "disk_capture") storeresults_stop = time.time() timestamps.append((storeresults_start, storeresults_stop)) # Clean up files on disk G.dir_remove(local_path) G.dir_remove(tmp_dir) print "* %s: Timestamp: %f" % (self.machine.config.name, time.time()) print "* %s: Done!" % self.machine.config.name print "** %s: Times " % self.machine.config.name, timestamps # Break out of our "try forever" loop break
def main(options): """ Implement your function here """ # Keep track of the type of analysis that is possible (for physical) has_memory = has_disk = True # Add a sensors to physical machines if needed if options.machine_type == G.MACHINE_TYPES.PHYSICAL: has_memory = has_disk = False if options.machine_config is None: logger.error("No machine config file given.") return # This isn't the class we use in practice, but fake it here for simplicity machines = CONF.import_from_config(options.machine_config, "machine") if options.machine not in machines: logger.error("%s is not a valid machine from the config file." % options.machine) logger.error("Valid targets are: %s" % machines.keys()) return # Get our machine object machine = machines[options.machine] # Ensure that a sensor config is defined if options.sensor_config is None: logger.error( "A sensor config file must be defined for physical analysis") return # Get the list of sensors sensors = CONF.import_from_config(options.sensor_config, "sensor") # Add sensors to our machine print "Trying to find physical sensors for %s..." % options.machine added_sensors = machine.add_sensors(sensors) # See which sensors were added for sensor in added_sensors: print "* Added %s to %s" % (sensor.id, machine.config.name) if issubclass(sensor.__class__, MemorySensor): has_memory = True if issubclass(sensor.__class__, DiskSensor): has_disk = True else: machine = VirtualMachine(options.machine, vm_type=options.machine_type, volatility_profile=options.volatility_profile) if options.analysis is not None: analysis = analysis_scripts[options.analysis] lae = LoPhiAnalysisEngine() lae.start(analysis[0], machine=machine) print "Running Analysis (%s)..." % options.analysis while True: print "* The following commands are available" print " p - Pause, r - Resume, s - Stop" command = raw_input('cmd: ') if command == "p": lae.pause() print "Analysis PAUSED." elif command == "r": lae.resume() print "Analysis RESUMED." elif command == "s": lae.stop() print "Analysis STOPPED." sys.exit(0) else: print "Unrecognized command (%s)." % command if False and has_memory: print "Starting memory analysis" # Create a queue and start our analysis output_queue = multiprocessing.Queue() mem_analysis = MemoryAnalysisEngine(machine, output_queue, plugins=['pslist']) mem_cap = CaptureWriter("memory.cap", output_queue) # mem_cap.start() mem_analysis.start() for i in range(10): print output_queue.get() # mem_cap.stop() mem_analysis.stop() if has_disk: print "Starting disk analysis" # create a queue and start analysis output_queue = multiprocessing.Queue() disk_analysis = DiskAnalysisEngine(machine, output_queue) disk_cap = CaptureWriter("disk.cap", output_queue) # disk_cap.start() disk_analysis.start() for i in range(100): print output_queue.get() # disk_cap.stop() disk_analysis.stop()
def main(options): if options.replay_file is not None: cap_reader = CaptureReader(options.replay_file) for (ts, data) in cap_reader: print "Time: ", ts, "s" print MemorySensorPacket(data) return if options.sensor_type == G.MACHINE_TYPES.PHYSICAL: client = MemorySensorPhysical(options.target, cache_timeout=0, use_threading=False) else: client = MemorySensorVirtual(options.target) READ_SIZE = int(options.read_size) start_addr = options.startaddr # Create our output file try: os.makedirs(os.path.dirname(options.output)) except: pass try: mcap_writer = None if options.loop_forever == True: logger.debug("Creating capture file.") options.output += ".mcap" mcap_writer = CaptureWriter(options.output) mcap_writer.start() else: logger.debug("Creating dump file.") options.output += ".mfd" output_file = open(options.output, "w+") except: print "ERROR: Could not open output file." sys.exit(0) # Read memory count = 0 start = time.time() sensor_packet = MemorySensorPacket() while True: try: # Get memory from remote system # Read memory data = client.read(start_addr, READ_SIZE) # Write to file? if not options.loop_forever: output_file.write(data) else: sensor_packet.address = start_addr sensor_packet.data = data sensor_packet.length = READ_SIZE mcap_writer.put(sensor_packet) # Just read once? if not options.loop_forever: break else: print "Completed read #%d"%count count += 1 except: # Just finish up break end = time.time() # Do we have an mcap file to close? if mcap_writer is not None: mcap_writer.stop() else: # Close output file output_file.close() print "Memory dump (%d bytes) written to %s. Took %s seconds." % (len(data),options.output,end-start)