Esempio n. 1
0
    def run(self):
        result = {
            "title": "Application Uses Deprecated Ciphers",
            "details": "",
            "severity": "Low",
            "report": False
        }

        # preparing variable to run
        ciphers = []
        ignore = [filepath.strip() for filepath in self.ignore.split(";")]

        Log.info("Identifying smali directories")
        dirs = smali_dirs(self.decompiled_apk)

        Log.info("Analysing application's smali code")
        for directory in dirs:
            smali = "{}/{}".format(self.decompiled_apk, directory)
            ssl_socket_files = pretty_grep(self.file_regex, smali)
            ciphers += pretty_grep(self.regex, smali)

        if ciphers:
            result.update({
                "report": True,
                "details": pretty_grep_to_str(
                    ciphers, self.decompiled_apk, ignore)
            })

        return {
            "{}_result".format(self.name()): result
        }
Esempio n. 2
0
def extract_providers(decompiled_app_path):
    """
    Extracts provider paths from a decompiled app directory using grep

    :param str decompiled_app_path: the directory where to look for the
    providers
    :return: a sorted list of proviers
    """
    from scrounger.utils.general import pretty_grep
    import re

    providers_regex = r"content://[a-zA-Z0-1.-@/]+"
    providers = []

    grep_result = pretty_grep(providers_regex, decompiled_app_path)

    for filename in grep_result:
        for finding in grep_result[filename]:
            # needs regex search since grep returns the whole line
            provider_path = re.search(providers_regex,
                                      finding["details"]).group().split(
                                          "://", 1)[-1].strip()

            # make sure that every provider follows a standard and has no /
            # in the end
            if provider_path.endswith("/"):
                provider_path = provider_path[:-1]

            # TODO: translate @string to value
            providers.append(provider_path)

    # creates a set to make sure there are no duplicates and returns a sorted
    # list
    return sorted(set(providers))
Esempio n. 3
0
    def run(self):
        result = {
            "title": "Application Does Not Implement SSL Pinning",
            "details": "",
            "severity": "Medium",
            "report": False
        }

        Log.info("Getting application's strings")
        strs = strings(self.binary)

        Log.info("Analysing strings and class dump")
        matches = re.findall(self._regex, strs)
        evidence = pretty_grep(self._regex, self.class_dump)

        if matches:
            result.update({
                "report":
                True,
                "details":
                "The following strings were found:\n* {}".format("\n* ".join(
                    sorted(set(matches))))
            })

        if evidence:
            result.update({
                "report":
                True,
                "details":
                "{}\nThe following was found in the class dump:\n\
{}".format(result["details"], pretty_grep_to_str(evidence, self.class_dump))
            })

        return {"{}_result".format(self.name()): result}
Esempio n. 4
0
    def run(self):
        result = {
            "title": "Application Does Not Implement Root Detection",
            "details": "",
            "severity": "High",
            "report": True
        }

        # preparing variable to run
        root_detection = {}
        ignore = [filepath.strip() for filepath in self.ignore.split(";")]

        Log.info("Identifying smali directories")
        dirs = smali_dirs(self.decompiled_apk)

        Log.info("Analysing application's smali code")
        for directory in dirs:
            smali = "{}/{}".format(self.decompiled_apk, directory)
            root_detection.update(pretty_grep(self.regex, smali))

        if root_detection:
            result = {
                "title":
                "Application Has Root Detection",
                "details":
                pretty_grep_to_str(root_detection, self.decompiled_apk,
                                   ignore),
                "severity":
                "Low",
                "report":
                True
            }

        return {"{}_result".format(self.name()): result}
Esempio n. 5
0
    def run(self):
        result = {
            "title": "Application Does Not Check For Third-Party Keyboards",
            "details": "",
            "severity": "Low",
            "report": False
        }

        # preparing variable to run
        third_party_keyboard_evidence = {}
        ignore = [filepath.strip() for filepath in self.ignore.split(";")]

        Log.info("Identifying smali directories")
        dirs = smali_dirs(self.decompiled_apk)

        Log.info("Analysing application's smali code")
        for directory in dirs:
            smali = "{}/{}".format(self.decompiled_apk, directory)
            third_party_keyboard_evidence.update(pretty_grep(
                self.regex, smali))

            # remove ignored paths
            to_remove = []
            for filename in third_party_keyboard_evidence:
                if any(filepath in filename for filepath in ignore):
                    to_remove += [filename]
            for filename in to_remove:
                third_party_keyboard_evidence.pop(filename)

        if not third_party_keyboard_evidence:
            result.update({"report": True})

        return {"{}_result".format(self.name()): result}
