Example #1
0
def findIntent(intent, results):
    """
	Find Intent 
	"""
    #TODO - This section is ugly and needs to be refactored
    #Looking for the intent used in the pending intent
    global tree
    found = False
    explicit = False
    if hasattr(tree, 'type_declarations'):
        for type_decl in tree.type_declarations:
            if type(type_decl) is m.ClassDeclaration:
                for t in type_decl.body:
                    if not found:
                        if type(t) is m.VariableDeclaration:
                            if hasattr(t, 'type'):
                                if type(t.type) is not str:
                                    report.write("parsingerror-issues-list",
                                                 str(current_file), "strong")
                                    common.logger.debug(
                                        "Please report the following error, if you see this"
                                    )
                                    common.logger.debug(
                                        "ERROR: INCOMPLETE CODE BRANCH REACHED findPending.py #6 - Press any key to continue (results may be incomplete)"
                                    )
                                    if str(t.type) == "Intent":
                                        common.logger.error(
                                            "FOUND Intent Variable 0: " +
                                            str(t))
                                    else:
                                        if hasattr(t.type, 'name'):
                                            if hasattr(t.type.name, 'value'):
                                                if str(t.type.name.value
                                                       ) == "Intent":
                                                    common.logger.debug(
                                                        "FOUND Intent Variable 1: "
                                                        + str(t))
                        else:
                            try:
                                temp = intent_digger(t, intent)
                            except Exception as e:
                                common.logger.debug(
                                    "Error in intent_digger function of findPending.py: "
                                    + str(e))
                            found = temp[0]
                            explicit = temp[1]
                            if found:
                                if not explicit:
                                    #See if the intent is explicit
                                    if type(t) is m.MethodInvocation:
                                        if str(t.name) == "setClass":
                                            explicit = True
                                        elif str(t.name) == "setPackage":
                                            explicit = True
                                    elif type(t) is m.MethodDeclaration:
                                        for f in t._fields:
                                            if type(getattr(t, f)) is list:
                                                for x in getattr(t, f):
                                                    if type(
                                                            x
                                                    ) is m.MethodInvocation:
                                                        if str(x.name
                                                               ) == "setClass":
                                                            explicit = True
                                                        elif str(
                                                                x.name
                                                        ) == "setPackage":
                                                            explicit = True
                                                    else:
                                                        if hasattr(
                                                                x, '_fields'):
                                                            for y in x._fields:
                                                                if type(
                                                                        getattr(
                                                                            x,
                                                                            y)
                                                                ) is m.MethodInvocation:
                                                                    if str(
                                                                            getattr(
                                                                                x,
                                                                                y
                                                                            ).
                                                                            name
                                                                    ) == "setClass":
                                                                        if hasattr(
                                                                                getattr(
                                                                                    x,
                                                                                    y
                                                                                )
                                                                                .
                                                                                target,
                                                                                'value'
                                                                        ):
                                                                            if str(
                                                                                    getattr(
                                                                                        x,
                                                                                        y
                                                                                    )
                                                                                    .
                                                                                    target
                                                                                    .
                                                                                    value
                                                                            ) == str(
                                                                                    intent
                                                                            ):
                                                                                explicit = True
                                                                            elif str(
                                                                                    getattr(
                                                                                        x,
                                                                                        y
                                                                                    )
                                                                                    .
                                                                                    name
                                                                            ) == "setPackage":
                                                                                if str(
                                                                                        getattr(
                                                                                            x,
                                                                                            y
                                                                                        )
                                                                                        .
                                                                                        target
                                                                                        .
                                                                                        value
                                                                                ) == str(
                                                                                        intent
                                                                                ):
                                                                                    explicit = True
                                                                        else:
                                                                            common.logger.debug(
                                                                                "Something went wrong in findPending, when determining if the Intent was explicit"
                                                                            )
                                                        elif type(x) is list:
                                                            common.logger.debug(
                                                                "ERROR: UNEXPECTED CODE PATH in findIntent - 1"
                                                            )
                                            elif type(getattr(
                                                    t,
                                                    f)) is m.MethodInvocation:
                                                common.logger.debug(
                                                    "ERROR: UNEXPECTED CODE PATH in findIntent - 2"
                                                )
                                    else:
                                        for f in t._fields:
                                            if type(getattr(t, f)) is list:
                                                for x in getattr(t, f):
                                                    if type(
                                                            x
                                                    ) is m.MethodInvocation:
                                                        if str(x.name
                                                               ) == "setClass":
                                                            explicit = True
                                                        elif str(
                                                                x.name
                                                        ) == "setPackage":
                                                            explicit = True
                                else:
                                    break
    else:
        common.logger.debug("NO TYPE DECLARATIONS")
    if not explicit:
        if found:
            issue = ReportIssue()
            issue.setCategory(ExploitType.INTENT)
            issue.setDetails(
                "Implicit Intent: " + str(intent) +
                " used to create instance of PendingIntent. A malicious application could potentially intercept, redirect and/or modify (in a limited manner) this Intent. Pending Intents retain the UID of your application and all related permissions, allowing another application to act as yours.  File: "
                + str(current_file) +
                " More details: https://www.securecoding.cert.org/confluence/display/android/DRD21-J.+Always+pass+explicit+intents+to+a+PendingIntent"
            )
            issue.setFile(current_file)
            issue.setSeverity(Severity.VULNERABILITY)
            results.append(issue)

            issue = terminalPrint()
            issue.setLevel(Severity.VULNERABILITY)
            issue.setData(
                "Implicit Intent: " + str(intent) +
                " used to create instance of PendingIntent. A malicious application could potentially intercept, redirect and/or modify (in a limited manner) this Intent. Pending Intents retain the UID of your application and all related permissions, allowing another application to act as yours.  File: "
                + str(current_file) +
                " More details: https://www.securecoding.cert.org/confluence/display/android/DRD21-J.+Always+pass+explicit+intents+to+a+PendingIntent"
            )
            results.append(issue)
        else:
            #TO DO - ensure we can resolve custom intents to avoid this error
            common.logger.debug(
                "ERROR: COULDN'T FIND THE INTENT: " + str(intent) +
                " This may either be due to a custom Intent class or other error"
            )
    return
Example #2
0
def show_wv_vulns(s_list,i,results):
    """
    Shows all identified web view vulnerabilities
    """
    #BUG - This sometimes prints twice, successively which shouldn't happen
    #print "#"*100
    issue = terminalPrint()
    issue.setLevel(Severity.INFO)
    issue.setData("WebView: " +str(i[0]))
    results.append(issue)
    #logger.info("WebView: " +str(i[0]))
    issue = terminalPrint()
    issue.setLevel(Severity.INFO)
    issue.setData("File: " + str(i[1]) +"\n")
    results.append(issue)
    #logger.info("File: " + str(i[1]) +"\n")

    if len(s_list)==0:
        default_wv_config(i[0], i[1], int(common.minSdkVersion), results)
        return

    for f in s_list:
        sl=re.sub(r'WebSettings\s*','',f)
        sl=re.sub(r'\s*[;=].*$','',sl)
        sl=re.sub(r'final\s','',sl)
        #strip string whitespace out
        sl=re.sub(r'^\W+','',sl)
        sl=re.sub(r'\.\w+\(\w+\)$','',sl)
        sl=sl.rstrip()
#Regex to look for javascript being enabled
#BUG I can reduce the number of files checked to only those that have the name / import WebViews
#Probably need to check for alternative true/false value representations
        wv_js_check=sl +'.setJavaScriptEnabled(true)'
        wv_js_check=re.escape(wv_js_check)
#check if webview JS in enabled
#BUG - THis can run twice, perhaps it is an artifact of an empty first element?
        if wv_config(i[1],wv_js_check):
            issue = ReportIssue()
            issue.setCategory(ExploitType.WEBVIEW)
            issue.setDetails(common.config.get('qarkhelper', 'JS_WARNING'))
            issue.setFile(str(i[1]))
            issue.setSeverity(Severity.WARNING)
            issue.setExtras(IS_JS_ENABLED, True)
            results.append(issue)

            issue = terminalPrint()
            issue.setLevel(Severity.WARNING)
            issue.setData(common.config.get('qarkhelper', 'TERMINAL_JS_WARNING') +" "+str(i[0]) +" "+common.config.get('qarkhelper', 'TERMINAL_JS_WARNING1') + " To validate this vulnerability, load the following url in this WebView: http://www.secbro.com/poc/html/JS_WARNING.html" + "Note: A local copy of this html file can also be found at <install_dir>/quark/poc/html/JS_WARNING.html\n")
            results.append(issue)
        else:
            issue = terminalPrint()
            issue.setLevel(Severity.INFO)
            issue.setData(common.config.get('qarkhelper', 'JS_OK') + " "+str(i[0]) + str(i[1]))
            results.append(issue)
#BUG - this is actually set on WebView
#Check whether webview sets arbitrary BaseURL
        wv_burl_check=re.escape(sl +'.loadDataWithBaseURL')
        if wv_config(i[1],wv_burl_check):
            issue = ReportIssue()
            issue.setCategory(ExploitType.WEBVIEW)
            issue.setDetails(common.config.get('qarkhelper', 'BURL_WARNING1'))
            issue.setFile(str(i[1]))
            issue.setSeverity(Severity.WARNING)
            issue.setExtras(IS_BASE_URL_DEFINED, False)
            results.append(issue)

            issue = terminalPrint()
            issue.setLevel(Severity.WARNING)
            issue.setData(common.config.get('qarkhelper', 'TERMINAL_BURL_WARNING1') + " "+str(i[0]) +" "+common.config.get('qarkhelper', 'TERMINAL_BURL_WARNING2') + "To validate this vulnerability, load the following url in this WebView: http://www.secbro.com/poc/html/BURL_WARNING.html " + "Note: A local copy of this html file can also be found at <install_dir>/quark/poc/html/BURL_WARNING.html\n")
            results.append(issue)
        else:
            issue = ReportIssue()
            issue.setCategory(ExploitType.WEBVIEW)
            issue.setDetails(common.config.get('qarkhelper', 'BURL_OK'))
            issue.setFile(str(i[1]))
            issue.setSeverity(Severity.INFO)
            issue.setExtras(IS_BASE_URL_DEFINED, True)
            results.append(issue)

            issue = terminalPrint()
            issue.setLevel(Severity.INFO)
            issue.setData(common.config.get('qarkhelper', 'BURL_OK'))
            results.append(issue)

    #Checks whether file URI can access filesystem
    #true by default, so the check is inverted
        wv_file_check=re.escape(sl+'.setAllowFileAccess(false)')
        if wv_config(i[1],wv_file_check):
            issue = ReportIssue()
            issue.setCategory(ExploitType.WEBVIEW)
            issue.setDetails(common.config.get('qarkhelper', 'FILE_SYS_OK'))
            issue.setFile(str(i[1]))
            issue.setSeverity(Severity.WARNING)
            issue.setExtras(IS_FILE_ACCESS_ENABLED, False)
            results.append(issue)

            issue = terminalPrint()
            issue.setLevel(Severity.INFO)
            issue.setData(common.config.get('qarkhelper', 'FILE_SYS_OK') + str(i[0]))
            results.append(issue)
        else:
            issue = ReportIssue()
            issue.setCategory(ExploitType.WEBVIEW)
            issue.setDetails(common.config.get('qarkhelper', 'FILE_SYS_WARN1'))
            issue.setFile(str(i[1]))
            issue.setSeverity(Severity.WARNING)
            issue.setExtras(IS_FILE_ACCESS_ENABLED, True)
            results.append(issue)

            issue = terminalPrint()
            issue.setLevel(Severity.WARNING)
            issue.setData(common.config.get('qarkhelper', 'TERMINAL_FILE_SYS_WARN1') + str(i[0]) +" "+ common.config.get('qarkhelper', 'TERMINAL_FILE_SYS_WARN2') + " To validate this vulnerability, load the following url in this WebView: http://www.secbro.com/poc/html/FILE_SYS_WARN.html " + "Note: A local copy of this html file can also be found at <install_dir>/quark/poc/html/FILE_SYS_WARN.html\n")
            results.append(issue)
