Ejemplo n.º 1
0
def empty_intent(t, filename, results):
    if type(t) is m.MethodDeclaration:
        for x in method_list:
            if str(x) in str(t):
                fileBody = str(open(filename, 'r').read())
                for line in fileBody.splitlines():
                    for y in method_list:
                        if str(y) in str(line):
                            if "new Intent()" in str(line):
                                issue = ReportIssue()
                                issue.setCategory(ExploitType.INTENT)
                                issue.setDetails(
                                    "Empty Pending instance found in: " +
                                    str(filename) +
                                    ". For security reasons, the Intent you supply here should almost always be an explicit intent that is specify an explicit component to be delivered to through Intent.setClass. A malicious application could potentially intercept, redirect and/or modify this Intent. Pending Intents retain the UID of your application and all related permissions, allowing another application to act as yours. Reference: https://developer.android.com/reference/android/app/PendingIntent.html"
                                )
                                issue.setFile(filename)
                                issue.setSeverity(Severity.WARNING)
                                results.append(issue)

                                issue = terminalPrint()
                                issue.setLevel(Severity.WARNING)
                                issue.setData(
                                    "Empty Pending instance found in: " +
                                    str(filename) +
                                    ". For security reasons, the Intent you supply here should almost always be an explicit intent that is specify an explicit component to be delivered to through Intent.setClass. A malicious application could potentially intercept, redirect and/or modify this Intent. Pending Intents retain the UID of your application and all related permissions, allowing another application to act as yours. Reference: https://developer.android.com/reference/android/app/PendingIntent.html"
                                )
                                results.append(issue)
    return
Ejemplo n.º 2
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
Ejemplo n.º 3
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
Ejemplo n.º 4
0
def recursive_insecure_ssl_error_handling(t, filename, results):
    if type(t) is m.MethodDeclaration:
        if str(t.name) == 'onReceivedSslError':
            if "proceed" in str(t.body):
                issue = ReportIssue()
                issue.setCategory(ExploitType.CERTIFICATE)
                issue.setDetails("Unsafe implementation of onReceivedSslError handler found in: " + str(
                    filename) + ". Specifically, the implementation ignores all SSL certificate validation errors, making your app vulnerable to man-in-the-middle attacks. To properly handle SSL certificate validation, change your code to invoke SslErrorHandler.cancel(). For details, please see: https://developer.android.com/reference/android/webkit/WebViewClient.html")
                issue.setFile(filename)
                issue.setSeverity(Severity.WARNING)
                results.append(issue)

                issue = terminalPrint()
                issue.setLevel(Severity.WARNING)
                issue.setData("Unsafe implementation of onReceivedSslError handler found in: " + str(
                    filename) + ". Specifically, the implementation ignores all SSL certificate validation errors, making your app vulnerable to man-in-the-middle attacks. To properly handle SSL certificate validation, change your code to invoke SslErrorHandler.cancel(). For details, please see: https://developer.android.com/reference/android/webkit/WebViewClient.html")
                results.append(issue)

    elif type(t) is list:
        for x in t:
            recursive_insecure_ssl_error_handling(x, filename, results)
    elif hasattr(t, '_fields'):
        for f in t._fields:
            recursive_insecure_ssl_error_handling(getattr(t, f), filename, results)
    return
Ejemplo n.º 5
0
def recursive_insecure_ssl_error_handling(t, filename, results):
    if type(t) is m.MethodDeclaration:
        if str(t.name) == 'onReceivedSslError':
            if "proceed" in str(t.body):
                issue = ReportIssue()
                issue.setCategory(ExploitType.CERTIFICATE)
                issue.setDetails(
                    "Unsafe implementation of onReceivedSslError handler found in: "
                    + str(filename) +
                    ". Specifically, the implementation ignores all SSL certificate validation errors, making your app vulnerable to man-in-the-middle attacks. To properly handle SSL certificate validation, change your code to invoke SslErrorHandler.cancel(). For details, please see: https://developer.android.com/reference/android/webkit/WebViewClient.html"
                )
                issue.setFile(filename)
                issue.setSeverity(Severity.WARNING)
                results.append(issue)

                issue = terminalPrint()
                issue.setLevel(Severity.WARNING)
                issue.setData(
                    "Unsafe implementation of onReceivedSslError handler found in: "
                    + str(filename) +
                    ". Specifically, the implementation ignores all SSL certificate validation errors, making your app vulnerable to man-in-the-middle attacks. To properly handle SSL certificate validation, change your code to invoke SslErrorHandler.cancel(). For details, please see: https://developer.android.com/reference/android/webkit/WebViewClient.html"
                )
                results.append(issue)

    elif type(t) is list:
        for x in t:
            recursive_insecure_ssl_error_handling(x, filename, results)
    elif hasattr(t, '_fields'):
        for f in t._fields:
            recursive_insecure_ssl_error_handling(getattr(t, f), filename,
                                                  results)
    return