Esempio n. 6
0
def string(string_variable, resources_strings_xml_file):
    """
    Looks for a string variable in the resources files

    :param str string_variable: the string variable to look for
    :param str resources_strings_xml_file: the strings.xml file to look for the
    string variable
    :return: the string value of the variable or `string_variable` if not found
    """
    from scrounger.utils.general import pretty_grep

    #replace @string if in variable name
    string_variable = string_variable.replace("@string/", "")

    grep_result = pretty_grep(string_variable, resources_strings_xml_file)

    # if variable was not found
    if len(grep_result) == 0:
        return string_variable

    # get the string from grep result
    string = grep_result.popitem()[1][0]["details"]

    # get the string between tags
    return string.split(">", 1)[-1].split("<", 1)[0]
Esempio n. 7
0
def public_resource(decompiled_app_path, resource_id):
    """
    Looks for strings reference for the resource

    :param str decompiled_app_path: the directory with the decompiled app
    :param str resource_id: the resource to look for
    :return: a str witht he resource or the str with the resource id
    """
    from scrounger.utils.general import pretty_grep

    # public xml file
    public_xml = "{}/res/values/public.xml".format(decompiled_app_path)

    grep_result = pretty_grep(resource_id, public_xml)

    # if variable was not found
    if len(grep_result) == 0:
        return resource_id

    # get the string from grep result
    string = grep_result.popitem()[1][0]["details"]

    # get the string between tags
    # <public type="string" name="action_update" id="0x7f0c0015" />
    return string.split("name=\"", 1)[-1].split("\" ", 1)[0]
Esempio n. 8
0
    def run(self):
        result = {
            "title": "Application Does Not Implement SSL Pinning",
            "details": "",
            "severity": "High",
            "report": False
        }

        # preparing variable to run
        ssl_keywords = {}
        ignore = [filepath.strip() for filepath in self.ignore.split(";")]

        Log.info("Identifying smali directories")
        dirs = smali_dirs(self.decompiled_apk)

        Log.info("Analysing application's smali for SSL evidences")
        for directory in dirs:
            smali = "{}/{}".format(self.decompiled_apk, directory)
            ssl_keywords.update(pretty_grep(self.regex, smali))

        if not ssl_keywords:
            result.update({
                "report": True,
                "details": "Found no evidences of a `TrustManager`."
            })

        Log.info("Analysing SSL evidences")

        for filename in ssl_keywords:
            if any(filepath in filename for filepath in ignore):
                continue

            with open(filename, "r") as fp:
                smali = fp.read()

            if re.search(self.mock_check_server, smali):
                result.update({
                    "report":
                    True,
                    "details":
                    "{}\n* {}:{}\n".format(
                        result["details"],
                        filename.replace(self.decompiled_apk, ""),
                        extract_smali_method("checkServerTrusted", filename))
                })

            if re.search(self.mock_accepted_issuers, smali):
                result.update({
                    "report":
                    True,
                    "details":
                    "{}\n* {}:{}\n".format(
                        result["details"],
                        filename.replace(self.decompiled_apk, ""),
                        extract_smali_method("getAcceptedIssuers", filename))
                })

        return {"{}_result".format(self.name()): result}
Esempio n. 9
0
    def run(self):
        result = {
            "title": "Application Does Not Prevent Screenshots",
            "details": "",
            "severity": "Low",
            "report": False
        }

        # preparing variable to run
        report_activities = []
        activities = {}
        ignore = [filepath.strip() for filepath in self.ignore.split(";")]

        Log.info("Identifying smali directories")
        dirs = smali_dirs(self.decompiled_apk)

        Log.info("Analysing application's smali code")
        for directory in dirs:
            smali = "{}/{}".format(self.decompiled_apk, directory)
            activities.update(pretty_grep(self.activities_regex, smali))

        if activities:
            safe_activities = pretty_grep(
                self.regex, " ".join(list(activities)))
            report_activities = list(set(activities) - set(safe_activities))

        if report_activities:
            result.update({
                "report": True,
                "details": "* {}".format("\n* ".join(
                    [activity.replace(self.decompiled_apk, "")
                    for activity in report_activities if not any(
                        i in activity for i in ignore)
                    ])
                )
            })

        return {
            "{}_result".format(self.name()): result
        }