#Regex to determine if WebViews have Content Provider access (default = true)
    #Checks whether WebView can access Content Providers
    #true by default, so the check is inverted
    #BUG - This can run twice, perhaps due to an empty element
        wv_cpa_check=re.escape(sl+'.setAllowContentAccess(false)')
        if wv_config(i[1],wv_cpa_check):
            issue = ReportIssue()
            issue.setCategory(ExploitType.WEBVIEW)
            issue.setDetails(common.config.get('qarkhelper', 'WV_CPA_OK'))
            issue.setFile(str(i[1]))
            issue.setSeverity(Severity.INFO)
            issue.setExtras(IS_CP_ACCESS_ENABLED, False)
            results.append(issue)

            issue = terminalPrint()
            issue.setLevel(Severity.INFO)
            issue.setData(common.config.get('qarkhelper', 'WV_CPA_OK') + str(i[0]))
            results.append(issue)
        else:
            issue = ReportIssue()
            issue.setCategory(ExploitType.WEBVIEW)
            issue.setDetails(common.config.get('qarkhelper', 'WV_CPA_WARNING'))
            issue.setFile(str(i[1]))
            issue.setSeverity(Severity.WARNING)
            issue.setExtras(IS_CP_ACCESS_ENABLED, True)
            results.append(issue)

            issue = terminalPrint()
            issue.setLevel(Severity.WARNING)
            issue.setData(common.config.get('qarkhelper', 'TERMINAL_WV_CPA_WARNING') + str(i[0]) + "To validate this vulnerability, load the following url in this WebView: http://www.secbro.com/poc/html/WV_CPA_WARNING.html " + "Note: A local copy of this html file can also be found at <install_dir>/quark/poc/html/WV_CPA_WARNING.html\n")
            results.append(issue)
    #check for JS access from file URL can access content from any origin
    #minSdk <= 15 default is true; minSdk > 16 default is false
    #BUG - This check is wrong on the second if; If set to false and not found, it prints OK
        if int(common.minSdkVersion) <16:
            wv_univ_file_access=re.escape(sl+'.setAllowUniversalAccessFromFileURLs(false)')
            if not wv_config(i[1],wv_univ_file_access):
                issue = ReportIssue()
                issue.setCategory(ExploitType.WEBVIEW)
                issue.setDetails(common.config.get('qarkhelper', 'UNIV_FILE_WARNING'))
                issue.setFile(str(i[1]))
                issue.setSeverity(Severity.WARNING)
                issue.setExtras(IS_FILE_ACCESS_ENABLED, True)
                results.append(issue)

                issue = terminalPrint()
                issue.setLevel(Severity.WARNING)
                issue.setData(common.config.get('qarkhelper', 'TERMINAL_UNIV_FILE_WARNING') +str(i[0]) + " To validate this vulnerability, load the following url in this WebView: http://www.secbro.com/poc/html/UNIV_FILE_WARNING.html " + "Note: A local copy of this html file can also be found at <install_dir>/quark/poc/html/UNIV_FILE_WARNING.html\n")
                results.append(issue)
                skip_next=True
            else:
                issue = ReportIssue()
                issue.setCategory(ExploitType.WEBVIEW)
                issue.setDetails(common.config.get('qarkhelper', 'UNIV_FILE_OK'))
                issue.setFile(str(i[1]))
                issue.setSeverity(Severity.INFO)
                issue.setExtras(IS_FILE_ACCESS_ENABLED, False)
                results.append(issue)

                issue = terminalPrint()
                issue.setLevel(Severity.INFO)
                issue.setData(common.config.get('qarkhelper', 'UNIV_FILE_OK') + str(i[0]))
                results.append(issue)
                skip_next=False
    #checking previous value above, as this is ignored if the above is true
    #could I just put pass above?
            if skip_next:
                pass
            else:
                #minSdk <= 15 default is true; minSdk > 16 default is false
                wv_allow_file_access_furls=re.escape(sl+'.setAllowFileAccessFromFileURLs(false)')
                if wv_config(i[1],wv_allow_file_access_furls):
                    issue = terminalPrint()
                    issue.setLevel(Severity.INFO)
                    issue.setData("This WebView does not have access to File URLs - setAllowFileAccessFromFileURLs(false)" + str(i[0]))
                    results.append(issue)

                    issue = ReportIssue()
                    issue.setCategory(ExploitType.WEBVIEW)
                    issue.setDetails("This WebView does not have access to File URLs - setAllowFileAccessFromFileURLs(false)")
                    issue.setFile(str(i[1]))
                    issue.setSeverity(Severity.WARNING)
                    issue.setExtras(IS_FILE_ACCESS_ENABLED, False)
                    results.append(issue)
                else:
                    issue = ReportIssue()
                    issue.setCategory(ExploitType.WEBVIEW)
                    issue.setDetails(common.config.get('qarkhelper', 'UNIV_FILE_WARNING'))
                    issue.setFile(str(i[1]))
                    issue.setSeverity(Severity.WARNING)
                    results.append(issue)

                    issue = terminalPrint()
                    issue.setLevel(Severity.WARNING)
                    issue.setExtras(IS_FILE_ACCESS_ENABLED, True)
                    issue.setData(common.config.get('qarkhelper', 'TERMINAL_UNIV_FILE_WARNING') + str(i[0]) + "To validate this vulnerability, load the following url in this WebView: http://www.secbro.com/poc/html/UNIV_FILE_WARNING2.html "+ "Note: A local copy of this html file can also be found at <install_dir>/quark/poc/html/UNIV_FILE_WARNING2.html\n")
                    results.append(issue)

        else:
            wv_univ_file_access=re.escape(sl+'.setAllowUniversalAccessFromFileURLs(true)')
            if wv_config(i[1],wv_univ_file_access):
                issue = ReportIssue()
                issue.setCategory(ExploitType.WEBVIEW)
                issue.setDetails(common.config.get('qarkhelper', 'UNIV_FILE_WARNING'))
                issue.setFile(str(i[1]))
                issue.setSeverity(Severity.WARNING)
                issue.setExtras(IS_UNIVERSAL_FILE_ACCESS_ENABLED, True)
                results.append(issue)

                issue = terminalPrint()
                issue.setLevel(Severity.WARNING)
                issue.setData(common.config.get('qarkhelper', 'TERMINAL_UNIV_FILE_WARNING') + '1 '+str(i[0]) + " To validate this vulnerability, load the following url in this WebView: http://www.secbro.com/poc/html/UNIV_FILE_WARNING.html " + "Note: A local copy of this html file can also be found at <install_dir>/quark/poc/html/UNIV_FILE_WARNING.html\n")
                results.append(issue)
                skip_next=True

            else:
                issue = ReportIssue()
                issue.setCategory(ExploitType.WEBVIEW)
                issue.setDetails(common.config.get('qarkhelper', 'UNIV_FILE_OK'))
                issue.setFile(str(i[1]))
                issue.setSeverity(Severity.INFO)
                issue.setExtras(IS_UNIVERSAL_FILE_ACCESS_ENABLED, False)
                results.append(issue)

                issue = terminalPrint()
                issue.setLevel(Severity.INFO)
                issue.setData(common.config.get('qarkhelper', 'UNIV_FILE_OK') + str(i[0]))
                results.append(issue)
                skip_next=False
    #checking previous value above, as this is ignored if the above is true
                if skip_next:
                    pass
                else:
                    #minSdk <= 15 default is true; minSdk > 16 default is false
                        wv_allow_file_access_furls=re.escape(sl+'.setAllowFileAccessFromFileURLs(true)')
                        if wv_config(i[1],wv_allow_file_access_furls):
                            issue = ReportIssue()
                            issue.setCategory(ExploitType.WEBVIEW)
                            issue.setDetails(common.config.get('qarkhelper', 'FURL_FILE_WARNING'))
                            issue.setFile(str(i[1]))
                            issue.setSeverity(Severity.WARNING)
                            issue.setExtras(IS_UNIVERSAL_FILE_ACCESS_ENABLED, True)
                            results.append(issue)

                            issue = terminalPrint()
                            issue.setLevel(Severity.WARNING)
                            issue.setData(common.config.get('qarkhelper', 'TERMINAL_FURL_FILE_WARNING') + str(i[0]) + "To validate this vulnerability, load the following url in this WebView: http://www.secbro.com/poc/html/FURL_FILE_WARNING.html " + "Note: A local copy of this html file can also be found at <install_dir>/quark/poc/html/FURL_FILE_WARNING.html\n")
                            results.append(issue)
                        else:
                            issue = ReportIssue()
                            issue.setCategory(ExploitType.WEBVIEW)
                            issue.setDetails(common.config.get('qarkhelper', 'FURL_FILE_OK'))
                            issue.setFile(str(i[1]))
                            issue.setSeverity(Severity.INFO)
                            issue.setExtras(IS_UNIVERSAL_FILE_ACCESS_ENABLED, False)
                            results.append(issue)

                            issue = terminalPrint()
                            issue.setLevel(Severity.INFO)
                            issue.setData(common.config.get('qarkhelper', 'FURL_FILE_OK') + str(i[0]))
                            results.append(issue)

    #Checking whether plugins are enabled for WebViews
    #setPluginsEnabled deprecated in API 9, removed in API 18
    #setPluginState added in API 8, deprecated in API 18
        wv_plugsinenabled=re.escape(sl+'.setPluginsEnabled(true)')
        wv_pluginstate=re.escape(sl+'.setPluginState(WebSettings.PluginState.ON*')

        if wv_config(i[1],wv_plugsinenabled):
            if int(common.minSdkVersion) < 18:
                issue = ReportIssue()
                issue.setCategory(ExploitType.WEBVIEW)
                issue.setDetails(common.config.get('qarkhelper', 'DEPRECATED_SINCE_9') +str(i[0]) + "<br>FILE: " +str(i[1]))
                issue.setFile(str(i[1]))
                issue.setSeverity(Severity.INFO)
                results.append(issue)

                issue = terminalPrint()
                issue.setLevel(Severity.INFO)
                issue.setData(common.config.get('qarkhelper', 'DEPRECATED_SINCE_9') +str(i[0]))
                results.append(issue)
            else:
                issue = ReportIssue()
                issue.setCategory(ExploitType.WEBVIEW)
                issue.setDetails(common.config.get('qarkhelper', 'REMOVED_IN_18')+str(i[0]) + "<br>FILE: " +str(i[1]))
                issue.setFile(str(i[1]))
                issue.setSeverity(Severity.INFO)
                results.append(issue)

                issue = terminalPrint()
                issue.setLevel(Severity.INFO)
                issue.setData(common.config.get('qarkhelper', 'REMOVED_IN_18')+str(i[0]))
                results.append(issue)
                logger.info(common.config.get('qarkhelper', 'REMOVED_IN_18')+str(i[0]))
        if wv_config(i[1],wv_pluginstate):
            if int(common.minSdkVersion) < 8:
                issue = ReportIssue()
                issue.setCategory(ExploitType.WEBVIEW)
                issue.setDetails(common.config.get('qarkhelper', 'ADDED_IN_8')+str(i[0]) + "<br>FILE: " +str(i[1]))
                issue.setFile(str(i[1]))
                issue.setSeverity(Severity.INFO)
                results.append(issue)

                issue = terminalPrint()
                issue.setLevel(Severity.INFO)
                issue.setData(common.config.get('qarkhelper', 'ADDED_IN_8')+str(i[0]))
                results.append(issue)
                logger.info(common.config.get('qarkhelper', 'ADDED_IN_8')+str(i[0]))
            else:
                issue = ReportIssue()
                issue.setCategory(ExploitType.WEBVIEW)
                issue.setDetails(common.config.get('qarkhelper', 'DEPRECATED_IN_18')+str(i[0])
                + "<br>FILE: " +str(i[1]))
                issue.setFile(str(i[1]))
                issue.setSeverity(Severity.INFO)
                results.append(issue)

                issue = terminalPrint()
                issue.setLevel(Severity.INFO)
                issue.setData(common.config.get('qarkhelper', 'DEPRECATED_IN_18')+str(i[0]))
                results.append(issue)
    #Check if addJavascriptInterface is used in WebView
    #BUG - this is actually on WebView, not settings
        wv_ajs=re.escape(sl+'.addJavascriptInterface')
        if wv_config(i[1],wv_ajs):
            if int(common.minSdkVersion)<17:
                issue = ReportIssue()
                issue.setCategory(ExploitType.WEBVIEW)
                issue.setDetails(common.config.get('qarkhelper', 'BAD_JS_INT'))
                issue.setFile(str(i[1]))
                issue.setSeverity(Severity.WARNING)
                results.append(issue)

                issue = terminalPrint()
                issue.setLevel(Severity.WARNING)
                issue.setData(common.config.get('qarkhelper', 'TERMINAL_BAD_JS_INT') + " "+str(i[0]) + " To validate this vulnerability, load the following url in this WebView: http://www.secbro.com/poc/html/BAD_JS_INT.html " + "Note: A local copy of this html file can also be found at <install_dir>/quark/poc/html/BAD_JS_INT.html" +"\n")
                results.append(issue)
            else:
                issue = ReportIssue()
                issue.setCategory(ExploitType.WEBVIEW)
                issue.setDetails(common.config.get('qarkhelper', 'OK_JS_INT') + str(i[0])
                + "<br>FILE: " +str(i[1]))
                issue.setFile(str(i[1]))
                issue.setSeverity(Severity.INFO)
                results.append(issue)

                issue = terminalPrint()
                issue.setLevel(Severity.INFO)
                issue.setData(common.config.get('qarkhelper', 'OK_JS_INT'))
                results.append(issue)
        else:
            issue = ReportIssue()
            issue.setCategory(ExploitType.WEBVIEW)
            issue.setDetails(common.config.get('qarkhelper', 'NO_JS_INT')
            + "<br>FILE: " +str(i[1]))
            issue.setFile(str(i[1]))
            issue.setSeverity(Severity.INFO)
            results.append(issue)

            issue = terminalPrint()
            issue.setLevel(Severity.INFO)
            issue.setData(common.config.get('qarkhelper', 'NO_JS_INT') + str(i[0]))
            results.append(issue)

    #Check if WebView has DOMStorage enabled
        wv_setdom=re.escape(sl+'.setDomStorageEnabled(true)')
        if wv_config(i[1],wv_setdom):
            issue = ReportIssue()
            issue.setCategory(ExploitType.WEBVIEW)
            issue.setDetails(common.config.get('qarkhelper', 'DOM_STORAGE_EN') + str(i[0])
            + "<br>FILE: " +str(i[1]))
            issue.setFile(str(i[1]))
            issue.setSeverity(Severity.INFO)
            issue.setExtras(IS_DOM_STORAGE_ENABLED, True)
            results.append(issue)

            issue = terminalPrint()
            issue.setLevel(Severity.INFO)
            issue.setData(common.config.get('qarkhelper', 'DOM_STORAGE_EN'))
            results.append(issue)
        else:
            issue = ReportIssue()
            issue.setCategory(ExploitType.WEBVIEW)
            issue.setDetails(common.config.get('qarkhelper', 'DOM_STORAGE_DIS')
            + "<br>FILE: " +str(i[1]))
            issue.setFile(str(i[1]))
            issue.setSeverity(Severity.INFO)
            issue.setExtras(IS_DOM_STORAGE_ENABLED, False)
            results.append(issue)

            issue = terminalPrint()
            issue.setLevel(Severity.INFO)
            issue.setData(common.config.get('qarkhelper', 'DOM_STORAGE_DIS') + str(i[0]))
            results.append(issue)

    return
Example #3
0
def parseArgs(arg, results):
    """
	Checking to see whether the setClass method is called on the arguments of a pending intent, if it is a new instance of an Intent
	"""
    if type(arg) is m.MethodInvocation:
        if type(arg.target) is m.InstanceCreation:
            #If the intent only has one argument, it must be implicit
            if len(arg.target.arguments) > 1:
                if type(arg.target.arguments[1]) is m.Name:
                    #At this point, I need to go through the tree and see if this arg is a class, making this explicit and safe
                    #If the argument is not a name, what is it?
                    if hasattr(arg.target.arguments[1], 'value'):
                        try:
                            if findClass(arg.target.arguments[1].value,
                                         results):
                                return
                            else:
                                report.write("parsingerror-issues-list",
                                             str(current_file), "strong")
                                common.logger.debug(
                                    "ERROR: CAN'T FIND THE CLASS in parseArgs")
                        except Exception as e:
                            report.write("parsingerror-issues-list",
                                         str(current_file), "strong")
                            common.logger.debug(
                                "Problem in findClass function of findPending.py: "
                                + str(e))
                else:
                    report.write("parsingerror-issues-list", str(current_file),
                                 "strong")
                    common.logger.debug("ERROR: UNEXPECTED Type " +
                                        str(type(arg.target.arguments[1])))
            else:
                #TODO - need to add details here
                issue = ReportIssue()
                issue.setCategory(ExploitType.INTENT)
                issue.setDetails(
                    "PendingIntent created with implicit intent. File: " +
                    str(current_file))
                issue.setFile(current_file)
                issue.setSeverity(Severity.VULNERABILITY)
                results.append(issue)

                issue = terminalPrint()
                issue.setLevel(Severity.VULNERABILITY)
                issue.setData(
                    "PendingIntent created with implicit intent. File: " +
                    str(current_file))
                results.append(issue)
        else:
            #TODO - Remove this (never seems to be hit)
            report.write("parsingerror-issues-list", str(current_file),
                         "strong")
            common.logger.debug(
                "Please report the following error, if you see this")
            common.logger.debug(
                "ERROR: INCOMPLETE CODE BRANCH REACHED findPending.py #4 - Press any key to continue (results may be incomplete)"
            )
    elif type(arg) is m.Name:
        if hasattr(arg, 'value'):
            try:
                findIntent(arg.value, results)
            except Exception as e:
                report.write("parsingerror-issues-list", str(current_file),
                             "strong")
                common.logger.debug(
                    "Problem in findIntent function of findPending.py: " +
                    str(e))
    else:
        #TODO - Remove this (never seems to be hit)
        report.write("parsingerror-issues-list", str(current_file), "strong")
        common.logger.debug(
            "Please report the following error, if you see this")
        common.logger.debug(
            "ERROR: INCOMPLETE CODE BRANCH REACHED findPending.py #5 - Press any key to continue (results may be incomplete)"
        )
    return
Example #4
0
def find_key_files(results):
	'''	PackagedPrivateKey
	------------------
	Summary: Packaged private key

	Priority: 8 / 10
	Severity: Fatal
	Category: Security

	In general, you should not package private key files inside your app.
	'''
	if len(common.keyFiles)>0:
		possibleKeyFiles=common.text_scan(common.keyFiles,r'PRIVATE\sKEY')
		if len(possibleKeyFiles)>0:
			for f in possibleKeyFiles:
				common.logger.debug("It appears there is a private key embedded in your application: " + str(f))
				issue = ReportIssue()
				issue.setCategory(ExploitType.CRYPTO)
				issue.setDetails("It appears there is a private key embedded in your application in the following file:")
				issue.setFile(str(f))
				issue.setSeverity(Severity.VULNERABILITY)
				results.append(issue)

				issue = terminalPrint()
				issue.setLevel(Severity.VULNERABILITY)
				issue.setData("It appears there is a private key embedded in your application in the following file:")
				results.append(issue)
	return
Example #5
0
def start(queue, height):
    results = []
    count = 0
    # TODO - add check for getSharedPreferences specifically, to run before these more generalized ones
    # Check for world readable files
    file_wr = r"MODE_WORLD_READABLE"
    for i in text_scan(common.java_files, file_wr):
        if len(i) > 0:
            report.write(
                IssueType.FileSystem,
                IssueSeverity.High,
                common.config.get("qarkhelper", "WR_FILE") + str(i[0]) + "<br>" + str(i[1]),
            )
            issue = ReportIssue()
            issue.setCategory(ExploitType.PERMISSION)
            issue.setDetails(common.config.get("qarkhelper", "WR_FILE") + str(i[0]) + str(i[1]))
            issue.setFile(str(i[1]))
            issue.setSeverity(Severity.WARNING)
            results.append(issue)

            issue = terminalPrint()
            issue.setLevel(Severity.WARNING)
            issue.setData(common.config.get("qarkhelper", "WR_FILE") + str(i[0]) + str(i[1]))
            results.append(issue)
            # Check for world writable files

    file_ww = r"MODE_WORLD_WRITEABLE"
    for i in text_scan(common.java_files, file_ww):
        if len(i) > 0:
            report.write(
                IssueType.FileSystem,
                IssueSeverity.High,
                common.config.get("qarkhelper", "WW_FILE") + str(i[0]) + "<br>" + str(i[1]),
            )
            issue = ReportIssue()
            issue.setCategory(ExploitType.PERMISSION)
            issue.setDetails(common.config.get("qarkhelper", "WW_FILE") + str(i[0]) + " in file: " + str(i[1]))
            issue.setFile(str(i[1]))
            issue.setSeverity(Severity.WARNING)
            results.append(issue)

            issue = terminalPrint()
            issue.setLevel(Severity.WARNING)
            issue.setData(common.config.get("qarkhelper", "WW_FILE") + str(i[0]) + " in file: " + str(i[1]))
            results.append(issue)
    queue.put(results)
    """
	More checks from Android Lint to implement

	WorldReadableFiles
	------------------
	Summary: openFileOutput() call passing MODE_WORLD_READABLE

	Priority: 4 / 10
	Severity: Warning
	Category: Security

	There are cases where it is appropriate for an application to write world
	readable files, but these should be reviewed carefully to ensure that they
	contain no private data that is leaked to other applications.


	WorldWriteableFiles
	-------------------
	Summary: openFileOutput() call passing MODE_WORLD_WRITEABLE

	Priority: 4 / 10
	Severity: Warning
	Category: Security

	There are cases where it is appropriate for an application to write world
	writeable files, but these should be reviewed carefully to ensure that they
	contain no private data, and that if the file is modified by a malicious
	application it does not trick or compromise your application.
	"""
    return
def unverified_sessions(results):
    global sslSessions
    #This is untested because I could not find a vulnerable app, which didn't have a custom .verify method
    for s in sslSessions:
        issue = ReportIssue()
        issue.setCategory(ExploitType.CERTIFICATE)
        issue.setDetails("Potential Man-In-The-Middle vulnerability - There appear to be SSLSession (boolean) objects which are not checked using the HostnameVerifier.verify method. You should manually inspect these in: " + str(filename) + ". Please see this URL for details: https://developer.android.com/training/articles/security-ssl.html")
        issue.setSeverity(Severity.WARNING)
        results.append(issue)

        issue = terminalPrint()
        issue.setLevel(Severity.WARNING)
        issue.setData("Potential Man-In-The-Middle vulnerability - There appear to be SSLSession (boolean) objects which are not checked using the HostnameVerifier.verify method. You should manually inspect these in: " + str(filename) + ". Please see this URL for details: https://developer.android.com/training/articles/security-ssl.html")
        results.append(issue)
    sslSessions=[]
    return
