Ejemplo n.º 1
0
    def __init__(self):
        self.monitorManager = MonitorsManager()
        self.profileManager = ProfilesManager()
        self.adb = Adb()
        self.fastboot = Fastboot()
        self.partition = Partition()

        self.tool = Tool()
        self.session = object
        self.config_ini = config.Session()
        self.device_backup_path = ""
        self.device = Device()
Ejemplo n.º 2
0
class SessionManager(object):
    def __init__(self):
        self.monitorManager = MonitorsManager()
        self.profileManager = ProfilesManager()
        self.adb = Adb()
        self.fastboot = Fastboot()
        self.partition = Partition()

        self.tool = Tool()
        self.session = object
        self.config_ini = config.Session()
        self.device_backup_path = ""
        self.device = Device()

    def create_session_dir(self, session_id, device_serial):
        """
        Create new session directory with given session ID
        :param session_id: session id
        :return: nil
        """
        try:
            id_path = os.path.join(SESSION_DIR, session_id.__str__())

            is_session_dir_exist = os.path.isdir(id_path)

            if is_session_dir_exist:
                raise SessionDirError

            for directory in directories:
                new_session_path = os.path.join(id_path, directory)
                os.makedirs(new_session_path)

            self.config_ini.create(id_path, device_serial)

        except Exception as e:
            log.error("Unable to create session directory")
            self.create_session_dir(session_id, device_serial)

    def save_result(self, session_id, name, result, ext=""):
        """
        save processing result into session directory
        :param session_id:
        :param name:
        :param result:
        :return:
        """
        try:
            session = Session(session_id)
            file = open(os.path.join(session.report_dir, name + ext), "w")
            file.write(result)
            file.close()

            return True
        except Exception as e:
            return False

    def get_results(self, session_id):
        """
        Get all json results from session's report directory
        :param session_id:
        :return:
        """
        reports = {}  # key: file name, value: json content
        current_session = Session(session_id)
        for file in os.listdir(current_session.report_dir):
            if file.endswith(".json"):
                with open(os.path.join(current_session.report_dir, file)) as data_file:
                    reports[file.split(".")[0].replace("_", " ")] = json.load(data_file)

        return reports

    def end(self, session_id, device_backup_path, modules_config, device_serial):
        """
        End sandbox analysis
        :param session_id:
        :return:
        """
        self.session = Session(session_id)

        log_name = "end_status_%s" % session_id
        end_logger = logging.getLogger(log_name)
        end_logger.setLevel(logging.INFO)
        START_LOG = os.path.join(self.session.logs_dir, "end_status.log")
        fh = logging.FileHandler(START_LOG)
        fh.setLevel(logging.INFO)
        formatter = logging.Formatter("%(asctime)s - %(message)s")
        fh.setFormatter(formatter)
        end_logger.addHandler(fh)

        # get post-session monitor required data from device
        end_logger.info("Post-session information gathering")
        if modules_config:
            for module, params in modules_config.iteritems():
                if params["module_type"] == "monitor":
                    end_result = self.monitorManager.postSession(
                        module, params, self.session, device_serial=device_serial
                    )
                    log_file = os.path.join(self.session.logs_dir, module.replace(" ", "_") + ".post" + ".cap")
                    file_handler = open(log_file, "w+")
                    file_handler.write(end_result.__str__())
                    file_handler.close()

        # restore partitions
        end_logger.info("Restoring boot partition")
        self.restore_boot_partition(self.session, device_serial)
        end_logger.info("Restoring other partitions")
        self.partition.restore(
            twrp_path=self.tool.twrp,
            backup_src=self.session.partition_dir,
            backup_dest=device_backup_path,
            device_serial=device_serial,
        )

        return True

    def start_logger(self, session_id):
        # initilize status logging
        log_name = "start_status_%s" % session_id
        self.start_logger = logging.getLogger(log_name)
        self.start_logger.setLevel(logging.INFO)
        self.START_LOG = os.path.join(self.session.logs_dir, "status.log")
        fh = logging.FileHandler(self.START_LOG)
        fh.setLevel(logging.INFO)
        formatter = logging.Formatter("%(asctime)s - %(message)s")
        fh.setFormatter(formatter)
        self.start_logger.addHandler(fh)

    def start(self, modules_config, session_id, apk_paths, duration, device_serial):
        """
        Begin sandbox analysis.
        :param modules_config: parameters selected from configuration page
        :type modules_config: dictionary. configuration of modules from django session database
        :return: if analysis is successful or not
        """

        # create session directory
        self.create_session_dir(session_id, device_serial)
        # session object
        self.session = Session(session_id)

        self.start_logger(session_id)

        # checking device temp folders are ready
        self.start_logger.info("Initilizing device %s", device_serial)
        self.start_logger.info("Checking device temp folders are ready")
        self.check_device_tmp_folders(device_serial)

        # create symbolic link for apks
        self.start_logger.info("Creating symbolic links for APKs")
        self.create_apk_symbolic_links(apk_paths)
        # backup device partitions
        self.start_logger.info("Backing up partitions")
        device_backup_path = self.backup_device_partitions(device_serial)

        # prepare device for session (haven't copy to device yet)
        self.start_logger.info("Preparing device partitions")
        is_partition_init = self.prepare_device_for_session(device_serial, modules_config)

        # install user profile
        self.start_logger.info("Installing user profile")
        self.install_user_profile(device_serial, modules_config)

        # copy daemons to device
        self.start_logger.info("Copying daemons onto device")
        self.copy_daemons_to_device(device_serial, modules_config)

        # push modified partition to device
        self.start_logger.info("Pushing modified partitions to device")
        self.push_modified_partition_to_device(device_serial, is_partition_init)

        # get baseline of the device (pre session)
        # depending on the monitor modules requirements
        self.start_logger.info("Pre-session initilizations")
        self.device_presession(device_serial, modules_config)

        # lastly, install the suspicious apk
        self.start_logger.info("Installing APK on device")
        package_name = self.install_apk(device_serial)
        while not package_name:
            package_name = self.install_apk(device_serial)

        # whitelist package name for monitoring
        self.whitelist_package_name(package_name, device_serial)

        # run profile simulation script
        self.start_logger.info("package name is %s" % package_name)
        self.start_logger.info("Running profile simulation")

        now = datetime.datetime.now()
        end_time = now + datetime.timedelta(minutes=duration)
        end_time_str = end_time.strftime("%H:%M:%S %d-%m-%Y")
        self.run_profile_simulation(duration, modules_config, device_serial, package_name, self.session)
        self.start_logger.info("Session end time:  %s" % end_time_str)

        return (device_backup_path, self.START_LOG, end_time)

    def whitelist_package_name(self, package_name, device_serial):
        tmp_path = self.device.daemon_path(device_serial)
        whitelist_path = os.path.join(tmp_path, "whitelist.txt")
        add_whitelist_command = 'echo "%s" > %s' % (package_name, whitelist_path)
        result = self.adb.shell(add_whitelist_command, root=True, device_serial=device_serial)

    def check_device_tmp_folders(self, device_serial):
        """
        Check android device for the temp folders declared in devices.ini
        :param device_serial: device serial no.
        :return: boolean result
        """
        try:
            device_backup_path = self.device.backup_path(device_serial)
            device_daemon_path = self.device.daemon_path(device_serial)

            paths = [device_backup_path, device_daemon_path]
            for path in paths:
                check_path_command = "ls %s" % path
                result = self.adb.shell(check_path_command, device_serial=device_serial, root=True)
                if not result.std_output:
                    log.error(
                        "device %s is not ready for DroidPot! Ensure all tmp folders declared in devices.ini are present on the device"
                    )
                    return False

            return True
        except Exception as e:
            log.error(
                "device %s is not ready for DroidPot! Ensure all tmp folders declared in devices.ini are present on the device"
            )
            return False

    def run_profile_simulation(self, duration, modules_config, device_serial, package_name, session):
        # try:
        log.info("Running user simulation")
        if modules_config:
            for modules, params in modules_config.iteritems():
                try:
                    if params["module_type"] == "profile":
                        simulation_option = params["simulation_option"]
                        p = Process(
                            target=run_simulation,
                            args=(simulation_option, modules, duration, device_serial, package_name, session),
                        )
                        p.start()
                        break  # break in case there's more than 1 profile selected
                except KeyError as e:
                    pass
        # except Exception as e:
        # log.error("Unable to run profile simulation")
        # time.sleep(10)
        # self.run_profile_simulation(duration, modules_config,device_serial, package_name, session)

    def install_apk(self, device_serial):
        try:
            log.info("Installing sample apk")
            self.adb.wait_for_device(device_serial)
            apks = os.listdir(self.session.apk_dir)
            for apk in apks:
                apk_path = os.path.join(self.session.apk_dir, apk)
                if os.path.isfile(apk_path):
                    log.info("Installing apk %s" % (apk_path))

                    get_current_packages_command = "pm list packages"
                    result = self.adb.shell(get_current_packages_command, root=True, device_serial=device_serial)
                    packages = result.std_output

                    apk_realpath = os.path.realpath(apk_path)
                    self.adb.push(source=apk_realpath, dest="/sdcard/tmp.apk", device_serial=device_serial)
                    time.sleep(2)
                    self.adb.shell("pm install -rt /sdcard/tmp.apk", root=True, device_serial=device_serial)
                    time.sleep(2)
                    self.adb.shell("rm -f /sdcard/tmp.apk", root=True, device_serial=device_serial)
                    # os.remove(apk_path)

                    result = self.adb.shell(get_current_packages_command, root=True, device_serial=device_serial)
                    packages_after = result.std_output
                    sample_package_name = ""
                    for package in packages_after:
                        if not packages.__contains__(package):
                            sample_package_name = package.replace("package:", "")

                    return sample_package_name
                    # break

                    # Note: ONLY 1 APK TO BE ANALYSIS AT A TIME. AFTER ANALYSIS SESSION, INSTALL THE NEXT APK
        except Exception as e:
            log.error("Unable to install APK onto device")
            print e
            time.sleep(10)
            return ""

    def device_presession(self, device_serial, modules_config):
        try:
            log.info("Getting device baseline")
            self.adb.wait_for_device(device_serial)
            time.sleep(10)
            if modules_config:
                for module, params in modules_config.iteritems():
                    if params["module_type"] == "monitor":
                        baseline = self.monitorManager.preSession(module, params, self.session, device_serial)

                        print "baseline file result is "
                        print baseline

                        # store baseline information into an analysis file
                        log_file = os.path.join(self.session.logs_dir, module.replace(" ", "_") + ".pre" + ".cap")

                        file_handler = open(log_file, "w+")
                        file_handler.write(baseline.__str__())
                        file_handler.close()
        except Exception as e:
            log.error("Unable to get baseline of device")
            time.sleep(10)
            self.device_presession(device_serial, modules_config)

    def push_modified_partition_to_device(self, device_serial, is_partition_init):
        try:
            log.info("Modifying device's partitions")
            if is_partition_init:
                self.push_boot_partition(self.session, device_serial=device_serial)
        except Exception as e:
            log.error("Unable to push modified partition to device")
            time.sleep(10)
            self.push_modified_partition_to_device(device_serial, is_partition_init)

    def copy_daemons_to_device(self, device_serial, modules_config):
        try:
            log.info("Transferring daemons to device")
            if modules_config:
                for module, params in modules_config.iteritems():
                    # copy each module's daemons individually into device

                    if params["module_type"] == "monitor":
                        daemon = self.monitorManager.daemons(module, params)
                        if daemon:
                            self.copy_daemons(daemon, self.session)
                            # check device ini for temp path preference
                            dev_daemon_path = self.device.daemon_path(device_serial)
                            self.push_daemons(self.session, dev_daemon_path, device_serial=device_serial)

        except Exception as e:
            log.error("Unable to install process monitors on device")
            time.sleep(10)
            self.copy_daemons_to_device(device_serial, modules_config)

    def install_user_profile(self, device_serial, modules_config):
        try:
            log.info("Installing profile on device")
            self.adb.wait_for_device(device_serial)
            if modules_config:
                for module, params in modules_config.iteritems():
                    if params["module_type"] == "profile":
                        self.profileManager.setup_device(module, params, device_serial)
                        break
        except Exception as e:
            log.error("Unable to install user profile onto device")
            time.sleep(10)
            self.install_user_profile(device_serial, modules_config)

    def prepare_device_for_session(self, device_serial, modules_config):
        try:
            is_partition_init = self.monitorManager.prepare(modules_config, self.session, device_serial)
        except Exception as e:
            log.error("Unable to prepare partitions for session")
            time.sleep(10)
            return self.prepare_device_for_session(device_serial, modules_config)

        return is_partition_init

    def backup_device_partitions(self, device_serial):
        try:
            log.info("Backing up device partitions")
            self.start_logger.info("Performing TWRP backup")
            device_backup_path = self.partition.backup(
                twrp_path=self.tool.twrp, backup_dest=self.session.partition_dir, device_serial=device_serial
            )

            if device_backup_path:
                log.debug("Backup completed, extracting boot partition for modification")

                time.sleep(3)
                self.device_backup_path = device_backup_path
                is_boot_extracted = self.get_and_extract_boot_partition(self.session, device_serial=device_serial)
                while not is_boot_extracted:
                    time.sleep(3)
                    is_boot_extracted = self.get_and_extract_boot_partition(self.session, device_serial=device_serial)
        except Exception as e:
            log.error("Unable to perform backup")
            time.sleep(2)
            return self.backup_device_partitions(device_serial)

        return device_backup_path

    def create_apk_symbolic_links(self, apk_paths):
        try:
            log.info("Creating symbolic links for APKs")
            for apk_name, apk_realpath in apk_paths.iteritems():
                os.symlink(apk_realpath, os.path.join(self.session.apk_dir, apk_name))
        except Exception as e:
            log.error("Unable to create symbolic link for apks")
            time.sleep(10)
            self.create_apk_symbolic_links(apk_paths)

    def get_baseline(self, device_serial):
        """
        Get the device baseline processes
        """
        process_names = []

        list_proc_command = "ls /proc/"
        output = self.adb.shell(list_proc_command, root=True, needOutput=True, device_serial=device_serial)
        processes = output.std_output

        commands = ""
        for proc in processes:
            get_proc_name_command = "cat /proc/%s/status" % (proc)

            commands += get_proc_name_command + " && "

        proc_name = self.adb.shell(commands, root=True, needOutput=True, device_serial=device_serial).std_output
        if proc_name:
            process_names.append(proc_name)

        return process_names

    """
    DAEMON HANDLER
    handles the copying daemons into session directory and pushing daemons to android device
    """

    def copy_daemons(self, daemons, session):
        daemon_dir = session.daemon_dir

        for module_name, daemons_path in daemons.iteritems():
            log.debug("found %s in module %s" % (daemons_path, module_name))

            for d_path in daemons_path:
                shutil.copy(d_path, daemon_dir)
        return True

    def push_daemons(self, session, dir, device_serial):
        daemon_dir = session.daemon_dir

        for daemon in os.listdir(daemon_dir):
            log.info("[*] Pushing %s to device" % daemon)
            log.debug("pushing %s to device %s directory" % (daemon, dir))
            source = os.path.join(daemon_dir, daemon)

            self.adb.push(source=source, dest=dir, device_serial=device_serial)

            log.info("[*] Changing permission of daemons")
            device_daemon_path = os.path.join(dir, daemon)
            chmod_command = "chmod 777 %s" % device_daemon_path
            chown_command = "chown root:root %s" % device_daemon_path
            self.adb.shell(chown_command, root=True, device_serial=device_serial)
            self.adb.shell(chmod_command, root=True, device_serial=device_serial)

        return True

    """
    PARTITION HANDLER
    handles the partition extraction and reflashing of android device
    """

    def get_and_extract_boot_partition(self, session, device_serial):
        self.start_logger.info("Extracting boot partition for modification")
        EXTRACTED_BOOT_LOC = "/sdcard/boot.img"

        # retrieve boot partition location
        retry = True
        while retry:
            log.warn("[*] Retrieving boot partition location...")
            command = "ls -al /dev/block/platform/msm_sdcc.1/by-name | grep ' boot'"
            result = self.adb.shell(command=command, device_serial=device_serial)

            boot_image_loc = ""

            for output in result.std_output:
                log.debug("result line: %s" % output)
                try:
                    output_split = output.split("-> ")
                    boot_image_loc = output_split[1]
                    boot_image_loc.replace("\r", "")
                    retry = False
                except IndexError:
                    log.debug("Cannot get boot partition location. Retrying.")
                    time.sleep(3)
                    pass

        time.sleep(5)

        # copy image locally
        log.info("[*] dd image on device...")
        command = "dd if=" + boot_image_loc + " of=" + EXTRACTED_BOOT_LOC
        result = self.adb.shell(root=True, command=command, device_serial=device_serial)

        if not result.isSuccess:
            raise OSError

        time.sleep(5)

        # pulling boot.img from device
        log.info("[*] Pulling boot.img from device...")
        self.adb.pull(source=EXTRACTED_BOOT_LOC, dest=session.partition_dir, device_serial=device_serial)

        time.sleep(5)

        # decompress boot.img
        log.info("[*] Decompressing boot.img with mkboot tool...")
        params = " ".join([session.bootimg_dir, session.extracted_boot_dir])

        log.debug("parameters are %s" % params)
        cmd = Command()
        cmd.setCommand(self.tool.mkboot)
        cmd.setParameters(params)
        logging.debug(params)
        cmd.execute()

        time.sleep(5)

        if not os.path.exists(session.extracted_boot_dir):
            self.start_logger.info("Extracting boot partition failed")
            return False
        else:
            return True

    def push_boot_partition(self, session, device_serial):
        # create new boot.img
        logging.debug("creating new boot partition")
        params = " ".join([session.extracted_boot_dir, session.new_bootimg_dir])
        cmd = Command()
        cmd.setCommand(self.tool.mkboot)
        cmd.setParameters(params)
        logging.debug(params)
        cmd.execute()

        time.sleep(5)

        # push new partition to device
        self.adb.reboot_bootloader(device_serial)
        time.sleep(5)

        fastboot_devices = self.fastboot.devices()
        for i in range(0, 5):
            if len(fastboot_devices) > 0:
                log.info("[*] Device found in bootloader mode")
                break
            else:
                log.info("[!] Could not detect device in bootloader mode. Retrying...")
                time.sleep(10)
                fastboot_devices = self.fastboot.devices()

            if i == 4:
                log.warning("[!] Could not detect device in bootloader mode. TIME OUT")
                return False

        # flash boot partition with fastboot
        # must be in sudo
        log.info("[*] Flashing partition with new image")

        self.fastboot.flash(partition="boot", image_path=session.new_bootimg_dir, device_serial=device_serial)

        time.sleep(5)
        self.fastboot.reboot(device_serial)

    def restore_boot_partition(self, session, device_serial):
        log.info("[*] Restoring boot partition...")
        self.adb.wait_for_device(device_serial)
        self.adb.reboot_bootloader(device_serial)

        while True:
            devices = self.fastboot.devices()
            if devices:
                break

        self.fastboot.flash("boot", session.bootimg_dir, device_serial=device_serial)
        self.fastboot.reboot(device_serial)