Esempio n. 10
0
    def run(self):
        result = {
            "title": "Application's WebViews Are Vulnerable To Arbitrary \
Redirection",
            "details": "",
            "severity": "Low",
            "report": False
        }

        # preparing variable to run
        webview_files = {}
        overrride_url_files = {}
        ignore = [filepath.strip() for filepath in self.ignore.split(";")]

        Log.info("Identifying smali directories")
        dirs = smali_dirs(self.decompiled_apk)

        Log.info("Analysing application's smali code")
        for directory in dirs:
            smali = "{}/{}".format(self.decompiled_apk, directory)
            webview_files.update(pretty_grep(self.use_webview_regex, smali))
            overrride_url_files.update(pretty_grep(self.regex, smali))

        Log.info("Analysing WebViews")

        for filename in overrride_url_files:
            webview_files.pop(filename)

        if webview_files:
            result.update({
                "report":
                True,
                "details":
                pretty_grep_to_str(webview_files, self.decompiled_apk, ignore)
            })

        return {"{}_result".format(self.name()): result}
Esempio n. 11
0
    def run(self):
        result = {
            "title": "Application's WebViews Enable JavaScript",
            "details": "",
            "severity": "Medium",
            "report": False
        }

        # preparing variable to run
        filenames = {}
        ignore = [filepath.strip() for filepath in self.ignore.split(";")]

        Log.info("Identifying smali directories")
        dirs = smali_dirs(self.decompiled_apk)

        Log.info("Analysing application's smali code")
        for directory in dirs:
            smali = "{}/{}".format(self.decompiled_apk, directory)
            filenames.update(pretty_grep(self.regex, smali))

        report = {}
        # check var setting
        for file_name in filenames:
            report[file_name] = []

            for instance in filenames[file_name]:
                var_name = instance["details"].split(
                    "}", 1)[0].split(",", 1)[-1].strip()

                var_setting = track_variable(
                    var_name, instance["line"], file_name)

                for setting_line in var_setting:
                    if "0x1" in setting_line["details"]:
                        report[file_name] += var_setting

        for file_name in report:
            filenames[file_name] += report[file_name]

        if filenames:
            result.update({
                "report": True,
                "details": pretty_grep_to_str(
                    filenames, self.decompiled_apk, ignore)
            })

        return {
            "{}_result".format(self.name()): result
        }
Esempio n. 12
0
    def run(self):
        result = {
            "title": "Application Does Not Delete Cached Files On Exit",
            "details": "",
            "severity": "Low",
            "report": False
        }

        # preparing variable to run
        webview_files = {}
        clear_cache = {}
        ignore = [filepath.strip() for filepath in self.ignore.split(";")]

        Log.info("Identifying smali directories")
        dirs = smali_dirs(self.decompiled_apk)

        Log.info("Analysing application's smali code")
        for directory in dirs:
            smali = "{}/{}".format(self.decompiled_apk, directory)
            webview_files.update(pretty_grep(self.use_webview_regex, smali))
            clear_cache.update(pretty_grep(self.regex, smali))

        Log.info("Analysing WebViews")

        for filename in clear_cache:
            webview_files.pop(filename)

        if webview_files:
            result.update({
                "report":
                True,
                "details":
                pretty_grep_to_str(webview_files, self.decompiled_apk, ignore)
            })

        return {"{}_result".format(self.name()): result}