Example #7
0
def recursive_ecb_check(t, filename, results):
    #TODO - review this for thoroughness
    #TODO - need to verify .getInstance is actually being invoked on a Cipher object
    #TODO - we could whittle down the possibilities by checking the imports as well
    if type(t) is m.MethodInvocation:
        if hasattr(t, 'name'):
            if str(t.name) == 'getInstance':
                if hasattr(t, 'arguments'):
                    for a in t.arguments:
                        if type(a) is m.Literal:
                            #sets mode to ECB
                            if re.search(r'.*\/ECB\/.*', str(a.value)):

                                issue = ReportIssue()
                                issue.setCategory(ExploitType.CRYPTO)
                                issue.setDetails(
                                    "getInstance should not be called with ECB as the cipher mode, as it is insecure. "
                                )
                                issue.setFile(str(filename))
                                issue.setSeverity(Severity.VULNERABILITY)
                                results.append(issue)

                                issue = terminalPrint()
                                issue.setLevel(Severity.VULNERABILITY)
                                issue.setData(
                                    "getInstance should not be called with ECB as the cipher mode, as it is insecure. "
                                )
                                results.append(issue)

                            #sets mode to something other than ECB
                            elif re.search(r'.*/.*/.*', str(a.value)):
                                return
                            #No mode set
                            elif str(a.value) == '':
                                issue = ReportIssue()
                                issue.setCategory(ExploitType.CRYPTO)
                                issue.setDetails(
                                    "getInstance should not be called without setting the cipher mode because the default mode on android is ECB, which is insecure. "
                                )
                                issue.setFile(str(filename))
                                issue.setSeverity(Severity.VULNERABILITY)
                                results.append(issue)

                                issue = terminalPrint()
                                issue.setLevel(Severity.VULNERABILITY)
                                issue.setData(
                                    "getInstance should not be called without setting the cipher mode because the default mode on android is ECB, which is insecure. "
                                )
                                results.append(issue)

    if type(t) is list:
        for l in t:
            recursive_ecb_check(l, filename, results)
    elif hasattr(t, '_fields'):
        for f in t._fields:
            recursive_ecb_check(getattr(t, f), filename, results)
    '''		GetInstance
	-----------
	Summary: Cipher.getInstance with ECB

	Priority: 9 / 10
	Severity: Warning
	Category: Security

	Cipher#getInstance should not be called with ECB as the cipher mode or without
	setting the cipher mode because the default mode on android is ECB, which is
	insecure.'''

    return
Example #8
0
def recursive_allow_all_hostname_verifier(t, filename, results):
    #TODO - This can be fleshed out to be more of an accurate, exhaustive check, but will suffice for now
    if type(t) is m.Assignment:
        if type(t.rhs) is m.InstanceCreation:
            if hasattr(t.rhs, 'type'):
                if hasattr(t.rhs.type, 'name'):
                    if hasattr(t.rhs.type.name, 'value'):
                        if str(t.rhs.type.name.value
                               ) == 'AllowAllHostnameVerifier':
                            #TODO - The list below will eventually be used to check the code for bad verifiers, but will wait for now, due to time constraints
                            if hasattr(t.lhs, 'value'):
                                issue = ReportIssue()
                                issue.setCategory(ExploitType.CERTIFICATE)
                                issue.setDetails(
                                    "AllowAllHostnameVerifier: " +
                                    str(t.lhs.value) + " found in " +
                                    str(filename) +
                                    ". This can allow for impromper x.509 certificate validation wherein the DNS hostname does not match the Common or Subject Alternative Name(s) on the certificate, making the application vulnerable to Man-In-The-Middle attacks. This means the application may potentially accept a certificate from any trusted CA, regardless of the domain it was issued for. The can be validated using the free version of Burpsuite by installing the Portswigger CA certificate, thereby making it a trusted CA on the device. Set the device network settings to use the Burpsuite proxy, then go Proxy > Options > Edit the Proxy Listener by changing the Certificate tab to Generate a CA-signed certificate with a specific hostname and enter a domain like foobar.com which doesn't match the domain name(s) the app is connecting to normally. You should always verify your results by visiting an https site in the native browser and confirming you see a certificate warning. For details, please see: https://developer.android.com/training/articles/security-ssl.html"
                                )
                                issue.setFile(filename)
                                issue.setSeverity(Severity.WARNING)
                                results.append(issue)

                                issue = terminalPrint()
                                issue.setLevel(Severity.WARNING)
                                issue.setData(
                                    "AllowAllHostnameVerifier: " +
                                    str(t.lhs.value) + " found in " +
                                    str(filename) +
                                    ". This can allow for impromper x.509 certificate validation wherein the DNS hostname does not match the Common or Subject Alternative Name(s) on the certificate, making the application vulnerable to Man-In-The-Middle attacks. This means the application may potentially accept a certificate from any trusted CA, regardless of the domain it was issued for. The can be validated using the free version of Burpsuite by installing the Portswigger CA certificate, thereby making it a trusted CA on the device. Set the device network settings to use the Burpsuite proxy, then go Proxy > Options > Edit the Proxy Listener by changing the Certificate tab to Generate a CA-signed certificate with a specific hostname and enter a domain like foobar.com which doesn't match the domain name(s) the app is connecting to normally. You should always verify your results by visiting an https site in the native browser and confirming you see a certificate warning. For details, please see: https://developer.android.com/training/articles/security-ssl.html"
                                )
                                results.append(issue)

    elif type(t) is m.MethodInvocation:
        if hasattr(t, 'name'):
            if str(t.name) == 'setHostnameVerifier':
                if hasattr(t, 'arguments'):
                    for a in t.arguments:
                        if type(a) is m.Name:
                            if hasattr(a, 'value'):
                                if re.search(r'\.ALLOW_ALL_HOSTNAME_VERIFIER$',
                                             str(a.value)):
                                    issue = ReportIssue()
                                    issue.setCategory(ExploitType.CERTIFICATE)
                                    issue.setDetails(
                                        "ALLOW_ALL_HOSTNAME_VERIFIER invoked : "
                                        + str(a.value) + " in " +
                                        str(filename) +
                                        ". This can allow for impromper x.509 certificate validation wherein the DNS hostname does not match the Common or Subject Alternative Name(s) on the certificate, making the application vulnerable to Man-In-The-Middle attacks. This means the application may potentially accept a certificate from any trusted CA, regardless of the domain it was issued for. The can be validated using the free version of Burpsuite by installing the Portswigger CA certificate, thereby making it a trusted CA on the device. Set the device network settings to use the Burpsuite proxy, then go Proxy > Options > Edit the Proxy Listener by changing the Certificate tab to Generate a CA-signed certificate with a specific hostname and enter a domain like foobar.com which doesn't match the domain name(s) the app is connecting to normally. You should always verify your results by visiting an https site in the native browser and confirming you see a certificate warning. For details, please see: https://developer.android.com/training/articles/security-ssl.html"
                                    )
                                    issue.setFile(filename)
                                    issue.setSeverity(Severity.WARNING)
                                    results.append(issue)

                                    issue = terminalPrint()
                                    issue.setLevel(Severity.WARNING)
                                    issue.setData(
                                        "ALLOW_ALL_HOSTNAME_VERIFIER invoked : "
                                        + str(a.value) + " in " +
                                        str(filename) +
                                        ". This can allow for impromper x.509 certificate validation wherein the DNS hostname does not match the Common or Subject Alternative Name(s) on the certificate, making the application vulnerable to Man-In-The-Middle attacks. This means the application may potentially accept a certificate from any trusted CA, regardless of the domain it was issued for. The can be validated using the free version of Burpsuite by installing the Portswigger CA certificate, thereby making it a trusted CA on the device. Set the device network settings to use the Burpsuite proxy, then go Proxy > Options > Edit the Proxy Listener by changing the Certificate tab to Generate a CA-signed certificate with a specific hostname and enter a domain like foobar.com which doesn't match the domain name(s) the app is connecting to normally. You should always verify your results by visiting an https site in the native browser and confirming you see a certificate warning. For details, please see: https://developer.android.com/training/articles/security-ssl.html"
                                    )
                                    results.append(issue)
    elif type(t) is list:
        for x in t:
            recursive_allow_all_hostname_verifier(x, filename, results)
    elif hasattr(t, '_fields'):
        for f in t._fields:
            recursive_allow_all_hostname_verifier(getattr(t, f), filename,
                                                  results)
    return
Example #9
0
def recursive_find_verify(q, filename, results):
    '''
    Find all .verify methods 
    '''
    global sslSessions
    global tree
    global verifyIteration
    global warningGiven

    if len(sslSessions) > 0:
        if verifyIteration == 0:
            try:
                for type_decl in tree.type_declarations:
                    if type(type_decl) is m.ClassDeclaration:
                        for t in type_decl.body:
                            if type(t) is m.MethodInvocation:
                                if hasattr(t, 'name'):
                                    if str(t.name) == 'verify':
                                        if hasattr(t, 'arguments'):
                                            if len(t.arguments) != 2:
                                                if not warningGiven:
                                                    issue = ReportIssue()
                                                    issue.setCategory(
                                                        ExploitType.CERTIFICATE
                                                    )
                                                    issue.setDetails(
                                                        "Custom verify method used in "
                                                        + str(filename) +
                                                        ". You should manually review certificate validation here."
                                                    )
                                                    issue.setFile(filename)
                                                    issue.setSeverity(
                                                        Severity.WARNING)
                                                    results.append(issue)

                                                    issue = terminalPrint()
                                                    issue.setLevel(
                                                        Severity.WARNING)
                                                    issue.setData(
                                                        "Custom verify method used in "
                                                        + str(filename) +
                                                        ". You should manually review certificate validation here."
                                                    )
                                                    results.append(issue)
                                                    warningGiven = True
                                            else:
                                                for r in q.arguments:
                                                    continue
                            elif type(t) is m.MethodDeclaration:
                                if hasattr(t, 'name'):
                                    if str(t.name) == 'verify':
                                        if not warningGiven:
                                            issue = ReportIssue()
                                            issue.setCategory(
                                                ExploitType.CERTIFICATE)
                                            issue.setDetails(
                                                "Custom verify method declared in "
                                                + str(filename) +
                                                ". You should manually review certificate validation here."
                                            )
                                            issue.setFile(filename)
                                            issue.setSeverity(Severity.WARNING)
                                            results.append(issue)

                                            issue = terminalPrint()
                                            issue.setLevel(Severity.WARNING)
                                            issue.setData(
                                                "Custom verify method declared in "
                                                + str(filename) +
                                                ". You should manually review certificate validation here."
                                            )
                                            results.append(issue)
                                            warningGiven = True
                            elif type(t) is list:
                                for l in t:
                                    if type(l) is not None:
                                        verifyIteration = 1
                                        recursive_find_verify(
                                            l, filename, results)
                            elif hasattr(t, '_fields'):
                                for f in t._fields:
                                    if type(getattr(t, f)) is not None:
                                        verifyIteration = 1
                                        recursive_find_verify(
                                            getattr(t, f), filename, results)
                                    elif type(t) is list:
                                        for l in t:
                                            if type(l) is not None:
                                                verifyIteration = 1
                                                recursive_find_verify(
                                                    l, filename, results)
                                    elif hasattr(t, '_fields'):
                                        for f in t._fields:
                                            if type(getattr(t, f)) is not None:
                                                verifyIteration = 1
                                                recursive_find_verify(
                                                    getattr(t, f), filename,
                                                    results)
            except Exception as e:
                common.logger.debug(
                    "Something went wrong in certValidation.py's findVerify: "
                    + str(e))
                report.write(
                    "parsingerror-issues-list",
                    "Something went wrong in certValidation.py's findVerify: "
                    + str(e), "strong")
        else:
            if type(q) is m.MethodInvocation:
                if hasattr(q, 'name'):
                    if str(q.name) == 'verify':
                        if hasattr(q, 'arguments'):
                            if len(q.arguments) != 2:
                                if not warningGiven:
                                    issue = ReportIssue()
                                    issue.setCategory(ExploitType.CERTIFICATE)
                                    issue.setDetails(
                                        "Custom verify method used in " +
                                        str(filename) +
                                        ". You should manually review certificate validation here."
                                    )
                                    issue.setFile(filename)
                                    issue.setSeverity(Severity.WARNING)
                                    results.append(issue)

                                    issue = terminalPrint()
                                    issue.setLevel(Severity.WARNING)
                                    issue.setData(
                                        "Custom verify method used in " +
                                        str(filename) +
                                        ". You should manually review certificate validation here."
                                    )
                                    results.append(issue)
                                    warningGiven = True
                            else:
                                common.logger.debug("sslSessions Before: " +
                                                    str(sslSessions))
                                if str(q.arguments[1]) in sslSessions:
                                    sslSessions.remove(str(q.arguments[1]))
                                    common.logger.debug("sslSessions After: " +
                                                        str(sslSessions))

                            #For each verify method, check whether the session being verified is in sslSessions and if so, remove it(considering it verified)
                            #This is not full proof at all, for several reasons, but we know it's definitely vulnerable if it's never verified, assuming no strange code
                            #TODO - check that the .verify actually belongs to a HostnameVerifier
                            #TODO - verify that .verify is not over ridden somewhere
            elif type(q) is m.MethodDeclaration:
                if hasattr(q, 'name'):
                    if str(q.name) == 'verify':
                        if not warningGiven:
                            issue = ReportIssue()
                            issue.setCategory(ExploitType.CERTIFICATE)
                            issue.setDetails(
                                "Custom verify method declared in " +
                                str(filename) +
                                ". You should manually review certificate validation here."
                            )
                            issue.setFile(filename)
                            issue.setSeverity(Severity.WARNING)
                            results.append(issue)

                            issue = terminalPrint()
                            issue.setLevel(Severity.WARNING)
                            issue.setData(
                                "Custom verify method declared in " +
                                str(filename) +
                                ". You should manually review certificate validation here."
                            )
                            results.append(issue)
                            warningGiven = True
            elif type(q) is list:
                for l in q:
                    if type(l) is not None:
                        recursive_find_verify(l, filename, results)
            elif hasattr(q, '_fields'):
                for f in q._fields:
                    if type(getattr(q, f)) is not None:
                        recursive_find_verify(getattr(q, f), filename, results)
                    elif type(q) is list:
                        for l in q:
                            if type(l) is not None:
                                recursive_find_verify(l, filename, results)
                    elif hasattr(q, '_fields'):
                        for f in q._fields:
                            if type(getattr(q, f)) is not None:
                                recursive_find_verify(getattr(q, f), filename,
                                                      results)
        verifyIteration = 1
        unverified_sessions(results)
    return
Example #10
0
def start(queue, height):
    results = []
    count = 0
    #TODO - add check for getSharedPreferences specifically, to run before these more generalized ones
    #Check for world readable files
    file_wr = r'MODE_WORLD_READABLE'
    for i in text_scan(common.java_files, file_wr):
        if len(i) > 0:
            report.write(
                IssueType.FileSystem, IssueSeverity.High,
                common.config.get('qarkhelper', 'WR_FILE') + str(i[0]) +
                "<br>" + str(i[1]))
            issue = ReportIssue()
            issue.setCategory(ExploitType.PERMISSION)
            issue.setDetails(
                common.config.get('qarkhelper', 'WR_FILE') + str(i[0]) +
                str(i[1]))
            issue.setFile(str(i[1]))
            issue.setSeverity(Severity.WARNING)
            results.append(issue)

            issue = terminalPrint()
            issue.setLevel(Severity.WARNING)
            issue.setData(
                common.config.get('qarkhelper', 'WR_FILE') + str(i[0]) +
                str(i[1]))
            results.append(issue)
    #Check for world writable files

    file_ww = r'MODE_WORLD_WRITEABLE'
    for i in text_scan(common.java_files, file_ww):
        if len(i) > 0:
            report.write(
                IssueType.FileSystem, IssueSeverity.High,
                common.config.get('qarkhelper', 'WW_FILE') + str(i[0]) +
                "<br>" + str(i[1]))
            issue = ReportIssue()
            issue.setCategory(ExploitType.PERMISSION)
            issue.setDetails(
                common.config.get('qarkhelper', 'WW_FILE') + str(i[0]) +
                " in file: " + str(i[1]))
            issue.setFile(str(i[1]))
            issue.setSeverity(Severity.WARNING)
            results.append(issue)

            issue = terminalPrint()
            issue.setLevel(Severity.WARNING)
            issue.setData(
                common.config.get('qarkhelper', 'WW_FILE') + str(i[0]) +
                " in file: " + str(i[1]))
            results.append(issue)
    queue.put(results)
    '''
	More checks from Android Lint to implement

	WorldReadableFiles
	------------------
	Summary: openFileOutput() call passing MODE_WORLD_READABLE

	Priority: 4 / 10
	Severity: Warning
	Category: Security

	There are cases where it is appropriate for an application to write world
	readable files, but these should be reviewed carefully to ensure that they
	contain no private data that is leaked to other applications.


	WorldWriteableFiles
	-------------------
	Summary: openFileOutput() call passing MODE_WORLD_WRITEABLE

	Priority: 4 / 10
	Severity: Warning
	Category: Security

	There are cases where it is appropriate for an application to write world
	writeable files, but these should be reviewed carefully to ensure that they
	contain no private data, and that if the file is modified by a malicious
	application it does not trick or compromise your application.
	'''
    return