Ejemplo n.º 3
0
def monitoring(request):
    '''
    Controller for monitoring module page
    :param request:
    :return:
    '''
    monitorsManager = MonitorsManager()
    request_path = request.path
    request_path = request_path.split('/')
    module_name = request_path[len(request_path) - 1]

    current_session = Sandbox_Session.objects.get(status=Sandbox_Session.CONFIGURING)
    module_form = monitorsManager.configForms(current_session.device_serial, module_name)

    module_info = monitorsManager.modules_info(module_name=module_name)

    if request.method == 'GET':
        apply =  request.GET.get("apply")

        current_session = Sandbox_Session.objects.get(status=Sandbox_Session.CONFIGURING)
        module_params = {}
        try:
            configuration = ast.literal_eval(current_session.configuration)
            #retrieve any existing configurations in database
            for module, params in configuration.iteritems():
                if module == module_name:
                    module_params = params
        except SyntaxError:
            pass
        '''
        #retrieve form object form module
        module_form = object
        module_info = object
        for pluginInfo, form in monitorModules.iteritems():
            if pluginInfo.name == module_name:
                module_form = form(module_params)
                module_info = pluginInfo
        '''

        profileModules = profileManager.modules_info()
        monitorModules = monitorsManager.modules_info()
        params = {
            "isMonitoring":True,
            "module_form":module_form,
            "profileModules":profileModules,
            "monitorModules":monitorModules,
            "module_info":module_info,
            "apply":apply,
            "current_session":current_session,
        }
        return render_to_response("dashboard/monitoring.html", params, context_instance=RequestContext(request))

    if request.method == "POST":
        config = {module_name:{}}

        params = request.POST
        for key in params.iterkeys():
            value = request.POST.getlist(key)
            if key == "csrfmiddlewaretoken" or key == "action":
                pass
            else:
                #extract the only element in value list with 1 element
                if len(value) == 1:
                    config[module_name][key] = value[0]
                else:
                    config[module_name][key] = value

        config[module_name]["module_type"] = "monitor"

        current_session = Sandbox_Session.objects.get(status=Sandbox_Session.CONFIGURING)
        if current_session.configuration:
            configuration = ast.literal_eval(current_session.configuration)
            for key,value in config.iteritems():
                configuration[key] = value
                current_session.configuration = configuration
        else:
            current_session.configuration = config

        current_session.save()

        hold_sessions = Sandbox_Session.objects.filter(status=Sandbox_Session.HOLD)

        for hold_session in hold_sessions:
            hold_session.configuration = current_session.configuration
            hold_session.save()

        return redirect('/monitoring/'+module_name+"?apply=True")