Esempio n. 13
0
def app_used_resources(decompiled_app_path, ignored, identifier=None):
    """
    Returns the strings that correspond to the used resources

    :param str decompiled_app_path: the directory with the decompiled app
    :param list ignored: a list of paths to be ignored
    :param str identifier: if set it tries to identify only class names in the
    path equivalent to the identifier
    :return: list with strings
    """
    from scrounger.utils.general import pretty_grep

    # prepare identifier paths
    identifier_paths = []
    if identifier:
        identifier_path = identifier.replace(".", "/")
        while identifier_path.count("/") > 1:
            identifier_paths += [identifier_path]
            identifier_path = identifier_path.rsplit("/", 1)[0]

    lsmali_dirs = smali_dirs(decompiled_app_path)
    full_smali_path = []
    for ldir in lsmali_dirs:
        full_smali_path += ["{}/{}".format(decompiled_app_path, ldir)]

    # find 0xXXXXX and look for it in xml files
    xml_references_regex = r"const .*0x[a-z0-9]{8}"
    grep_result = pretty_grep(xml_references_regex, " ".join(full_smali_path))

    strings = []  # we want repeated string names
    for filename in grep_result:

        # check if path not to be ignored and filder identifier paths
        if not any([ignored_path in filename for ignored_path in ignored]) and \
        ((
            identifier and \
            any([id_path in filename for id_path in identifier_paths])
        ) or not identifier):

            for finding in grep_result[filename]:
                resource_id = finding["details"].strip().rsplit(" ", 1)[-1]
                resource = public_resource(decompiled_app_path, resource_id)
                if resource_id != resource:
                    strings += [resource]

    # return sorted classes but not unique
    return sorted(strings)
Esempio n. 14
0
def app_strings(decompiled_app_path, ignored, identifier=None):
    """
    Looks for strings in the smali code and xml files

    :param str decompiled_app_path: the directory with the decompiled app
    :param list ignored: a list of paths to be ignored
    :param str identifier: if set it tries to identify only class names in the
    path equivalent to the identifier
    :return: list with strings
    """
    from scrounger.utils.general import pretty_grep

    # prepare identifier paths
    identifier_paths = []
    if identifier:
        identifier_path = identifier.replace(".", "/")
        while identifier_path.count("/") > 1:
            identifier_paths += [identifier_path]
            identifier_path = identifier_path.rsplit("/", 1)[0]

    # grep class names from smali code
    string_regex = r"\".*?\""

    lsmali_dirs = smali_dirs(decompiled_app_path)
    full_smali_path = []
    for ldir in lsmali_dirs:
        full_smali_path += ["{}/{}".format(decompiled_app_path, ldir)]
    grep_result = pretty_grep(string_regex, " ".join(full_smali_path))

    strings = []  # we want repeated string names
    for filename in grep_result:

        # check if path not to be ignored and filder identifier paths
        if not any([ignored_path in filename for ignored_path in ignored]) and \
        ((
            identifier and \
            any([id_path in filename for id_path in identifier_paths])
        ) or not identifier):

            for finding in grep_result[filename]:

                # get string name
                name = finding["details"].split("\"")[1]
                strings += [name]

    return sorted(strings)
Esempio n. 15
0
    def run(self):
        result = {
            "title": "Application Communicates Over Unencrypted Channels",
            "details": "",
            "severity": "High",
            "report": False
        }

        # preparing variable to run
        pretty_result = ""
        ignore = [url.strip() for url in self.ignore.split(";")]

        Log.info("Identifying smali directories")
        dirs = smali_dirs(self.decompiled_apk)

        Log.info("Analysing application's smali code")
        for directory in dirs:
            smali = "{}/{}".format(self.decompiled_apk, directory)
            urls = pretty_grep(self.regex, smali)
            to_remove = []
            for url in urls:
                for detail in urls[url]:
                    if any(iurl in detail["details"] for iurl in ignore) or \
                    detail["details"] == "http://":
                        urls[url].remove(detail)

                    if not urls[url]:
                        to_remove += [url]

            for filename in to_remove:
                urls.pop(filename)

            pretty_result += pretty_grep_to_str(urls, smali)

        if pretty_result:
            result.update({
                "report": True,
                "details": pretty_result
            })

        return {
            "{}_result".format(self.name()): result
        }