Example #11
0
def recursive_insecure_trust_manager(t, filename, results):
    if type(t) is m.MethodDeclaration:
        if str(t.name) == 'checkServerTrusted':
            if len(t.body) == 0:
                issue = ReportIssue()
                issue.setCategory(ExploitType.CERTIFICATE)
                issue.setDetails(
                    "Instance of checkServerTrusted, with no body found in: " +
                    str(filename) +
                    ". This means this application is likely vulnerable to Man-In-The-Middle attacks. This can be confirmed using the free version of Burpsuite. Simply set the Android device's proxy to use Burpsuite via the network settings, but DO NOT install the Portswigger CA certificate on the device. If you still see traffic in the proxy, the app is vulnerable. Note: You need to ensure you exercise this code path. If you are unsure, make sure you click through each part of the application which makes network requests. You may need to toggle the proxy on/off to get past sections that do validate certificates properly in order to reach the vulnerable code. This proves that it will accept certificates from any CA. You should always validate your configuration by visiting an HTTPS site in the native browser and verifying you receive a certificate warning. For details, please see: https://developer.android.com/training/articles/security-ssl.html"
                )
                issue.setFile(filename)
                issue.setSeverity(Severity.WARNING)
                results.append(issue)

                issue = terminalPrint()
                issue.setLevel(Severity.WARNING)
                issue.setData(
                    "Instance of checkServerTrusted, with no body found in: " +
                    str(filename) +
                    ". This means this application is likely vulnerable to Man-In-The-Middle attacks. This can be confirmed using the free version of Burpsuite. Simply set the Android device's proxy to use Burpsuite via the network settings, but DO NOT install the Portswigger CA certificate on the device. If you still see traffic in the proxy, the app is vulnerable. Note: You need to ensure you exercise this code path. If you are unsure, make sure you click through each part of the application which makes network requests. You may need to toggle the proxy on/off to get past sections that do validate certificates properly in order to reach the vulnerable code. This proves that it will accept certificates from any CA. You should always validate your configuration by visiting an HTTPS site in the native browser and verifying you receive a certificate warning. For details, please see: https://developer.android.com/training/articles/security-ssl.html"
                )
                results.append(issue)
            else:
                for b in t.body:
                    if type(b) is m.Return:
                        #TODO - This needs to be fleshed out more, but it will have to wait due to time constraints
                        issue = terminalPrint()
                        issue.setLevel(Severity.WARNING)
                        issue.setData(
                            "Instance of checkServerTrusted, which only returns "
                            + str(filename) +
                            ". This means this application is likely vulnerable to Man-In-The-Middle attacks. This can be confirmed using the free version of Burpsuite. Simply set the Android device's proxy to use Burpsuite via the network settings, but DO NOT install the Portswigger CA certificate on the device. If you still see traffic in the proxy, the app is vulnerable. Note: You need to ensure you excercise this code path. If you are unsure, make sure you click through each part of the application which makes network requests. You may need to toggle the proxy on/off to get past sections that do validate certificates properly in order to reach the vulnerable code. This proves that it will accept certitificates from any CA. You should always validate your configuration by visiting an HTTPS site in the native browser and verifying you receive a certificate warning. For details, please see: https://developer.android.com/training/articles/security-ssl.html"
                        )
                        results.append(issue)

                        issue = ReportIssue()
                        issue.setCategory(ExploitType.CERTIFICATE)
                        issue.setDetails(
                            "Instance of checkServerTrusted, which only returns "
                            + str(filename) +
                            ". This means this application is likely vulnerable to Man-In-The-Middle attacks. This can be confirmed using the free version of Burpsuite. Simply set the Android device's proxy to use Burpsuite via the network settings, but DO NOT install the Portswigger CA certificate on the device. If you still see traffic in the proxy, the app is vulnerable. Note: You need to ensure you excercise this code path. If you are unsure, make sure you click through each part of the application which makes network requests. You may need to toggle the proxy on/off to get past sections that do validate certificates properly in order to reach the vulnerable code. This proves that it will accept certitificates from any CA. You should always validate your configuration by visiting an HTTPS site in the native browser and verifying you receive a certificate warning. For details, please see: https://developer.android.com/training/articles/security-ssl.html"
                        )
                        issue.setFile(filename)
                        issue.setSeverity(Severity.WARNING)
                        results.append(issue)
                    else:
                        break  #TODO - only want to check once, to see if it's only a return, can probably be replaced by len()
    elif type(t) is list:
        for x in t:
            recursive_insecure_trust_manager(x, filename, results)
    elif hasattr(t, '_fields'):
        for f in t._fields:
            recursive_insecure_trust_manager(getattr(t, f), filename, results)
    return
Example #12
0
def findIntent(intent, results):
    """
	Find Intent 
	"""
    # TODO - This section is ugly and needs to be refactored
    # Looking for the intent used in the pending intent
    global tree
    found = False
    explicit = False
    if hasattr(tree, "type_declarations"):
        for type_decl in tree.type_declarations:
            if type(type_decl) is m.ClassDeclaration:
                for t in type_decl.body:
                    if not found:
                        if type(t) is m.VariableDeclaration:
                            if hasattr(t, "type"):
                                if type(t.type) is not str:
                                    report.write("parsingerror-issues-list", str(current_file), "strong")
                                    common.logger.debug("Please report the following error, if you see this")
                                    common.logger.debug(
                                        "ERROR: INCOMPLETE CODE BRANCH REACHED findPending.py #6 - Press any key to continue (results may be incomplete)"
                                    )
                                    if str(t.type) == "Intent":
                                        common.logger.error("FOUND Intent Variable 0: " + str(t))
                                    else:
                                        if hasattr(t.type, "name"):
                                            if hasattr(t.type.name, "value"):
                                                if str(t.type.name.value) == "Intent":
                                                    common.logger.debug("FOUND Intent Variable 1: " + str(t))
                        else:
                            try:
                                temp = intent_digger(t, intent)
                            except Exception as e:
                                common.logger.debug("Error in intent_digger function of findPending.py: " + str(e))
                            found = temp[0]
                            explicit = temp[1]
                            if found:
                                if not explicit:
                                    # See if the intent is explicit
                                    if type(t) is m.MethodInvocation:
                                        if str(t.name) == "setClass":
                                            explicit = True
                                        elif str(t.name) == "setPackage":
                                            explicit = True
                                    elif type(t) is m.MethodDeclaration:
                                        for f in t._fields:
                                            if type(getattr(t, f)) is list:
                                                for x in getattr(t, f):
                                                    if type(x) is m.MethodInvocation:
                                                        if str(x.name) == "setClass":
                                                            explicit = True
                                                        elif str(x.name) == "setPackage":
                                                            explicit = True
                                                    else:
                                                        if hasattr(x, "_fields"):
                                                            for y in x._fields:
                                                                if type(getattr(x, y)) is m.MethodInvocation:
                                                                    if str(getattr(x, y).name) == "setClass":
                                                                        if hasattr(getattr(x, y).target, "value"):
                                                                            if str(getattr(x, y).target.value) == str(
                                                                                intent
                                                                            ):
                                                                                explicit = True
                                                                            elif (
                                                                                str(getattr(x, y).name) == "setPackage"
                                                                            ):
                                                                                if str(
                                                                                    getattr(x, y).target.value
                                                                                ) == str(intent):
                                                                                    explicit = True
                                                                        else:
                                                                            common.logger.debug(
                                                                                "Something went wrong in findPending, when determining if the Intent was explicit"
                                                                            )
                                                        elif type(x) is list:
                                                            common.logger.debug(
                                                                "ERROR: UNEXPECTED CODE PATH in findIntent - 1"
                                                            )
                                            elif type(getattr(t, f)) is m.MethodInvocation:
                                                common.logger.debug("ERROR: UNEXPECTED CODE PATH in findIntent - 2")
                                    else:
                                        for f in t._fields:
                                            if type(getattr(t, f)) is list:
                                                for x in getattr(t, f):
                                                    if type(x) is m.MethodInvocation:
                                                        if str(x.name) == "setClass":
                                                            explicit = True
                                                        elif str(x.name) == "setPackage":
                                                            explicit = True
                                else:
                                    break
    else:
        common.logger.debug("NO TYPE DECLARATIONS")
    if not explicit:
        if found:
            issue = ReportIssue()
            issue.setCategory(ExploitType.INTENT)
            issue.setDetails(
                "Implicit Intent: "
                + str(intent)
                + " used to create instance of PendingIntent. A malicious application could potentially intercept, redirect and/or modify (in a limited manner) this Intent. Pending Intents retain the UID of your application and all related permissions, allowing another application to act as yours.  File: "
                + str(current_file)
                + " More details: https://www.securecoding.cert.org/confluence/display/android/DRD21-J.+Always+pass+explicit+intents+to+a+PendingIntent"
            )
            issue.setFile(current_file)
            issue.setSeverity(Severity.VULNERABILITY)
            results.append(issue)

            issue = terminalPrint()
            issue.setLevel(Severity.VULNERABILITY)
            issue.setData(
                "Implicit Intent: "
                + str(intent)
                + " used to create instance of PendingIntent. A malicious application could potentially intercept, redirect and/or modify (in a limited manner) this Intent. Pending Intents retain the UID of your application and all related permissions, allowing another application to act as yours.  File: "
                + str(current_file)
                + " More details: https://www.securecoding.cert.org/confluence/display/android/DRD21-J.+Always+pass+explicit+intents+to+a+PendingIntent"
            )
            results.append(issue)
        else:
            # TO DO - ensure we can resolve custom intents to avoid this error
            common.logger.debug(
                "ERROR: COULDN'T FIND THE INTENT: "
                + str(intent)
                + " This may either be due to a custom Intent class or other error"
            )
    return
Example #13
0
def parseArgs(arg, results):
    """
	Checking to see whether the setClass method is called on the arguments of a pending intent, if it is a new instance of an Intent
	"""
    if type(arg) is m.MethodInvocation:
        if type(arg.target) is m.InstanceCreation:
            # If the intent only has one argument, it must be implicit
            if len(arg.target.arguments) > 1:
                if type(arg.target.arguments[1]) is m.Name:
                    # At this point, I need to go through the tree and see if this arg is a class, making this explicit and safe
                    # If the argument is not a name, what is it?
                    if hasattr(arg.target.arguments[1], "value"):
                        try:
                            if findClass(arg.target.arguments[1].value, results):
                                return
                            else:
                                report.write("parsingerror-issues-list", str(current_file), "strong")
                                common.logger.debug("ERROR: CAN'T FIND THE CLASS in parseArgs")
                        except Exception as e:
                            report.write("parsingerror-issues-list", str(current_file), "strong")
                            common.logger.debug("Problem in findClass function of findPending.py: " + str(e))
                else:
                    report.write("parsingerror-issues-list", str(current_file), "strong")
                    common.logger.debug("ERROR: UNEXPECTED Type " + str(type(arg.target.arguments[1])))
            else:
                # TODO - need to add details here
                issue = ReportIssue()
                issue.setCategory(ExploitType.INTENT)
                issue.setDetails("PendingIntent created with implicit intent. File: " + str(current_file))
                issue.setFile(current_file)
                issue.setSeverity(Severity.VULNERABILITY)
                results.append(issue)

                issue = terminalPrint()
                issue.setLevel(Severity.VULNERABILITY)
                issue.setData("PendingIntent created with implicit intent. File: " + str(current_file))
                results.append(issue)
        else:
            # TODO - Remove this (never seems to be hit)
            report.write("parsingerror-issues-list", str(current_file), "strong")
            common.logger.debug("Please report the following error, if you see this")
            common.logger.debug(
                "ERROR: INCOMPLETE CODE BRANCH REACHED findPending.py #4 - Press any key to continue (results may be incomplete)"
            )
    elif type(arg) is m.Name:
        if hasattr(arg, "value"):
            try:
                findIntent(arg.value, results)
            except Exception as e:
                report.write("parsingerror-issues-list", str(current_file), "strong")
                common.logger.debug("Problem in findIntent function of findPending.py: " + str(e))
    else:
        # TODO - Remove this (never seems to be hit)
        report.write("parsingerror-issues-list", str(current_file), "strong")
        common.logger.debug("Please report the following error, if you see this")
        common.logger.debug(
            "ERROR: INCOMPLETE CODE BRANCH REACHED findPending.py #5 - Press any key to continue (results may be incomplete)"
        )
    return
Example #14
0
def recursive_ecb_check(t,filename,results):
	#TODO - review this for thoroughness
	#TODO - need to verify .getInstance is actually being invoked on a Cipher object
	#TODO - we could whittle down the possibilities by checking the imports as well
	if type(t) is m.MethodInvocation:
		if hasattr(t,'name'):
			if str(t.name)=='getInstance':
				if hasattr(t,'arguments'):
					for a in t.arguments:
						if type(a) is m.Literal:
							#sets mode to ECB
							if re.search(r'.*\/ECB\/.*',str(a.value)):

								issue = ReportIssue()
								issue.setCategory(ExploitType.CRYPTO)
								issue.setDetails("getInstance should not be called with ECB as the cipher mode, as it is insecure. ")
								issue.setFile(str(filename))
								issue.setSeverity(Severity.VULNERABILITY)
								results.append(issue)

								issue = terminalPrint()
								issue.setLevel(Severity.VULNERABILITY)
								issue.setData("getInstance should not be called with ECB as the cipher mode, as it is insecure. ")
								results.append(issue)

							#sets mode to something other than ECB
							elif re.search(r'.*/.*/.*',str(a.value)):
								return
							#No mode set
							elif str(a.value)=='':
								issue = ReportIssue()
								issue.setCategory(ExploitType.CRYPTO)
								issue.setDetails("getInstance should not be called without setting the cipher mode because the default mode on android is ECB, which is insecure. ")
								issue.setFile(str(filename))
								issue.setSeverity(Severity.VULNERABILITY)
								results.append(issue)

								issue = terminalPrint()
								issue.setLevel(Severity.VULNERABILITY)
								issue.setData("getInstance should not be called without setting the cipher mode because the default mode on android is ECB, which is insecure. ")
								results.append(issue)

	if type(t) is list:
		for l in t:
			recursive_ecb_check(l,filename, results)
	elif hasattr(t,'_fields'):
		for f in t._fields:
			recursive_ecb_check(getattr(t,f),filename,results)


	'''		GetInstance
	-----------
	Summary: Cipher.getInstance with ECB

	Priority: 9 / 10
	Severity: Warning
	Category: Security

	Cipher#getInstance should not be called with ECB as the cipher mode or without
	setting the cipher mode because the default mode on android is ECB, which is
	insecure.'''

	return
