Example #1
0
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)
Example #2
0
    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
Example #3
0
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
Example #4
0
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
Example #5
0
    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
Example #6
0
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()
Example #7
0
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)