Esempio n. 16
0
def class_names(decompiled_app_path, ignored, identifier=None):
    """
    Looks for class names from the smali code

    :param str decompiled_app_path: the directory with the decompiled app
    :param list ignored: a list of paths to be ignored
    :param str identifier: if set it tries to identify only class names in the
    path equivalent to the identifier
    :return: list with class names
    """
    from scrounger.utils.general import pretty_grep

    # prepare identifier paths
    identifier_paths = []
    if identifier:
        identifier_path = identifier.replace(".", "/")
        while identifier_path.count("/") > 1:
            identifier_paths += [identifier_path]
            identifier_path = identifier_path.rsplit("/", 1)[0]

    # grep class names from smali code
    class_regex = r"\.class.*L.*"
    grep_result = pretty_grep(class_regex, decompiled_app_path)

    classes = []  # we want repeated class names
    for filename in grep_result:

        # check if path not to be ignored and filder identifier paths
        if not any([ignored_path in filename for ignored_path in ignored]) and \
        ((
            identifier and \
            any([id_path in filename for id_path in identifier_paths])
        ) or not identifier):

            for finding in grep_result[filename]:

                # get class name
                name = finding["details"].rsplit("/", 1)[-1].rsplit(";", 1)[0]
                classes += [name]

    # return sorted classes but not unique
    return sorted(classes)
Esempio n. 17
0
    def run(self):
        result = {
            "title": "Application's WebViews Implement Javascript Bridges",
            "details": "",
            "severity": "Medium",
            "report": False
        }

        # preparing variable to run
        bridges = {}
        ignore = [filepath.strip() for filepath in self.ignore.split(";")]

        Log.info("Identifying smali directories")
        dirs = smali_dirs(self.decompiled_apk)

        Log.info("Analysing application's smali code")
        for directory in dirs:
            smali = "{}/{}".format(self.decompiled_apk, directory)
            bridges.update(pretty_grep(self.js_interface_regex, smali))

        report = {}
        # check var setting
        for file_name in bridges:
            report[file_name] = []

            for instance in bridges[file_name]:
                report[file_name] += method_name(instance["line"], file_name)

        bridges = {}  # TODO: check this works
        for file_name in report:
            bridges[file_name] += report[file_name]

        if bridges:
            result.update({
                "report":
                True,
                "details":
                pretty_grep_to_str(bridges, self.decompiled_apk, ignore)
            })

        return {"{}_result".format(self.name()): result}
Esempio n. 18
0
    def run(self):
        result = {
            "title": "Application Communicates Over Insecure Channels",
            "details": "",
            "severity": "Medium",
            "report": False
        }

        Log.info("Getting application's strings")
        strs = strings(self.binary)

        Log.info("Analysing strings and class dump")
        if not re.search(self._regex, strs) and \
        not pretty_grep(self._regex, self.class_dump):
            result.update({
                "report": True,
                "details": "No evidence of secure channels being used."
            })

        return {
            "{}_result".format(self.name()): result
        }
Esempio n. 19
0
    def run(self):
        result = {
            "title": "Application Is Vulnerable To Fragment Injection",
            "details": "",
            "severity": "Medium",
            "report": False
        }

        # create yaml
        apktool_module = YamlModule()
        apktool_module.decompiled_apk = self.decompiled_apk
        apktool = apktool_module.run()
        if "print" in apktool:
            return {"print": "Could not get the apktool yaml file"}
        apktool = apktool.popitem()[1]

        # preparing variable to run
        activities = {}
        ignore = [filepath.strip() for filepath in self.ignore.split(";")]

        Log.info("Identifying smali directories")
        dirs = smali_dirs(self.decompiled_apk)

        Log.info("Analysing application's apktool yaml and smali")
        for directory in dirs:
            smali = "{}/{}".format(self.decompiled_apk, directory)
            activities.update(pretty_grep(self.regex, smali))

        if activities and int(apktool.min_sdk()) < 18:
            result.update({
                "report":
                True,
                "details":
                pretty_grep_to_str(activities, self.decompiled_apk, ignore)
            })

        return {"{}_result".format(self.name()): result}