def recursive_allow_all_hostname_verifier(t,filename,results):
    #TODO - This can be fleshed out to be more of an accurate, exhaustive check, but will suffice for now
    if type(t) is m.Assignment:
        if type(t.rhs) is m.InstanceCreation:
            if hasattr(t.rhs,'type'):
                if hasattr(t.rhs.type,'name'):
                    if hasattr(t.rhs.type.name,'value'):
                        if str(t.rhs.type.name.value)=='AllowAllHostnameVerifier':
                            #TODO - The list below will eventually be used to check the code for bad verifiers, but will wait for now, due to time constraints
                            if hasattr(t.lhs,'value'):
                                issue = ReportIssue()
                                issue.setCategory(ExploitType.CERTIFICATE)
                                issue.setDetails("AllowAllHostnameVerifier: " + str(t.lhs.value) + " found in " + str(filename) + ". This can allow for impromper x.509 certificate validation wherein the DNS hostname does not match the Common or Subject Alternative Name(s) on the certificate, making the application vulnerable to Man-In-The-Middle attacks. This means the application may potentially accept a certificate from any trusted CA, regardless of the domain it was issued for. The can be validated using the free version of Burpsuite by installing the Portswigger CA certificate, thereby making it a trusted CA on the device. Set the device network settings to use the Burpsuite proxy, then go Proxy > Options > Edit the Proxy Listener by changing the Certificate tab to Generate a CA-signed certificate with a specific hostname and enter a domain like foobar.com which doesn't match the domain name(s) the app is connecting to normally. You should always verify your results by visiting an https site in the native browser and confirming you see a certificate warning. For details, please see: https://developer.android.com/training/articles/security-ssl.html")
                                issue.setFile(filename)
                                issue.setSeverity(Severity.WARNING)
                                results.append(issue)

                                issue = terminalPrint()
                                issue.setLevel(Severity.WARNING)
                                issue.setData("AllowAllHostnameVerifier: " + str(t.lhs.value) + " found in " + str(filename) + ". This can allow for impromper x.509 certificate validation wherein the DNS hostname does not match the Common or Subject Alternative Name(s) on the certificate, making the application vulnerable to Man-In-The-Middle attacks. This means the application may potentially accept a certificate from any trusted CA, regardless of the domain it was issued for. The can be validated using the free version of Burpsuite by installing the Portswigger CA certificate, thereby making it a trusted CA on the device. Set the device network settings to use the Burpsuite proxy, then go Proxy > Options > Edit the Proxy Listener by changing the Certificate tab to Generate a CA-signed certificate with a specific hostname and enter a domain like foobar.com which doesn't match the domain name(s) the app is connecting to normally. You should always verify your results by visiting an https site in the native browser and confirming you see a certificate warning. For details, please see: https://developer.android.com/training/articles/security-ssl.html")
                                results.append(issue)

    elif type(t) is m.MethodInvocation:
        if hasattr(t,'name'):
            if str(t.name) == 'setHostnameVerifier':
                if hasattr(t,'arguments'):
                    for a in t.arguments:
                        if type(a) is m.Name:
                            if hasattr(a,'value'):
                                if re.search(r'\.ALLOW_ALL_HOSTNAME_VERIFIER$',str(a.value)):
                                    issue = ReportIssue()
                                    issue.setCategory(ExploitType.CERTIFICATE)
                                    issue.setDetails("ALLOW_ALL_HOSTNAME_VERIFIER invoked : " + str(a.value) + " in " + str(filename) + ". This can allow for impromper x.509 certificate validation wherein the DNS hostname does not match the Common or Subject Alternative Name(s) on the certificate, making the application vulnerable to Man-In-The-Middle attacks. This means the application may potentially accept a certificate from any trusted CA, regardless of the domain it was issued for. The can be validated using the free version of Burpsuite by installing the Portswigger CA certificate, thereby making it a trusted CA on the device. Set the device network settings to use the Burpsuite proxy, then go Proxy > Options > Edit the Proxy Listener by changing the Certificate tab to Generate a CA-signed certificate with a specific hostname and enter a domain like foobar.com which doesn't match the domain name(s) the app is connecting to normally. You should always verify your results by visiting an https site in the native browser and confirming you see a certificate warning. For details, please see: https://developer.android.com/training/articles/security-ssl.html")
                                    issue.setFile(filename)
                                    issue.setSeverity(Severity.WARNING)
                                    results.append(issue)

                                    issue = terminalPrint()
                                    issue.setLevel(Severity.WARNING)
                                    issue.setData("ALLOW_ALL_HOSTNAME_VERIFIER invoked : " + str(a.value) + " in " + str(filename) + ". This can allow for impromper x.509 certificate validation wherein the DNS hostname does not match the Common or Subject Alternative Name(s) on the certificate, making the application vulnerable to Man-In-The-Middle attacks. This means the application may potentially accept a certificate from any trusted CA, regardless of the domain it was issued for. The can be validated using the free version of Burpsuite by installing the Portswigger CA certificate, thereby making it a trusted CA on the device. Set the device network settings to use the Burpsuite proxy, then go Proxy > Options > Edit the Proxy Listener by changing the Certificate tab to Generate a CA-signed certificate with a specific hostname and enter a domain like foobar.com which doesn't match the domain name(s) the app is connecting to normally. You should always verify your results by visiting an https site in the native browser and confirming you see a certificate warning. For details, please see: https://developer.android.com/training/articles/security-ssl.html")
                                    results.append(issue)
    elif type(t) is list:
        for x in t:
            recursive_allow_all_hostname_verifier(x,filename,results)
    elif hasattr(t,'_fields'):
        for f in t._fields:
            recursive_allow_all_hostname_verifier(getattr(t,f),filename,results)
    return
Example #16
0
def unverified_sessions(results):
    global sslSessions
    #This is untested because I could not find a vulnerable app, which didn't have a custom .verify method
    for s in sslSessions:
        issue = ReportIssue()
        issue.setCategory(ExploitType.CERTIFICATE)
        issue.setDetails(
            "Potential Man-In-The-Middle vulnerability - There appear to be SSLSession (boolean) objects which are not checked using the HostnameVerifier.verify method. You should manually inspect these in: "
            + str(filename) +
            ". Please see this URL for details: https://developer.android.com/training/articles/security-ssl.html"
        )
        issue.setSeverity(Severity.WARNING)
        results.append(issue)

        issue = terminalPrint()
        issue.setLevel(Severity.WARNING)
        issue.setData(
            "Potential Man-In-The-Middle vulnerability - There appear to be SSLSession (boolean) objects which are not checked using the HostnameVerifier.verify method. You should manually inspect these in: "
            + str(filename) +
            ". Please see this URL for details: https://developer.android.com/training/articles/security-ssl.html"
        )
        results.append(issue)
    sslSessions = []
    return
def recursive_find_verify(q,filename,results):
    '''
    Find all .verify methods 
    '''
    global sslSessions
    global tree
    global verifyIteration
    global warningGiven

    if len(sslSessions)>0:
        if verifyIteration==0:
            try:
                for type_decl in tree.type_declarations:
                    if type(type_decl) is m.ClassDeclaration:
                        for t in type_decl.body:
                            if type(t) is m.MethodInvocation:
                                if hasattr(t,'name'):
                                    if str(t.name)=='verify':
                                        if hasattr(t,'arguments'):
                                            if len(t.arguments)!=2:
                                                if not warningGiven:
                                                    issue = ReportIssue()
                                                    issue.setCategory(ExploitType.CERTIFICATE)
                                                    issue.setDetails("Custom verify method used in " + str(filename) + ". You should manually review certificate validation here." )
                                                    issue.setFile(filename)
                                                    issue.setSeverity(Severity.WARNING)
                                                    results.append(issue)

                                                    issue = terminalPrint()
                                                    issue.setLevel(Severity.WARNING)
                                                    issue.setData("Custom verify method used in " + str(filename) + ". You should manually review certificate validation here." )
                                                    results.append(issue)
                                                    warningGiven=True
                                            else:
                                                for r in q.arguments:
                                                    continue
                            elif type(t) is m.MethodDeclaration:
                                if hasattr(t,'name'):
                                    if str(t.name)=='verify':
                                        if not warningGiven:
                                            issue = ReportIssue()
                                            issue.setCategory(ExploitType.CERTIFICATE)
                                            issue.setDetails("Custom verify method declared in " + str(filename) + ". You should manually review certificate validation here." )
                                            issue.setFile(filename)
                                            issue.setSeverity(Severity.WARNING)
                                            results.append(issue)

                                            issue = terminalPrint()
                                            issue.setLevel(Severity.WARNING)
                                            issue.setData("Custom verify method declared in " + str(filename) + ". You should manually review certificate validation here." )
                                            results.append(issue)
                                            warningGiven=True
                            elif type(t) is list:
                                for l in t:
                                    if type(l) is not None:
                                        verifyIteration=1
                                        recursive_find_verify(l,filename,results)
                            elif hasattr(t,'_fields'):
                                for f in t._fields:
                                    if type(getattr(t,f)) is not None:
                                        verifyIteration=1
                                        recursive_find_verify(getattr(t,f),filename,results)
                                    elif type(t) is list:
                                        for l in t:
                                            if type(l) is not None:
                                                verifyIteration=1
                                                recursive_find_verify(l,filename,results)
                                    elif hasattr(t,'_fields'):
                                        for f in t._fields:
                                            if type(getattr(t,f)) is not None:
                                                verifyIteration=1
                                                recursive_find_verify(getattr(t,f),filename,results)
            except Exception as e:
                common.logger.debug("Something went wrong in certValidation.py's findVerify: " + str(e))
                report.write("parsingerror-issues-list", "Something went wrong in certValidation.py's findVerify: " + str(e), "strong")
        else:
            if type(q) is m.MethodInvocation:
                if hasattr(q,'name'):
                    if str(q.name)=='verify':
                        if hasattr(q,'arguments'):
                            if len(q.arguments)!=2:
                                if not warningGiven:
                                    issue = ReportIssue()
                                    issue.setCategory(ExploitType.CERTIFICATE)
                                    issue.setDetails("Custom verify method used in " + str(filename) + ". You should manually review certificate validation here." )
                                    issue.setFile(filename)
                                    issue.setSeverity(Severity.WARNING)
                                    results.append(issue)

                                    issue = terminalPrint()
                                    issue.setLevel(Severity.WARNING)
                                    issue.setData("Custom verify method used in " + str(filename) + ". You should manually review certificate validation here." )
                                    results.append(issue)
                                    warningGiven=True
                            else:
                                common.logger.debug("sslSessions Before: " + str(sslSessions))
                                if str(q.arguments[1]) in sslSessions:
                                    sslSessions.remove(str(q.arguments[1]))
                                    common.logger.debug("sslSessions After: " + str(sslSessions))

                            #For each verify method, check whether the session being verified is in sslSessions and if so, remove it(considering it verified)
                            #This is not full proof at all, for several reasons, but we know it's definitely vulnerable if it's never verified, assuming no strange code
                            #TODO - check that the .verify actually belongs to a HostnameVerifier
                            #TODO - verify that .verify is not over ridden somewhere
            elif type(q) is m.MethodDeclaration:
                if hasattr(q,'name'):
                    if str(q.name)=='verify':
                        if not warningGiven:
                            issue = ReportIssue()
                            issue.setCategory(ExploitType.CERTIFICATE)
                            issue.setDetails("Custom verify method declared in " + str(filename) + ". You should manually review certificate validation here." )
                            issue.setFile(filename)
                            issue.setSeverity(Severity.WARNING)
                            results.append(issue)

                            issue = terminalPrint()
                            issue.setLevel(Severity.WARNING)
                            issue.setData("Custom verify method declared in " + str(filename) + ". You should manually review certificate validation here." )
                            results.append(issue)
                            warningGiven=True
            elif type(q) is list:
                for l in q:
                    if type(l) is not None:
                        recursive_find_verify(l,filename,results)
            elif hasattr(q,'_fields'):
                for f in q._fields:
                    if type(getattr(q,f)) is not None:
                        recursive_find_verify(getattr(q,f),filename,results)
                    elif type(q) is list:
                        for l in q:
                            if type(l) is not None:
                                recursive_find_verify(l,filename,results)
                    elif hasattr(q,'_fields'):
                        for f in q._fields:
                            if type(getattr(q,f)) is not None:
                                recursive_find_verify(getattr(q,f),filename,results)
        verifyIteration=1
        unverified_sessions(results)
    return