Ejemplo n.º 6
0
def parse_args(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 find_class(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 parse_args")
                        except Exception as e:
                            report.write("parsingerror-issues-list", str(current_file), "strong")
                            common.logger.debug("Problem in find_class 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:
                find_intent(arg.value, results)
            except Exception as e:
                report.write("parsingerror-issues-list", str(current_file), "strong")
                common.logger.debug("Problem in find_intent 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
Ejemplo n.º 7
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
Ejemplo n.º 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
Ejemplo n.º 9
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
Ejemplo n.º 10
0
def empty_intent(t, filename, results):
    if type(t) is m.MethodDeclaration:
        for x in method_list:
            if str(x) in str(t):
                fileBody = str(open(filename, 'r').read())
                for line in fileBody.splitlines():
                    for y in method_list:
                        if str(y) in str(line):
                            if "new Intent()" in str(line):
                                issue = ReportIssue()
                                issue.setCategory(ExploitType.CERTIFICATE)
                                issue.setDetails("Empty Pending instance found in: " + str(
                                    filename) + ". For security reasons, the Intent you supply here should almost always be an explicit intent that is specify an explicit component to be delivered to through Intent.setClass. A malicious application could potentially intercept, redirect and/or modify this Intent. Pending Intents retain the UID of your application and all related permissions, allowing another application to act as yours. Reference: https://developer.android.com/reference/android/app/PendingIntent.html")
                                issue.setFile(filename)
                                issue.setSeverity(Severity.WARNING)
                                results.append(issue)

                                issue = terminalPrint()
                                issue.setLevel(Severity.WARNING)
                                issue.setData("Empty Pending instance found in: " + str(
                                    filename) + ". For security reasons, the Intent you supply here should almost always be an explicit intent that is specify an explicit component to be delivered to through Intent.setClass. A malicious application could potentially intercept, redirect and/or modify this Intent. Pending Intents retain the UID of your application and all related permissions, allowing another application to act as yours. Reference: https://developer.android.com/reference/android/app/PendingIntent.html")
                                results.append(issue)
    return
Ejemplo n.º 11
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
Ejemplo n.º 12
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
Ejemplo n.º 13
0
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
Ejemplo n.º 14
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
Ejemplo n.º 15
0
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
Ejemplo n.º 16
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
Ejemplo n.º 17
0
def main(queue):
    global parser
    global tree
    results = []
    count = 0

    if common.minSdkVersion < 19:
        weak_rng_warning(results)
    find_key_files(results)
    for j in common.java_files:
        count = count + 1
        pub.sendMessage('progress', bar='Crypto issues', percent=round(count * 100 / common.java_files.__len__()))
        try:
            tree = parser.parse_file(j)
            if tree is not None:
                # if re.search(r'\.getInstance\(',str(tree)):
                #	print "YES"
                for type_decl in tree.type_declarations:
                    if type(type_decl) is m.ClassDeclaration:
                        for t in type_decl.body:
                            try:
                                recursive_ecb_check(t, j, results)
                            # fixedSeedCheck(t,j)
                            except Exception as e:
                                common.logger.debug("Error running recursive_ecb_check in cryptoFlaws.py: " + str(e))
                                report.write("parsingerror-issues-list",
                                             "Error running recursive_ecb_check in cryptoFlaws.py: " + str(e), "strong")

                            # Using a fixed seed with SecureRandom
                for import_decl in tree.import_declarations:
                    try:
                        if 'SecureRandom' in import_decl.name.value:
                            if "setSeed" in str(tree):
                                issue = ReportIssue()
                                issue.setCategory(ExploitType.CRYPTO)
                                issue.setDetails(
                                    "setSeed should not be called with SecureRandom, as it is insecure. Specifying a fixed seed will cause the instance to return a predictable sequence of numbers. This may be useful for testing but it is not appropriate for secure use.")
                                issue.setFile(str(j))
                                issue.setSeverity(Severity.VULNERABILITY)
                                results.append(issue)

                                issue = terminalPrint()
                                issue.setLevel(Severity.VULNERABILITY)
                                issue.setData(
                                    "setSeed should not be called with SecureRandom, as it is insecure. Specifying a fixed seed will cause the instance to return a predictable sequence of numbers. This may be useful for testing but it is not appropriate for secure use.")
                                results.append(issue)

                            if "generateSeed" in str(tree):
                                issue = ReportIssue()
                                issue.setCategory(ExploitType.CRYPTO)
                                issue.setDetails(
                                    "generateSeed should not be called with SecureRandom, as it is insecure. Specifying a fixed seed will cause the instance to return a predictable sequence of numbers. This may be useful for testing but it is not appropriate for secure use.")
                                issue.setFile(str(j))
                                issue.setSeverity(Severity.VULNERABILITY)
                                results.append(issue)

                                issue = terminalPrint()
                                issue.setLevel(Severity.VULNERABILITY)
                                issue.setData(
                                    "generateSeed should not be called with SecureRandom, as it is insecure. Specifying a fixed seed will cause the instance to return a predictable sequence of numbers. This may be useful for testing but it is not appropriate for secure use. ")
                                results.append(issue)
                    except Exception as e:
                        common.logger.debug("Error checking insecure used of SecureRandom in cryptoFlaws.py: " + str(e))
                        report.write("parsingerror-issues-list",
                                     "Error checking insecure used of SecureRandom in cryptoFlaws.py: " + str(e))

        except Exception as e:
            common.logger.debug("Unable to create tree for " + str(j))
            report.write("parsingerror-issues-list", "Unable to create tree for " + str(j), "strong")
    queue.put(results)
    return
Ejemplo n.º 18
0
def find_intent(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 find_intent - 1")
                                            elif type(getattr(t, f)) is m.MethodInvocation:
                                                common.logger.debug("ERROR: UNEXPECTED CODE PATH in find_intent - 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
Ejemplo n.º 19
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
Ejemplo n.º 20
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
Ejemplo n.º 21
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
Ejemplo n.º 22
0
def find_intent(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 find_intent - 1"
                                                            )
                                            elif type(getattr(
                                                    t,
                                                    f)) is m.MethodInvocation:
                                                common.logger.debug(
                                                    "ERROR: UNEXPECTED CODE PATH in find_intent - 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