Esempio n. 20
0
    def run(self):
        result = {
            "title": "Application Does Not Implement SSL Pinning",
            "details": "",
            "severity": "Medium",
            "report": False
        }

        Log.info("Getting application's strings")
        strs = strings(self.binary)

        Log.info("Analysing strings and class dump")
        matches = re.findall(self._regex, strs)
        evidence = pretty_grep(self._regex, self.class_dump)

        if matches:
            result.update({
                "report":
                True,
                "details":
                "The following strings were found:\n* {}".format("\n* ".join(
                    sorted(set(matches))))
            })

        if evidence:
            result.update({
                "report":
                True,
                "details":
                "{}\nThe following was found in the class dump:\n\
{}".format(result["details"], pretty_grep_to_str(evidence, self.class_dump))
            })

        if self.device and self.identifier and \
        self.proxy_host != None and self.proxy_port != None:
            Log.info("Testing SSL Pinning using a proxy")
            Log.info(
                "Make sure your device trusts the CA in: {}/ca.crt".format(
                    _CERT_PATH))
            Log.info("Waiting for {} seconds to allow time to setup the \
proxy on the remote device".format(self.wait_time))
            sleep(int(self.wait_time))

            Log.info("Killing the application")
            self.device.stop(self.identifier)

            Log.info("Starting the SSL proxy")
            proxy_server = create_server(self.proxy_host, self.proxy_port,
                                         _CERT_PATH)

            Log.info("Starting the Application")
            self.device.start(self.identifier)

            Log.info("Waiting for the Application to start and make requests")
            sleep(10)

            pinned = list(
                set(proxy_server.server.connected) -
                set(proxy_server.server.requested))

            if not proxy_server.server.connected:
                Log.error("No connections made by the application")

            if pinned:
                result.update({
                    "report":
                    True,
                    "details":
                    "{}\n\nThe application started a connection but \
made no requests to the following domains:\n* {}".format(
                        result["details"], "\n* ".join(pinned))
                })

            proxy_server.stop()

        return {"{}_result".format(self.name()): result}
Esempio n. 21
0
    def run(self):
        from time import sleep
        result = {
            "title": "Application Does Not Implement SSL Pinning",
            "details": "",
            "severity": "High",
            "report": False
        }

        # preparing variable to run
        ssl_keywords = {}
        ignore = [filepath.strip() for filepath in self.ignore.split(";")]

        Log.info("Identifying smali directories")
        dirs = smali_dirs(self.decompiled_apk)

        Log.info("Analysing application's smali for SSL evidences")
        for directory in dirs:
            smali = "{}/{}".format(self.decompiled_apk, directory)
            ssl_keywords.update(pretty_grep(self.regex, smali))

        if not ssl_keywords:
            result.update({
                "report": True,
                "details": "Found no evidences of a `TrustManager`."
            })

        Log.info("Analysing SSL evidences")

        for filename in ssl_keywords:
            if any(filepath in filename for filepath in ignore):
                continue

            with open(filename, "r") as fp:
                smali = fp.read()

            if re.search(self.mock_check_server, smali):
                result.update({
                    "report":
                    True,
                    "details":
                    "{}\n* {}:{}\n".format(
                        result["details"],
                        filename.replace(self.decompiled_apk, ""),
                        extract_smali_method("checkServerTrusted", filename))
                })

            if re.search(self.mock_accepted_issuers, smali):
                result.update({
                    "report":
                    True,
                    "details":
                    "{}\n* {}:{}\n".format(
                        result["details"],
                        filename.replace(self.decompiled_apk, ""),
                        extract_smali_method("getAcceptedIssuers", filename))
                })

        if self.device and self.identifier and \
        self.proxy_host != None and self.proxy_port != None:
            Log.info("Testing SSL Pinning using a proxy")
            Log.info(
                "Make sure your device trusts the CA in: {}/ca.crt".format(
                    _CERT_PATH))
            Log.info("Waiting for {} seconds to allow time to setup the \
proxy on the remote device".format(self.wait_time))
            sleep(int(self.wait_time))

            Log.info("Killing the application")
            self.device.stop(self.identifier)

            Log.info("Starting the SSL proxy")
            proxy_server = create_server(self.proxy_host, self.proxy_port,
                                         _CERT_PATH)

            Log.info("Starting the Application")
            self.device.start(self.identifier)

            Log.info("Waiting for the Application to start and make requests")
            sleep(10)

            pinned = list(
                set(proxy_server.server.connected) -
                set(proxy_server.server.requested))

            if not proxy_server.server.connected:
                Log.error("No connections made by the application")

            if pinned:
                result.update({
                    "title":
                    "Application Implements SSL Pinning",
                    "report":
                    True,
                    "details":
                    "{}\n\nThe application started a connection but \
made no requests to the following domains:\n* {}".format(
                        result["details"], "\n* ".join(pinned))
                })

            proxy_server.stop()

        return {"{}_result".format(self.name()): result}