def recursive_broadcast_finder(t,results):

	if type(t) is m.MethodDeclaration:
		if str(t.name) == 'sendBroadcast':
			common.logger.debug("It appears the sendBroadcast method may be overridden in this class. The following findings for this class may be false positives")
		if str(t.name) == 'sendBroadcastAsUser':
			common.logger.debug("It appears the sendBroadcastAsUser method may be overridden in this class. The following findings for this class may be false positives")
		if str(t.name) == 'sendOrderedBroadcast':
			common.logger.debug("It appears the sendOrderedBroadcast method may be overridden in this class. The following findings for this class may be false positives")
		if str(t.name) == 'sendOrderedBroadcastAsUser':
			common.logger.debug("It appears the sendOrderedBroadcastAsUser method may be overridden in this class. The following findings for this class may be false positives")
		if str(t.name) == 'sendStickyBroadcast':
			common.logger.debug("It appears the sendStickyBroadcast method may be overridden in this class. The following findings for this class may be false positives")
		if str(t.name) == 'sendStickyBroadcastAsUser':
			common.logger.debug("It appears the sendStickyBroadcastAsUser method may be overridden in this class. The following findings for this class may be false positives")
		if str(t.name) == 'sendStickyOrderedBroadcast':
			common.logger.debug("It appears the sendStickyOrderedBroadcast method may be overridden in this class. The following findings for this class may be false positives")
		if str(t.name) == 'sendStickyOrderedBroadcastAsUser':
			common.logger.debug("It appears the sendStickyOrderedBroadcastAsUser method may be overridden in this class. The following findings for this class may be false positives")
	if type(t) is m.MethodInvocation:
		if str(t.name) == 'sendBroadcast':
			if len(t.arguments)==1:
				#We need to ensure this isn't a local broadcast
				#TODO - There is a lot more we need to do to fully qualify this, but should be good enough for now
				if local_broadcast_manager_imported()==True:
					common.logger.debug(tree)
				else:
					report.write_badger("manifest-issues", modules.common.Severity.INFO, "NO IMPORT")
					common.logger.debug("FOUND A sendBroadcast")
					issue = ReportIssue()
					issue.setCategory(ExploitType.BROADCAST_INTENT)
					issue.setDetails("A broadcast is sent from this class: " + str(current_file) + ", which does not specify the receiverPermission. This means any application on the device can receive this broadcast. You should investigate this for potential data leakage.")
					issue.setFile(str(current_file))
					issue.setSeverity(Severity.WARNING)
					results.append(issue)

					issue = terminalPrint()
					issue.setLevel(Severity.WARNING)
					issue.setData("A broadcast is sent from this class: " + str(current_file) + ", which does not specify the receiverPermission. This means any application on the device can receive this broadcast. You should investigate this for potential data leakage.")
					results.append(issue)

			elif len(t.arguments)==2:
				if common.minSdkVersion<21:
					issue = ReportIssue()
					issue.setCategory(ExploitType.BROADCAST_INTENT)
					issue.setDetails("A broadcast is sent from this class: " + str(current_file) + ", which specifies the receiverPermission, but may still be vulnerable to interception, due to the permission squatting vulnerability in API levels before 21. This means any application, installed prior to the expected receiver(s) on the device can potentially receive this broadcast. You should investigate this for potential data leakage.")
					issue.setFile(str(current_file))
					issue.setSeverity(Severity.WARNING)
					results.append(issue)

					issue = terminalPrint()
					issue.setLevel(Severity.WARNING)
					issue.setData("A broadcast is sent from this class: " + str(current_file) + ", which specifies the receiverPermission, but may still be vulnerable to interception, due to the permission squatting vulnerability in API levels before 21. This means any application, installed prior to the expected receiver(s) on the device can potentially receive this broadcast. You should investigate this for potential data leakage.")
					results.append(issue)
				else:
					issue = ReportIssue()
					issue.setCategory(ExploitType.BROADCAST_INTENT)
					issue.setDetails("A broadcast is sent from this class: " + str(current_file) + ", which specifies the receiverPermission, but depending on the protection level of the permission (on the receiving app side), may still be vulnerable to interception, if the protection level of the permission is not set to signature or signatureOrSystem. You should investigate this for potential data leakage.")
					issue.setFile(str(current_file))
					issue.setSeverity(Severity.WARNING)
					results.append(issue)

					issue = terminalPrint()
					issue.setLevel(Severity.WARNING)
					issue.setData("A broadcast is sent from this class: " + str(current_file) + ", which specifies the receiverPermission, but depending on the protection level of the permission (on the receiving app side), may still be vulnerable to interception, if the protection level of the permission is not set to signature or signatureOrSystem. You should investigate this for potential data leakage.")
					results.append(issue)
		elif str(t.name) == 'sendBroadcastAsUser':
			if len(t.arguments)==2:
				issue = ReportIssue()
				issue.setCategory(ExploitType.BROADCAST_INTENT)
				issue.setDetails("A broadcast, as a specific user, is sent from this class: " + str(current_file) + ", which does not specify the receiverPermission. This means any application on the device can receive this broadcast. You should investigate this for potential data leakage.")
				issue.setFile(str(current_file))
				issue.setSeverity(Severity.WARNING)
				results.append(issue)

				issue = terminalPrint()
				issue.setLevel(Severity.WARNING)
				issue.setData("A broadcast, as a specific user, is sent from this class: " + str(current_file) + ", which does not specify the receiverPermission. This means any application on the device can receive this broadcast. You should investigate this for potential data leakage.")
				results.append(issue)
			elif len(t.arguments)==3:
				if common.minSdkVersion<21:
					issue = ReportIssue()
					issue.setCategory(ExploitType.BROADCAST_INTENT)
					issue.setDetails("A broadcast, as a specific user, is sent from this class: " + str(current_file) + ", which specifies the receiverPermission, but may still be vulnerable to interception, due to the permission squatting vulnerability in API levels before 21. This means any application, installed prior to the expected receiver(s) on the device can potentially receive this broadcast. You should investigate this for potential data leakage.")
					issue.setFile(str(current_file))
					issue.setSeverity(Severity.WARNING)
					results.append(issue)

					issue = terminalPrint()
					issue.setLevel(Severity.WARNING)
					issue.setData("A broadcast, as a specific user, is sent from this class: " + str(current_file) + ", which specifies the receiverPermission, but may still be vulnerable to interception, due to the permission squatting vulnerability in API levels before 21. This means any application, installed prior to the expected receiver(s) on the device can potentially receive this broadcast. You should investigate this for potential data leakage.")
					results.append(issue)
				else:
					issue = ReportIssue()
					issue.setCategory(ExploitType.BROADCAST_INTENT)
					issue.setDetails("A broadcast, as a specific user, is sent from this class: " + str(current_file) + ", which specifies the receiverPermission, but depending on the protection level of the permission (on the receiving app side), may still be vulnerable to interception, if the protection level of the permission is not set to signature or signatureOrSystem. You should investigate this for potential data leakage.")
					issue.setFile(str(current_file))
					issue.setSeverity(Severity.WARNING)
					results.append(issue)

					issue = terminalPrint()
					issue.setLevel(Severity.WARNING)
					issue.setData("A broadcast, as a specific user, is sent from this class: " + str(current_file) + ", which specifies the receiverPermission, but depending on the protection level of the permission (on the receiving app side), may still be vulnerable to interception, if the protection level of the permission is not set to signature or signatureOrSystem. You should investigate this for potential data leakage.")
					results.append(issue)
		elif str(t.name) == 'sendOrderedBroadcast':
			if ((len(t.arguments)==2) or (len(t.arguments)==7)):
				if common.minSdkVersion<21:
					issue = ReportIssue()
					issue.setCategory(ExploitType.BROADCAST_INTENT)
					issue.setDetails("An ordered broadcast, as a specific user, is sent from this class: " + str(current_file) + ", which specifies the receiverPermission, but may still be vulnerable to interception, due to the permission squatting vulnerability in API levels before 21. This means any application, installed prior to the expected receiver(s) on the device can potentially receive this broadcast. You should investigate this for potential data leakage.")
					issue.setFile(str(current_file))
					issue.setSeverity(Severity.WARNING)
					results.append(issue)

					issue = terminalPrint()
					issue.setLevel(Severity.WARNING)
					issue.setData("An ordered broadcast, as a specific user, is sent from this class: " + str(current_file) + ", which specifies the receiverPermission, but may still be vulnerable to interception, due to the permission squatting vulnerability in API levels before 21. This means any application, installed prior to the expected receiver(s) on the device can potentially receive this broadcast. You should investigate this for potential data leakage.")
					results.append(issue)
				else:
					issue = ReportIssue()
					issue.setCategory(ExploitType.BROADCAST_INTENT)
					issue.setDetails("An ordered broadcast, as a specific user, is sent from this class: " + str(current_file) + ", which specifies the receiverPermission, but may still be vulnerable to interception, due to the permission squatting vulnerability in API levels before 21. This means any application, installed prior to the expected receiver(s) on the device can potentially receive this broadcast. You should investigate this for potential data leakage.")
					issue.setFile(str(current_file))
					issue.setSeverity(Severity.WARNING)
					results.append(issue)

					issue = terminalPrint()
					issue.setLevel(Severity.WARNING)
					issue.setData("An ordered broadcast, as a specific user, is sent from this class: " + str(current_file) + ", which specifies the receiverPermission, but may still be vulnerable to interception, due to the permission squatting vulnerability in API levels before 21. This means any application, installed prior to the expected receiver(s) on the device can potentially receive this broadcast. You should investigate this for potential data leakage.")
					results.append(issue)
		elif str(t.name) == 'sendOrderedBroadcastAsUser':
			if len(t.arguments)==7:
				if common.minSdkVersion<21:
					issue = ReportIssue()
					issue.setCategory(ExploitType.BROADCAST_INTENT)
					issue.setDetails("An ordered broadcast, as a specific user, is sent from this class: " + str(current_file) + ", which specifies the receiverPermission, but may still be vulnerable to interception, due to the permission squatting vulnerability in API levels before 21. This means any application, installed prior to the expected receiver(s) on the device can potentially receive this broadcast. You should investigate this for potential data leakage.")
					issue.setFile(str(current_file))
					issue.setSeverity(Severity.WARNING)
					results.append(issue)

					issue = terminalPrint()
					issue.setLevel(Severity.WARNING)
					issue.setData("An ordered broadcast, as a specific user, is sent from this class: " + str(current_file) + ", which specifies the receiverPermission, but may still be vulnerable to interception, due to the permission squatting vulnerability in API levels before 21. This means any application, installed prior to the expected receiver(s) on the device can potentially receive this broadcast. You should investigate this for potential data leakage.")
					results.append(issue)
				else:
					issue = ReportIssue()
					issue.setCategory(ExploitType.BROADCAST_INTENT)
					issue.setDetails("An ordered broadcast, as a specific user, is sent from this class: " + str(current_file) + ", which specifies the receiverPermission, but depending on the protection level of the permission (on the receiving app side), may still be vulnerable to interception, if the protection level of the permission is not set to signature or signatureOrSystem. You should investigate this for potential data leakage.")
					issue.setFile(str(current_file))
					issue.setSeverity(Severity.WARNING)
					results.append(issue)

					issue = terminalPrint()
					issue.setLevel(Severity.WARNING)
					issue.setData("An ordered broadcast, as a specific user, is sent from this class: " + str(current_file) + ", which specifies the receiverPermission, but depending on the protection level of the permission (on the receiving app side), may still be vulnerable to interception, if the protection level of the permission is not set to signature or signatureOrSystem. You should investigate this for potential data leakage.")
					results.append(issue)
		elif str(t.name) == 'sendStickyBroadcast':
			issue = ReportIssue()
			issue.setCategory(ExploitType.BROADCAST_INTENT)
			issue.setDetails("A sticky broadcast is sent from this class: " + str(current_file) + ". These should not be used, as they provide no security (anyone can access them), no protection (anyone can modify them), and many other problems. For more info: http://developer.android.com/reference/android/content/Context.html")
			issue.setFile(str(current_file))
			issue.setSeverity(Severity.VULNERABILITY)
			results.append(issue)

			issue = terminalPrint()
			issue.setLevel(Severity.VULNERABILITY)
			issue.setData("A sticky broadcast is sent from this class: " + str(current_file) + ". These should not be used, as they provide no security (anyone can access them), no protection (anyone can modify them), and many other problems. For more info: http://developer.android.com/reference/android/content/Context.html")
			results.append(issue)
		elif str(t.name) == 'sendStickyBroadcastAsUser':
			issue = ReportIssue()
			issue.setCategory(ExploitType.BROADCAST_INTENT)
			issue.setDetails("A sticky user broadcast is sent from this class: " + str(current_file) + ". These should not be used, as they provide no security (anyone can access them), no protection (anyone can modify them), and many other problems. For more info: http://developer.android.com/reference/android/content/Context.html")
			issue.setFile(str(current_file))
			issue.setSeverity(Severity.VULNERABILITY)
			results.append(issue)

			issue = terminalPrint()
			issue.setLevel(Severity.VULNERABILITY)
			issue.setData("A sticky user broadcast is sent from this class: " + str(current_file) + ". These should not be used, as they provide no security (anyone can access them), no protection (anyone can modify them), and many other problems. For more info: http://developer.android.com/reference/android/content/Context.html")
			results.append(issue)
		elif str(t.name) == 'sendStickyOrderedBroadcast':
			issue = ReportIssue()
			issue.setCategory(ExploitType.BROADCAST_INTENT)
			issue.setDetails("A sticky ordered broadcast is sent from this class: " + str(current_file) + ". These should not be used, as they provide no security (anyone can access them), no protection (anyone can modify them), and many other problems. For more info: http://developer.android.com/reference/android/content/Context.html")
			issue.setFile(str(current_file))
			issue.setSeverity(Severity.VULNERABILITY)
			results.append(issue)

			issue = terminalPrint()
			issue.setLevel(Severity.VULNERABILITY)
			issue.setData("A sticky ordered broadcast is sent from this class: " + str(current_file) + ". These should not be used, as they provide no security (anyone can access them), no protection (anyone can modify them), and many other problems. For more info: http://developer.android.com/reference/android/content/Context.html")
			results.append(issue)
		elif str(t.name) == 'sendStickyOrderedBroadcastAsUser':
			issue = ReportIssue()
			issue.setCategory(ExploitType.BROADCAST_INTENT)
			issue.setDetails("A sticky ordered user broadcast is sent from this class: " + str(current_file) + ". These should not be used, as they provide no security (anyone can access them), no protection (anyone can modify them), and many other problems. For more info: http://developer.android.com/reference/android/content/Context.html")
			issue.setFile(str(current_file))
			issue.setSeverity(Severity.VULNERABILITY)
			results.append(issue)

			issue = terminalPrint()
			issue.setLevel(Severity.VULNERABILITY)
			issue.setData("A sticky ordered user broadcast is sent from this class: " + str(current_file) + ". These should not be used, as they provide no security (anyone can access them), no protection (anyone can modify them), and many other problems. For more info: http://developer.android.com/reference/android/content/Context.html")
			results.append(issue)
		elif hasattr(t,'_fields'):
			for g in t._fields:
				recursive_broadcast_finder(getattr(t,g),results)
	elif type(t) is list:
		for l in t:
			recursive_broadcast_finder(l,results)
	elif hasattr(t,'_fields'):
		for f in t._fields:
			if type(getattr(t,f)) is not str:
				recursive_broadcast_finder(getattr(t,f),results)
	return
def recursive_insecure_trust_manager(t,filename,results):
    if type(t) is m.MethodDeclaration:
        if str(t.name)=='checkServerTrusted':
            if len(t.body)==0:
                issue = ReportIssue()
                issue.setCategory(ExploitType.CERTIFICATE)
                issue.setDetails("Instance of checkServerTrusted, with no body found in: " + str(filename) +". This means this application is likely vulnerable to Man-In-The-Middle attacks. This can be confirmed using the free version of Burpsuite. Simply set the Android device's proxy to use Burpsuite via the network settings, but DO NOT install the Portswigger CA certificate on the device. If you still see traffic in the proxy, the app is vulnerable. Note: You need to ensure you exercise this code path. If you are unsure, make sure you click through each part of the application which makes network requests. You may need to toggle the proxy on/off to get past sections that do validate certificates properly in order to reach the vulnerable code. This proves that it will accept certificates from any CA. You should always validate your configuration by visiting an HTTPS site in the native browser and verifying you receive a certificate warning. For details, please see: https://developer.android.com/training/articles/security-ssl.html")
                issue.setFile(filename)
                issue.setSeverity(Severity.WARNING)
                results.append(issue)

                issue = terminalPrint()
                issue.setLevel(Severity.WARNING)
                issue.setData("Instance of checkServerTrusted, with no body found in: " + str(filename) +". This means this application is likely vulnerable to Man-In-The-Middle attacks. This can be confirmed using the free version of Burpsuite. Simply set the Android device's proxy to use Burpsuite via the network settings, but DO NOT install the Portswigger CA certificate on the device. If you still see traffic in the proxy, the app is vulnerable. Note: You need to ensure you exercise this code path. If you are unsure, make sure you click through each part of the application which makes network requests. You may need to toggle the proxy on/off to get past sections that do validate certificates properly in order to reach the vulnerable code. This proves that it will accept certificates from any CA. You should always validate your configuration by visiting an HTTPS site in the native browser and verifying you receive a certificate warning. For details, please see: https://developer.android.com/training/articles/security-ssl.html")
                results.append(issue)
            else:
                for b in t.body:
                    if type(b) is m.Return:
                        #TODO - This needs to be fleshed out more, but it will have to wait due to time constraints
                        issue = terminalPrint()
                        issue.setLevel(Severity.WARNING)
                        issue.setData("Instance of checkServerTrusted, which only returns " + str(filename) +". This means this application is likely vulnerable to Man-In-The-Middle attacks. This can be confirmed using the free version of Burpsuite. Simply set the Android device's proxy to use Burpsuite via the network settings, but DO NOT install the Portswigger CA certificate on the device. If you still see traffic in the proxy, the app is vulnerable. Note: You need to ensure you excercise this code path. If you are unsure, make sure you click through each part of the application which makes network requests. You may need to toggle the proxy on/off to get past sections that do validate certificates properly in order to reach the vulnerable code. This proves that it will accept certitificates from any CA. You should always validate your configuration by visiting an HTTPS site in the native browser and verifying you receive a certificate warning. For details, please see: https://developer.android.com/training/articles/security-ssl.html")
                        results.append(issue)

                        issue = ReportIssue()
                        issue.setCategory(ExploitType.CERTIFICATE)
                        issue.setDetails("Instance of checkServerTrusted, which only returns " + str(filename) +". This means this application is likely vulnerable to Man-In-The-Middle attacks. This can be confirmed using the free version of Burpsuite. Simply set the Android device's proxy to use Burpsuite via the network settings, but DO NOT install the Portswigger CA certificate on the device. If you still see traffic in the proxy, the app is vulnerable. Note: You need to ensure you excercise this code path. If you are unsure, make sure you click through each part of the application which makes network requests. You may need to toggle the proxy on/off to get past sections that do validate certificates properly in order to reach the vulnerable code. This proves that it will accept certitificates from any CA. You should always validate your configuration by visiting an HTTPS site in the native browser and verifying you receive a certificate warning. For details, please see: https://developer.android.com/training/articles/security-ssl.html")
                        issue.setFile(filename)
                        issue.setSeverity(Severity.WARNING)
                        results.append(issue)
                    else:
                        break #TODO - only want to check once, to see if it's only a return, can probably be replaced by len()
    elif type(t) is list:
        for x in t:
            recursive_insecure_trust_manager(x,filename,results)
    elif hasattr(t,'_fields'):
        for f in t._fields:
            recursive_insecure_trust_manager(getattr(t,f),filename,results)
    return
Example #20
0
def show_wv_vulns(s_list, i, results):
    """
    Shows all identified web view vulnerabilities
    """
    #BUG - This sometimes prints twice, successively which shouldn't happen
    #print "#"*100
    issue = terminalPrint()
    issue.setLevel(Severity.INFO)
    issue.setData("WebView: " + str(i[0]))
    results.append(issue)
    #logger.info("WebView: " +str(i[0]))
    issue = terminalPrint()
    issue.setLevel(Severity.INFO)
    issue.setData("File: " + str(i[1]) + "\n")
    results.append(issue)
    #logger.info("File: " + str(i[1]) +"\n")

    if len(s_list) == 0:
        default_wv_config(i[0], i[1], int(common.minSdkVersion), results)
        return

    for f in s_list:
        sl = re.sub(r'WebSettings\s*', '', f)
        sl = re.sub(r'\s*[;=].*$', '', sl)
        sl = re.sub(r'final\s', '', sl)
        #strip string whitespace out
        sl = re.sub(r'^\W+', '', sl)
        sl = re.sub(r'\.\w+\(\w+\)$', '', sl)
        sl = sl.rstrip()
        #Regex to look for javascript being enabled
        #BUG I can reduce the number of files checked to only those that have the name / import WebViews
        #Probably need to check for alternative true/false value representations
        wv_js_check = sl + '.setJavaScriptEnabled(true)'
        wv_js_check = re.escape(wv_js_check)
        #check if webview JS in enabled
        #BUG - THis can run twice, perhaps it is an artifact of an empty first element?
        if wv_config(i[1], wv_js_check):
            issue = ReportIssue()
            issue.setCategory(ExploitType.WEBVIEW)
            issue.setDetails(common.config.get('qarkhelper', 'JS_WARNING'))
            issue.setFile(str(i[1]))
            issue.setSeverity(Severity.WARNING)
            issue.setExtras(IS_JS_ENABLED, True)
            results.append(issue)

            issue = terminalPrint()
            issue.setLevel(Severity.WARNING)
            issue.setData(
                common.config.get('qarkhelper', 'TERMINAL_JS_WARNING') + " " +
                str(i[0]) + " " +
                common.config.get('qarkhelper', 'TERMINAL_JS_WARNING1') +
                " To validate this vulnerability, load the following url in this WebView: http://www.secbro.com/poc/html/JS_WARNING.html"
                +
                "Note: A local copy of this html file can also be found at <install_dir>/quark/poc/html/JS_WARNING.html\n"
            )
            results.append(issue)
        else:
            issue = terminalPrint()
            issue.setLevel(Severity.INFO)
            issue.setData(
                common.config.get('qarkhelper', 'JS_OK') + " " + str(i[0]) +
                str(i[1]))
            results.append(issue)
#BUG - this is actually set on WebView
#Check whether webview sets arbitrary BaseURL
        wv_burl_check = re.escape(sl + '.loadDataWithBaseURL')
        if wv_config(i[1], wv_burl_check):
            issue = ReportIssue()
            issue.setCategory(ExploitType.WEBVIEW)
            issue.setDetails(common.config.get('qarkhelper', 'BURL_WARNING1'))
            issue.setFile(str(i[1]))
            issue.setSeverity(Severity.WARNING)
            issue.setExtras(IS_BASE_URL_DEFINED, False)
            results.append(issue)

            issue = terminalPrint()
            issue.setLevel(Severity.WARNING)
            issue.setData(
                common.config.get('qarkhelper', 'TERMINAL_BURL_WARNING1') +
                " " + str(i[0]) + " " +
                common.config.get('qarkhelper', 'TERMINAL_BURL_WARNING2') +
                "To validate this vulnerability, load the following url in this WebView: http://www.secbro.com/poc/html/BURL_WARNING.html "
                +
                "Note: A local copy of this html file can also be found at <install_dir>/quark/poc/html/BURL_WARNING.html\n"
            )
            results.append(issue)
        else:
            issue = ReportIssue()
            issue.setCategory(ExploitType.WEBVIEW)
            issue.setDetails(common.config.get('qarkhelper', 'BURL_OK'))
            issue.setFile(str(i[1]))
            issue.setSeverity(Severity.INFO)
            issue.setExtras(IS_BASE_URL_DEFINED, True)
            results.append(issue)

            issue = terminalPrint()
            issue.setLevel(Severity.INFO)
            issue.setData(common.config.get('qarkhelper', 'BURL_OK'))
            results.append(issue)

    #Checks whether file URI can access filesystem
    #true by default, so the check is inverted
        wv_file_check = re.escape(sl + '.setAllowFileAccess(false)')
        if wv_config(i[1], wv_file_check):
            issue = ReportIssue()
            issue.setCategory(ExploitType.WEBVIEW)
            issue.setDetails(common.config.get('qarkhelper', 'FILE_SYS_OK'))
            issue.setFile(str(i[1]))
            issue.setSeverity(Severity.WARNING)
            issue.setExtras(IS_FILE_ACCESS_ENABLED, False)
            results.append(issue)

            issue = terminalPrint()
            issue.setLevel(Severity.INFO)
            issue.setData(
                common.config.get('qarkhelper', 'FILE_SYS_OK') + str(i[0]))
            results.append(issue)
        else:
            issue = ReportIssue()
            issue.setCategory(ExploitType.WEBVIEW)
            issue.setDetails(common.config.get('qarkhelper', 'FILE_SYS_WARN1'))
            issue.setFile(str(i[1]))
            issue.setSeverity(Severity.WARNING)
            issue.setExtras(IS_FILE_ACCESS_ENABLED, True)
            results.append(issue)

            issue = terminalPrint()
            issue.setLevel(Severity.WARNING)
            issue.setData(
                common.config.get('qarkhelper', 'TERMINAL_FILE_SYS_WARN1') +
                str(i[0]) + " " +
                common.config.get('qarkhelper', 'TERMINAL_FILE_SYS_WARN2') +
                " To validate this vulnerability, load the following url in this WebView: http://www.secbro.com/poc/html/FILE_SYS_WARN.html "
                +
                "Note: A local copy of this html file can also be found at <install_dir>/quark/poc/html/FILE_SYS_WARN.html\n"
            )
            results.append(issue)
#Regex to determine if WebViews have Content Provider access (default = true)
#Checks whether WebView can access Content Providers
#true by default, so the check is inverted
#BUG - This can run twice, perhaps due to an empty element
        wv_cpa_check = re.escape(sl + '.setAllowContentAccess(false)')
        if wv_config(i[1], wv_cpa_check):
            issue = ReportIssue()
            issue.setCategory(ExploitType.WEBVIEW)
            issue.setDetails(common.config.get('qarkhelper', 'WV_CPA_OK'))
            issue.setFile(str(i[1]))
            issue.setSeverity(Severity.INFO)
            issue.setExtras(IS_CP_ACCESS_ENABLED, False)
            results.append(issue)

            issue = terminalPrint()
            issue.setLevel(Severity.INFO)
            issue.setData(
                common.config.get('qarkhelper', 'WV_CPA_OK') + str(i[0]))
            results.append(issue)
        else:
            issue = ReportIssue()
            issue.setCategory(ExploitType.WEBVIEW)
            issue.setDetails(common.config.get('qarkhelper', 'WV_CPA_WARNING'))
            issue.setFile(str(i[1]))
            issue.setSeverity(Severity.WARNING)
            issue.setExtras(IS_CP_ACCESS_ENABLED, True)
            results.append(issue)

            issue = terminalPrint()
            issue.setLevel(Severity.WARNING)
            issue.setData(
                common.config.get('qarkhelper', 'TERMINAL_WV_CPA_WARNING') +
                str(i[0]) +
                "To validate this vulnerability, load the following url in this WebView: http://www.secbro.com/poc/html/WV_CPA_WARNING.html "
                +
                "Note: A local copy of this html file can also be found at <install_dir>/quark/poc/html/WV_CPA_WARNING.html\n"
            )
            results.append(issue)
    #check for JS access from file URL can access content from any origin
    #minSdk <= 15 default is true; minSdk > 16 default is false
    #BUG - This check is wrong on the second if; If set to false and not found, it prints OK
        if int(common.minSdkVersion) < 16:
            wv_univ_file_access = re.escape(
                sl + '.setAllowUniversalAccessFromFileURLs(false)')
            if not wv_config(i[1], wv_univ_file_access):
                issue = ReportIssue()
                issue.setCategory(ExploitType.WEBVIEW)
                issue.setDetails(
                    common.config.get('qarkhelper', 'UNIV_FILE_WARNING'))
                issue.setFile(str(i[1]))
                issue.setSeverity(Severity.WARNING)
                issue.setExtras(IS_FILE_ACCESS_ENABLED, True)
                results.append(issue)

                issue = terminalPrint()
                issue.setLevel(Severity.WARNING)
                issue.setData(
                    common.config.get('qarkhelper',
                                      'TERMINAL_UNIV_FILE_WARNING') +
                    str(i[0]) +
                    " To validate this vulnerability, load the following url in this WebView: http://www.secbro.com/poc/html/UNIV_FILE_WARNING.html "
                    +
                    "Note: A local copy of this html file can also be found at <install_dir>/quark/poc/html/UNIV_FILE_WARNING.html\n"
                )
                results.append(issue)
                skip_next = True
            else:
                issue = ReportIssue()
                issue.setCategory(ExploitType.WEBVIEW)
                issue.setDetails(
                    common.config.get('qarkhelper', 'UNIV_FILE_OK'))
                issue.setFile(str(i[1]))
                issue.setSeverity(Severity.INFO)
                issue.setExtras(IS_FILE_ACCESS_ENABLED, False)
                results.append(issue)

                issue = terminalPrint()
                issue.setLevel(Severity.INFO)
                issue.setData(
                    common.config.get('qarkhelper', 'UNIV_FILE_OK') +
                    str(i[0]))
                results.append(issue)
                skip_next = False
    #checking previous value above, as this is ignored if the above is true
    #could I just put pass above?
            if skip_next:
                pass
            else:
                #minSdk <= 15 default is true; minSdk > 16 default is false
                wv_allow_file_access_furls = re.escape(
                    sl + '.setAllowFileAccessFromFileURLs(false)')
                if wv_config(i[1], wv_allow_file_access_furls):
                    issue = terminalPrint()
                    issue.setLevel(Severity.INFO)
                    issue.setData(
                        "This WebView does not have access to File URLs - setAllowFileAccessFromFileURLs(false)"
                        + str(i[0]))
                    results.append(issue)

                    issue = ReportIssue()
                    issue.setCategory(ExploitType.WEBVIEW)
                    issue.setDetails(
                        "This WebView does not have access to File URLs - setAllowFileAccessFromFileURLs(false)"
                    )
                    issue.setFile(str(i[1]))
                    issue.setSeverity(Severity.WARNING)
                    issue.setExtras(IS_FILE_ACCESS_ENABLED, False)
                    results.append(issue)
                else:
                    issue = ReportIssue()
                    issue.setCategory(ExploitType.WEBVIEW)
                    issue.setDetails(
                        common.config.get('qarkhelper', 'UNIV_FILE_WARNING'))
                    issue.setFile(str(i[1]))
                    issue.setSeverity(Severity.WARNING)
                    results.append(issue)

                    issue = terminalPrint()
                    issue.setLevel(Severity.WARNING)
                    issue.setExtras(IS_FILE_ACCESS_ENABLED, True)
                    issue.setData(
                        common.config.get('qarkhelper',
                                          'TERMINAL_UNIV_FILE_WARNING') +
                        str(i[0]) +
                        "To validate this vulnerability, load the following url in this WebView: http://www.secbro.com/poc/html/UNIV_FILE_WARNING2.html "
                        +
                        "Note: A local copy of this html file can also be found at <install_dir>/quark/poc/html/UNIV_FILE_WARNING2.html\n"
                    )
                    results.append(issue)

        else:
            wv_univ_file_access = re.escape(
                sl + '.setAllowUniversalAccessFromFileURLs(true)')
            if wv_config(i[1], wv_univ_file_access):
                issue = ReportIssue()
                issue.setCategory(ExploitType.WEBVIEW)
                issue.setDetails(
                    common.config.get('qarkhelper', 'UNIV_FILE_WARNING'))
                issue.setFile(str(i[1]))
                issue.setSeverity(Severity.WARNING)
                issue.setExtras(IS_UNIVERSAL_FILE_ACCESS_ENABLED, True)
                results.append(issue)

                issue = terminalPrint()
                issue.setLevel(Severity.WARNING)
                issue.setData(
                    common.config.get('qarkhelper',
                                      'TERMINAL_UNIV_FILE_WARNING') + '1 ' +
                    str(i[0]) +
                    " To validate this vulnerability, load the following url in this WebView: http://www.secbro.com/poc/html/UNIV_FILE_WARNING.html "
                    +
                    "Note: A local copy of this html file can also be found at <install_dir>/quark/poc/html/UNIV_FILE_WARNING.html\n"
                )
                results.append(issue)
                skip_next = True

            else:
                issue = ReportIssue()
                issue.setCategory(ExploitType.WEBVIEW)
                issue.setDetails(
                    common.config.get('qarkhelper', 'UNIV_FILE_OK'))
                issue.setFile(str(i[1]))
                issue.setSeverity(Severity.INFO)
                issue.setExtras(IS_UNIVERSAL_FILE_ACCESS_ENABLED, False)
                results.append(issue)

                issue = terminalPrint()
                issue.setLevel(Severity.INFO)
                issue.setData(
                    common.config.get('qarkhelper', 'UNIV_FILE_OK') +
                    str(i[0]))
                results.append(issue)
                skip_next = False
                #checking previous value above, as this is ignored if the above is true
                if skip_next:
                    pass
                else:
                    #minSdk <= 15 default is true; minSdk > 16 default is false
                    wv_allow_file_access_furls = re.escape(
                        sl + '.setAllowFileAccessFromFileURLs(true)')
                    if wv_config(i[1], wv_allow_file_access_furls):
                        issue = ReportIssue()
                        issue.setCategory(ExploitType.WEBVIEW)
                        issue.setDetails(
                            common.config.get('qarkhelper',
                                              'FURL_FILE_WARNING'))
                        issue.setFile(str(i[1]))
                        issue.setSeverity(Severity.WARNING)
                        issue.setExtras(IS_UNIVERSAL_FILE_ACCESS_ENABLED, True)
                        results.append(issue)

                        issue = terminalPrint()
                        issue.setLevel(Severity.WARNING)
                        issue.setData(
                            common.config.get('qarkhelper',
                                              'TERMINAL_FURL_FILE_WARNING') +
                            str(i[0]) +
                            "To validate this vulnerability, load the following url in this WebView: http://www.secbro.com/poc/html/FURL_FILE_WARNING.html "
                            +
                            "Note: A local copy of this html file can also be found at <install_dir>/quark/poc/html/FURL_FILE_WARNING.html\n"
                        )
                        results.append(issue)
                    else:
                        issue = ReportIssue()
                        issue.setCategory(ExploitType.WEBVIEW)
                        issue.setDetails(
                            common.config.get('qarkhelper', 'FURL_FILE_OK'))
                        issue.setFile(str(i[1]))
                        issue.setSeverity(Severity.INFO)
                        issue.setExtras(IS_UNIVERSAL_FILE_ACCESS_ENABLED,
                                        False)
                        results.append(issue)

                        issue = terminalPrint()
                        issue.setLevel(Severity.INFO)
                        issue.setData(
                            common.config.get('qarkhelper', 'FURL_FILE_OK') +
                            str(i[0]))
                        results.append(issue)

    #Checking whether plugins are enabled for WebViews
    #setPluginsEnabled deprecated in API 9, removed in API 18
    #setPluginState added in API 8, deprecated in API 18
        wv_plugsinenabled = re.escape(sl + '.setPluginsEnabled(true)')
        wv_pluginstate = re.escape(
            sl + '.setPluginState(WebSettings.PluginState.ON*')

        if wv_config(i[1], wv_plugsinenabled):
            if int(common.minSdkVersion) < 18:
                issue = ReportIssue()
                issue.setCategory(ExploitType.WEBVIEW)
                issue.setDetails(
                    common.config.get('qarkhelper', 'DEPRECATED_SINCE_9') +
                    str(i[0]) + "<br>FILE: " + str(i[1]))
                issue.setFile(str(i[1]))
                issue.setSeverity(Severity.INFO)
                results.append(issue)

                issue = terminalPrint()
                issue.setLevel(Severity.INFO)
                issue.setData(
                    common.config.get('qarkhelper', 'DEPRECATED_SINCE_9') +
                    str(i[0]))
                results.append(issue)
            else:
                issue = ReportIssue()
                issue.setCategory(ExploitType.WEBVIEW)
                issue.setDetails(
                    common.config.get('qarkhelper', 'REMOVED_IN_18') +
                    str(i[0]) + "<br>FILE: " + str(i[1]))
                issue.setFile(str(i[1]))
                issue.setSeverity(Severity.INFO)
                results.append(issue)

                issue = terminalPrint()
                issue.setLevel(Severity.INFO)
                issue.setData(
                    common.config.get('qarkhelper', 'REMOVED_IN_18') +
                    str(i[0]))
                results.append(issue)
                logger.info(
                    common.config.get('qarkhelper', 'REMOVED_IN_18') +
                    str(i[0]))
        if wv_config(i[1], wv_pluginstate):
            if int(common.minSdkVersion) < 8:
                issue = ReportIssue()
                issue.setCategory(ExploitType.WEBVIEW)
                issue.setDetails(
                    common.config.get('qarkhelper', 'ADDED_IN_8') + str(i[0]) +
                    "<br>FILE: " + str(i[1]))
                issue.setFile(str(i[1]))
                issue.setSeverity(Severity.INFO)
                results.append(issue)

                issue = terminalPrint()
                issue.setLevel(Severity.INFO)
                issue.setData(
                    common.config.get('qarkhelper', 'ADDED_IN_8') + str(i[0]))
                results.append(issue)
                logger.info(
                    common.config.get('qarkhelper', 'ADDED_IN_8') + str(i[0]))
            else:
                issue = ReportIssue()
                issue.setCategory(ExploitType.WEBVIEW)
                issue.setDetails(
                    common.config.get('qarkhelper', 'DEPRECATED_IN_18') +
                    str(i[0]) + "<br>FILE: " + str(i[1]))
                issue.setFile(str(i[1]))
                issue.setSeverity(Severity.INFO)
                results.append(issue)

                issue = terminalPrint()
                issue.setLevel(Severity.INFO)
                issue.setData(
                    common.config.get('qarkhelper', 'DEPRECATED_IN_18') +
                    str(i[0]))
                results.append(issue)
    #Check if addJavascriptInterface is used in WebView
    #BUG - this is actually on WebView, not settings
        wv_ajs = re.escape(sl + '.addJavascriptInterface')
        if wv_config(i[1], wv_ajs):
            if int(common.minSdkVersion) < 17:
                issue = ReportIssue()
                issue.setCategory(ExploitType.WEBVIEW)
                issue.setDetails(common.config.get('qarkhelper', 'BAD_JS_INT'))
                issue.setFile(str(i[1]))
                issue.setSeverity(Severity.WARNING)
                results.append(issue)

                issue = terminalPrint()
                issue.setLevel(Severity.WARNING)
                issue.setData(
                    common.config.get('qarkhelper', 'TERMINAL_BAD_JS_INT') +
                    " " + str(i[0]) +
                    " To validate this vulnerability, load the following url in this WebView: http://www.secbro.com/poc/html/BAD_JS_INT.html "
                    +
                    "Note: A local copy of this html file can also be found at <install_dir>/quark/poc/html/BAD_JS_INT.html"
                    + "\n")
                results.append(issue)
            else:
                issue = ReportIssue()
                issue.setCategory(ExploitType.WEBVIEW)
                issue.setDetails(
                    common.config.get('qarkhelper', 'OK_JS_INT') + str(i[0]) +
                    "<br>FILE: " + str(i[1]))
                issue.setFile(str(i[1]))
                issue.setSeverity(Severity.INFO)
                results.append(issue)

                issue = terminalPrint()
                issue.setLevel(Severity.INFO)
                issue.setData(common.config.get('qarkhelper', 'OK_JS_INT'))
                results.append(issue)
        else:
            issue = ReportIssue()
            issue.setCategory(ExploitType.WEBVIEW)
            issue.setDetails(
                common.config.get('qarkhelper', 'NO_JS_INT') + "<br>FILE: " +
                str(i[1]))
            issue.setFile(str(i[1]))
            issue.setSeverity(Severity.INFO)
            results.append(issue)

            issue = terminalPrint()
            issue.setLevel(Severity.INFO)
            issue.setData(
                common.config.get('qarkhelper', 'NO_JS_INT') + str(i[0]))
            results.append(issue)

    #Check if WebView has DOMStorage enabled
        wv_setdom = re.escape(sl + '.setDomStorageEnabled(true)')
        if wv_config(i[1], wv_setdom):
            issue = ReportIssue()
            issue.setCategory(ExploitType.WEBVIEW)
            issue.setDetails(
                common.config.get('qarkhelper', 'DOM_STORAGE_EN') + str(i[0]) +
                "<br>FILE: " + str(i[1]))
            issue.setFile(str(i[1]))
            issue.setSeverity(Severity.INFO)
            issue.setExtras(IS_DOM_STORAGE_ENABLED, True)
            results.append(issue)

            issue = terminalPrint()
            issue.setLevel(Severity.INFO)
            issue.setData(common.config.get('qarkhelper', 'DOM_STORAGE_EN'))
            results.append(issue)
        else:
            issue = ReportIssue()
            issue.setCategory(ExploitType.WEBVIEW)
            issue.setDetails(
                common.config.get('qarkhelper', 'DOM_STORAGE_DIS') +
                "<br>FILE: " + str(i[1]))
            issue.setFile(str(i[1]))
            issue.setSeverity(Severity.INFO)
            issue.setExtras(IS_DOM_STORAGE_ENABLED, False)
            results.append(issue)

            issue = terminalPrint()
            issue.setLevel(Severity.INFO)
            issue.setData(
                common.config.get('qarkhelper', 'DOM_STORAGE_DIS') + str(i[0]))
            results.append(issue)

    return