Esempio n. 22
0
    def run(self):
        result = {
            "title": "Application Does Not Detect Emulators",
            "details": "",
            "severity": "Medium",
            "report": True
        }

        # preparing variable to run
        emulator_detection = {}
        ignore = [filepath.strip() for filepath in self.ignore.split(";")]

        Log.info("Identifying smali directories")
        dirs = smali_dirs(self.decompiled_apk)

        Log.info("Analysing smali code for emulator detection mechanisms")
        for directory in dirs:
            smali = "{}/{}".format(self.decompiled_apk, directory)
            emulator_detection.update(pretty_grep(self.regex, smali))

        if emulator_detection:
            result = {
                "title":
                "Application Detects Emulators",
                "details":
                "{}\n\n{}".format(
                    result["details"],
                    pretty_grep_to_str(emulator_detection, self.decompiled_apk,
                                       ignore)),
                "severity":
                "Medium",
                "report":
                True
            }

        # dynamic testing
        Log.info("Checking requirements for dynamic testing")

        if hasattr(self, "apk") and hasattr(self, "avd") and \
        hasattr(self, "identifier") and self.identifier and \
        self.apk and self.avd:
            # get available devices before starting the emulator
            available_devices = devices()

            # start emulator
            Log.info("Starting the emulator")
            emulator_process = process("emulator -avd {}".format(self.avd))

            # wait for emulator to start
            sleep(60)

            # diff devices -> get emulator
            emulator_id = list(set(devices()) - set(available_devices))

            if len(emulator_id) != 1:
                Log.warn("Could not find the emulator in the device list")
                emulator_process.kill()
                return {
                    "{}_result".format(self.name()): result,
                    "print": "Coud not start emulator or find defined avd"
                }

            device = AndroidDevice(emulator_id)

            Log.info("Installing the apk in the device")
            device.install(self.apk)
            if device.installed(self.identifier):

                while not device.unlocked():
                    Log.info("Please unlock the emulator")
                    sleep(5)

                Log.info("Starting the application")
                device.start(identifier)
                sleep(15)

                if self.identifier not in device.processes():
                    result.update({"report": False})

            emulator_process.kill()

        return {"{}_result".format(self.name()): result}
Esempio n. 23
0
    def run(self):
        result = {
            "title": "Application Does Not Detect Debuggers",
            "details": "",
            "severity": "Medium",
            "report": False
        }

        ignore = [filepath.strip() for filepath in self.ignore.split(";")]

        Log.info("Identifying smali directories")
        dirs = smali_dirs(self.decompiled_apk)

        Log.info("Looking for evidence in smali code")
        debug_evidence = {}
        for directory in dirs:
            smali = "{}/{}".format(self.decompiled_apk, directory)
            debug_evidence.update(pretty_grep(self.debug_regex, smali))

        if debug_evidence:
            result.update({
                "title":
                "Application Destects Debuggers",
                "report":
                True,
                "details":
                "The following evidence was found in the smali \
code:\n{}".format(
                    pretty_grep_to_str(debug_evidence, self.decompiled_apk,
                                       ignore))
            })
        else:
            result.update({
                "details": "No evidence of debug detection was found in the \
smali code.",
                "report": True
            })

        if self.repackage:
            Log.info("Trying to modify the application to be debuggable")

            # make the application debuggable
            debug_module = DModule()
            debug_module.decompiled_apk = self.decompiled_apk
            debug_module.device = self.device
            debug_module.output = None  # will default to /tmp
            debug_module.install = True
            debug_module.run()

        Log.info("Starting the application and identifying the process ID")
        self.device.start(self.identifier)
        pid = self.device.pid(self.identifier)

        if pid:
            Log.info("Forwarding local ports")
            forward(54321, pid)

            Log.info("Starting JDB")
            jdb = JDB("127.0.0.1", 54321)

            if not jdb.running():
                result.update({
                    "report":
                    True,
                    "details":
                    "{}\n\nScrounger was unable to attach a debugger\
 to the application.".format(result["details"])
                })
            else:
                result.update({
                    "report":
                    True,
                    "details":
                    "{}\n\nScrounger was able to attach a debugger \
to the application:\n\n{}".format(result["details"], jdb.read())
                })

            Log.info("Removing forwarded ports and exiting jdb")
            remove_forward()
            jdb.exit()

        else:
            Log.error("The application is not running")

        return {"{}_result".format(self.name()): result}