Example #21
0
def find_key_files(results):
    '''	PackagedPrivateKey
	------------------
	Summary: Packaged private key

	Priority: 8 / 10
	Severity: Fatal
	Category: Security

	In general, you should not package private key files inside your app.
	'''
    if len(common.keyFiles) > 0:
        possibleKeyFiles = common.text_scan(common.keyFiles, r'PRIVATE\sKEY')
        if len(possibleKeyFiles) > 0:
            for f in possibleKeyFiles:
                common.logger.debug(
                    "It appears there is a private key embedded in your application: "
                    + str(f))
                issue = ReportIssue()
                issue.setCategory(ExploitType.CRYPTO)
                issue.setDetails(
                    "It appears there is a private key embedded in your application in the following file:"
                )
                issue.setFile(str(f))
                issue.setSeverity(Severity.VULNERABILITY)
                results.append(issue)

                issue = terminalPrint()
                issue.setLevel(Severity.VULNERABILITY)
                issue.setData(
                    "It appears there is a private key embedded in your application in the following file:"
                )
                results.append(issue)
    return
Example #22
0
def recursiveBroadcastFinder(t, results):

    if type(t) is m.MethodDeclaration:
        if str(t.name) == 'sendBroadcast':
            common.logger.debug(
                "It appears the sendBroadcast method may be overridden in this class. The following findings for this class may be false positives"
            )
        if str(t.name) == 'sendBroadcastAsUser':
            common.logger.debug(
                "It appears the sendBroadcastAsUser method may be overridden in this class. The following findings for this class may be false positives"
            )
        if str(t.name) == 'sendOrderedBroadcast':
            common.logger.debug(
                "It appears the sendOrderedBroadcast method may be overridden in this class. The following findings for this class may be false positives"
            )
        if str(t.name) == 'sendOrderedBroadcastAsUser':
            common.logger.debug(
                "It appears the sendOrderedBroadcastAsUser method may be overridden in this class. The following findings for this class may be false positives"
            )
        if str(t.name) == 'sendStickyBroadcast':
            common.logger.debug(
                "It appears the sendStickyBroadcast method may be overridden in this class. The following findings for this class may be false positives"
            )
        if str(t.name) == 'sendStickyBroadcastAsUser':
            common.logger.debug(
                "It appears the sendStickyBroadcastAsUser method may be overridden in this class. The following findings for this class may be false positives"
            )
        if str(t.name) == 'sendStickyOrderedBroadcast':
            common.logger.debug(
                "It appears the sendStickyOrderedBroadcast method may be overridden in this class. The following findings for this class may be false positives"
            )
        if str(t.name) == 'sendStickyOrderedBroadcastAsUser':
            common.logger.debug(
                "It appears the sendStickyOrderedBroadcastAsUser method may be overridden in this class. The following findings for this class may be false positives"
            )
    if type(t) is m.MethodInvocation:
        if str(t.name) == 'sendBroadcast':
            if len(t.arguments) == 1:
                #We need to ensure this isn't a local broadcast
                #TODO - There is a lot more we need to do to fully qualify this, but should be good enough for now
                if localBroadcastManagerImported() == True:
                    common.logger.debug(tree)
                else:
                    report.write_badger("manifest-issues",
                                        modules.common.Severity.INFO,
                                        "NO IMPORT")
                    common.logger.debug("FOUND A sendBroadcast")
                    issue = ReportIssue()
                    issue.setCategory(ExploitType.BROADCAST_INTENT)
                    issue.setDetails(
                        "A broadcast is sent from this class: " +
                        str(current_file) +
                        ", which does not specify the receiverPermission. This means any application on the device can receive this broadcast. You should investigate this for potential data leakage."
                    )
                    issue.setFile(str(current_file))
                    issue.setSeverity(Severity.WARNING)
                    results.append(issue)

                    issue = terminalPrint()
                    issue.setLevel(Severity.WARNING)
                    issue.setData(
                        "A broadcast is sent from this class: " +
                        str(current_file) +
                        ", which does not specify the receiverPermission. This means any application on the device can receive this broadcast. You should investigate this for potential data leakage."
                    )
                    results.append(issue)

            elif len(t.arguments) == 2:
                if common.minSdkVersion < 21:
                    issue = ReportIssue()
                    issue.setCategory(ExploitType.BROADCAST_INTENT)
                    issue.setDetails(
                        "A broadcast is sent from this class: " +
                        str(current_file) +
                        ", which specifies the receiverPermission, but may still be vulnerable to interception, due to the permission squatting vulnerability in API levels before 21. This means any application, installed prior to the expected receiver(s) on the device can potentially receive this broadcast. You should investigate this for potential data leakage."
                    )
                    issue.setFile(str(current_file))
                    issue.setSeverity(Severity.WARNING)
                    results.append(issue)

                    issue = terminalPrint()
                    issue.setLevel(Severity.WARNING)
                    issue.setData(
                        "A broadcast is sent from this class: " +
                        str(current_file) +
                        ", which specifies the receiverPermission, but may still be vulnerable to interception, due to the permission squatting vulnerability in API levels before 21. This means any application, installed prior to the expected receiver(s) on the device can potentially receive this broadcast. You should investigate this for potential data leakage."
                    )
                    results.append(issue)
                else:
                    issue = ReportIssue()
                    issue.setCategory(ExploitType.BROADCAST_INTENT)
                    issue.setDetails(
                        "A broadcast is sent from this class: " +
                        str(current_file) +
                        ", which specifies the receiverPermission, but depending on the protection level of the permission (on the receiving app side), may still be vulnerable to interception, if the protection level of the permission is not set to signature or signatureOrSystem. You should investigate this for potential data leakage."
                    )
                    issue.setFile(str(current_file))
                    issue.setSeverity(Severity.WARNING)
                    results.append(issue)

                    issue = terminalPrint()
                    issue.setLevel(Severity.WARNING)
                    issue.setData(
                        "A broadcast is sent from this class: " +
                        str(current_file) +
                        ", which specifies the receiverPermission, but depending on the protection level of the permission (on the receiving app side), may still be vulnerable to interception, if the protection level of the permission is not set to signature or signatureOrSystem. You should investigate this for potential data leakage."
                    )
                    results.append(issue)
        elif str(t.name) == 'sendBroadcastAsUser':
            if len(t.arguments) == 2:
                issue = ReportIssue()
                issue.setCategory(ExploitType.BROADCAST_INTENT)
                issue.setDetails(
                    "A broadcast, as a specific user, is sent from this class: "
                    + str(current_file) +
                    ", which does not specify the receiverPermission. This means any application on the device can receive this broadcast. You should investigate this for potential data leakage."
                )
                issue.setFile(str(current_file))
                issue.setSeverity(Severity.WARNING)
                results.append(issue)

                issue = terminalPrint()
                issue.setLevel(Severity.WARNING)
                issue.setData(
                    "A broadcast, as a specific user, is sent from this class: "
                    + str(current_file) +
                    ", which does not specify the receiverPermission. This means any application on the device can receive this broadcast. You should investigate this for potential data leakage."
                )
                results.append(issue)
            elif len(t.arguments) == 3:
                if common.minSdkVersion < 21:
                    issue = ReportIssue()
                    issue.setCategory(ExploitType.BROADCAST_INTENT)
                    issue.setDetails(
                        "A broadcast, as a specific user, is sent from this class: "
                        + str(current_file) +
                        ", which specifies the receiverPermission, but may still be vulnerable to interception, due to the permission squatting vulnerability in API levels before 21. This means any application, installed prior to the expected receiver(s) on the device can potentially receive this broadcast. You should investigate this for potential data leakage."
                    )
                    issue.setFile(str(current_file))
                    issue.setSeverity(Severity.WARNING)
                    results.append(issue)

                    issue = terminalPrint()
                    issue.setLevel(Severity.WARNING)
                    issue.setData(
                        "A broadcast, as a specific user, is sent from this class: "
                        + str(current_file) +
                        ", which specifies the receiverPermission, but may still be vulnerable to interception, due to the permission squatting vulnerability in API levels before 21. This means any application, installed prior to the expected receiver(s) on the device can potentially receive this broadcast. You should investigate this for potential data leakage."
                    )
                    results.append(issue)
                else:
                    issue = ReportIssue()
                    issue.setCategory(ExploitType.BROADCAST_INTENT)
                    issue.setDetails(
                        "A broadcast, as a specific user, is sent from this class: "
                        + str(current_file) +
                        ", which specifies the receiverPermission, but depending on the protection level of the permission (on the receiving app side), may still be vulnerable to interception, if the protection level of the permission is not set to signature or signatureOrSystem. You should investigate this for potential data leakage."
                    )
                    issue.setFile(str(current_file))
                    issue.setSeverity(Severity.WARNING)
                    results.append(issue)

                    issue = terminalPrint()
                    issue.setLevel(Severity.WARNING)
                    issue.setData(
                        "A broadcast, as a specific user, is sent from this class: "
                        + str(current_file) +
                        ", which specifies the receiverPermission, but depending on the protection level of the permission (on the receiving app side), may still be vulnerable to interception, if the protection level of the permission is not set to signature or signatureOrSystem. You should investigate this for potential data leakage."
                    )
                    results.append(issue)
        elif str(t.name) == 'sendOrderedBroadcast':
            if ((len(t.arguments) == 2) or (len(t.arguments) == 7)):
                if common.minSdkVersion < 21:
                    issue = ReportIssue()
                    issue.setCategory(ExploitType.BROADCAST_INTENT)
                    issue.setDetails(
                        "An ordered broadcast, as a specific user, is sent from this class: "
                        + str(current_file) +
                        ", which specifies the receiverPermission, but may still be vulnerable to interception, due to the permission squatting vulnerability in API levels before 21. This means any application, installed prior to the expected receiver(s) on the device can potentially receive this broadcast. You should investigate this for potential data leakage."
                    )
                    issue.setFile(str(current_file))
                    issue.setSeverity(Severity.WARNING)
                    results.append(issue)

                    issue = terminalPrint()
                    issue.setLevel(Severity.WARNING)
                    issue.setData(
                        "An ordered broadcast, as a specific user, is sent from this class: "
                        + str(current_file) +
                        ", which specifies the receiverPermission, but may still be vulnerable to interception, due to the permission squatting vulnerability in API levels before 21. This means any application, installed prior to the expected receiver(s) on the device can potentially receive this broadcast. You should investigate this for potential data leakage."
                    )
                    results.append(issue)
                else:
                    issue = ReportIssue()
                    issue.setCategory(ExploitType.BROADCAST_INTENT)
                    issue.setDetails(
                        "An ordered broadcast, as a specific user, is sent from this class: "
                        + str(current_file) +
                        ", which specifies the receiverPermission, but may still be vulnerable to interception, due to the permission squatting vulnerability in API levels before 21. This means any application, installed prior to the expected receiver(s) on the device can potentially receive this broadcast. You should investigate this for potential data leakage."
                    )
                    issue.setFile(str(current_file))
                    issue.setSeverity(Severity.WARNING)
                    results.append(issue)

                    issue = terminalPrint()
                    issue.setLevel(Severity.WARNING)
                    issue.setData(
                        "An ordered broadcast, as a specific user, is sent from this class: "
                        + str(current_file) +
                        ", which specifies the receiverPermission, but may still be vulnerable to interception, due to the permission squatting vulnerability in API levels before 21. This means any application, installed prior to the expected receiver(s) on the device can potentially receive this broadcast. You should investigate this for potential data leakage."
                    )
                    results.append(issue)
        elif str(t.name) == 'sendOrderedBroadcastAsUser':
            if len(t.arguments) == 7:
                if common.minSdkVersion < 21:
                    issue = ReportIssue()
                    issue.setCategory(ExploitType.BROADCAST_INTENT)
                    issue.setDetails(
                        "An ordered broadcast, as a specific user, is sent from this class: "
                        + str(current_file) +
                        ", which specifies the receiverPermission, but may still be vulnerable to interception, due to the permission squatting vulnerability in API levels before 21. This means any application, installed prior to the expected receiver(s) on the device can potentially receive this broadcast. You should investigate this for potential data leakage."
                    )
                    issue.setFile(str(current_file))
                    issue.setSeverity(Severity.WARNING)
                    results.append(issue)

                    issue = terminalPrint()
                    issue.setLevel(Severity.WARNING)
                    issue.setData(
                        "An ordered broadcast, as a specific user, is sent from this class: "
                        + str(current_file) +
                        ", which specifies the receiverPermission, but may still be vulnerable to interception, due to the permission squatting vulnerability in API levels before 21. This means any application, installed prior to the expected receiver(s) on the device can potentially receive this broadcast. You should investigate this for potential data leakage."
                    )
                    results.append(issue)
                else:
                    issue = ReportIssue()
                    issue.setCategory(ExploitType.BROADCAST_INTENT)
                    issue.setDetails(
                        "An ordered broadcast, as a specific user, is sent from this class: "
                        + str(current_file) +
                        ", which specifies the receiverPermission, but depending on the protection level of the permission (on the receiving app side), may still be vulnerable to interception, if the protection level of the permission is not set to signature or signatureOrSystem. You should investigate this for potential data leakage."
                    )
                    issue.setFile(str(current_file))
                    issue.setSeverity(Severity.WARNING)
                    results.append(issue)

                    issue = terminalPrint()
                    issue.setLevel(Severity.WARNING)
                    issue.setData(
                        "An ordered broadcast, as a specific user, is sent from this class: "
                        + str(current_file) +
                        ", which specifies the receiverPermission, but depending on the protection level of the permission (on the receiving app side), may still be vulnerable to interception, if the protection level of the permission is not set to signature or signatureOrSystem. You should investigate this for potential data leakage."
                    )
                    results.append(issue)
        elif str(t.name) == 'sendStickyBroadcast':
            issue = ReportIssue()
            issue.setCategory(ExploitType.BROADCAST_INTENT)
            issue.setDetails(
                "A sticky broadcast is sent from this class: " +
                str(current_file) +
                ". These should not be used, as they provide no security (anyone can access them), no protection (anyone can modify them), and many other problems. For more info: http://developer.android.com/reference/android/content/Context.html"
            )
            issue.setFile(str(current_file))
            issue.setSeverity(Severity.VULNERABILITY)
            results.append(issue)

            issue = terminalPrint()
            issue.setLevel(Severity.VULNERABILITY)
            issue.setData(
                "A sticky broadcast is sent from this class: " +
                str(current_file) +
                ". These should not be used, as they provide no security (anyone can access them), no protection (anyone can modify them), and many other problems. For more info: http://developer.android.com/reference/android/content/Context.html"
            )
            results.append(issue)
        elif str(t.name) == 'sendStickyBroadcastAsUser':
            issue = ReportIssue()
            issue.setCategory(ExploitType.BROADCAST_INTENT)
            issue.setDetails(
                "A sticky user broadcast is sent from this class: " +
                str(current_file) +
                ". These should not be used, as they provide no security (anyone can access them), no protection (anyone can modify them), and many other problems. For more info: http://developer.android.com/reference/android/content/Context.html"
            )
            issue.setFile(str(current_file))
            issue.setSeverity(Severity.VULNERABILITY)
            results.append(issue)

            issue = terminalPrint()
            issue.setLevel(Severity.VULNERABILITY)
            issue.setData(
                "A sticky user broadcast is sent from this class: " +
                str(current_file) +
                ". These should not be used, as they provide no security (anyone can access them), no protection (anyone can modify them), and many other problems. For more info: http://developer.android.com/reference/android/content/Context.html"
            )
            results.append(issue)
        elif str(t.name) == 'sendStickyOrderedBroadcast':
            issue = ReportIssue()
            issue.setCategory(ExploitType.BROADCAST_INTENT)
            issue.setDetails(
                "A sticky ordered broadcast is sent from this class: " +
                str(current_file) +
                ". These should not be used, as they provide no security (anyone can access them), no protection (anyone can modify them), and many other problems. For more info: http://developer.android.com/reference/android/content/Context.html"
            )
            issue.setFile(str(current_file))
            issue.setSeverity(Severity.VULNERABILITY)
            results.append(issue)

            issue = terminalPrint()
            issue.setLevel(Severity.VULNERABILITY)
            issue.setData(
                "A sticky ordered broadcast is sent from this class: " +
                str(current_file) +
                ". These should not be used, as they provide no security (anyone can access them), no protection (anyone can modify them), and many other problems. For more info: http://developer.android.com/reference/android/content/Context.html"
            )
            results.append(issue)
        elif str(t.name) == 'sendStickyOrderedBroadcastAsUser':
            issue = ReportIssue()
            issue.setCategory(ExploitType.BROADCAST_INTENT)
            issue.setDetails(
                "A sticky ordered user broadcast is sent from this class: " +
                str(current_file) +
                ". These should not be used, as they provide no security (anyone can access them), no protection (anyone can modify them), and many other problems. For more info: http://developer.android.com/reference/android/content/Context.html"
            )
            issue.setFile(str(current_file))
            issue.setSeverity(Severity.VULNERABILITY)
            results.append(issue)

            issue = terminalPrint()
            issue.setLevel(Severity.VULNERABILITY)
            issue.setData(
                "A sticky ordered user broadcast is sent from this class: " +
                str(current_file) +
                ". These should not be used, as they provide no security (anyone can access them), no protection (anyone can modify them), and many other problems. For more info: http://developer.android.com/reference/android/content/Context.html"
            )
            results.append(issue)
        elif hasattr(t, '_fields'):
            for g in t._fields:
                recursiveBroadcastFinder(getattr(t, g), results)
    elif type(t) is list:
        for l in t:
            recursiveBroadcastFinder(l, results)
    elif hasattr(t, '_fields'):
        for f in t._fields:
            if type(getattr(t, f)) is not str:
                recursiveBroadcastFinder(getattr(t, f), results)
    return