def validate(queue): results = [] wv_dec_list = find_webviews() #remove empty list items wv_dec_list = filter(None, wv_dec_list) #remove duplicates #Need to check why duplicates would even occur, may lead to false negatives wv_dec_list = common.dedup(wv_dec_list) issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData("FOUND " + str(len(wv_dec_list)) + " WEBVIEWS:") results.append(issue) #BUG IN OUTPUT for p in wv_dec_list: issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData(str(p)) results.append(issue) #logger.info(str(p)) #print "\n" #search for WebView configuration settings wv_decs = find_wv_settings_dec(wv_dec_list, results) queue.put(results) return
def validate(queue): results = [] wv_dec_list=find_webviews() #remove empty list items wv_dec_list=filter(None,wv_dec_list) #remove duplicates #Need to check why duplicates would even occur, may lead to false negatives wv_dec_list=common.dedup(wv_dec_list) issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData("FOUND " + str(len(wv_dec_list)) + " WEBVIEWS:") results.append(issue) #BUG IN OUTPUT for p in wv_dec_list: issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData(str(p)) results.append(issue) #logger.info(str(p)) #print "\n" #search for WebView configuration settings wv_decs=find_wv_settings_dec(wv_dec_list, results) queue.put(results) return
def recursive_insecure_trust_manager(t, filename, results): if type(t) is m.MethodDeclaration: if str(t.name) == 'checkServerTrusted': if len(t.body) == 0: issue = ReportIssue() issue.setCategory(ExploitType.CERTIFICATE) issue.setDetails( "Instance of checkServerTrusted, with no body found in: " + str(filename) + ". This means this application is likely vulnerable to Man-In-The-Middle attacks. This can be confirmed using the free version of Burpsuite. Simply set the Android device's proxy to use Burpsuite via the network settings, but DO NOT install the Portswigger CA certificate on the device. If you still see traffic in the proxy, the app is vulnerable. Note: You need to ensure you exercise this code path. If you are unsure, make sure you click through each part of the application which makes network requests. You may need to toggle the proxy on/off to get past sections that do validate certificates properly in order to reach the vulnerable code. This proves that it will accept certificates from any CA. You should always validate your configuration by visiting an HTTPS site in the native browser and verifying you receive a certificate warning. For details, please see: https://developer.android.com/training/articles/security-ssl.html" ) issue.setFile(filename) issue.setSeverity(Severity.WARNING) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData( "Instance of checkServerTrusted, with no body found in: " + str(filename) + ". This means this application is likely vulnerable to Man-In-The-Middle attacks. This can be confirmed using the free version of Burpsuite. Simply set the Android device's proxy to use Burpsuite via the network settings, but DO NOT install the Portswigger CA certificate on the device. If you still see traffic in the proxy, the app is vulnerable. Note: You need to ensure you exercise this code path. If you are unsure, make sure you click through each part of the application which makes network requests. You may need to toggle the proxy on/off to get past sections that do validate certificates properly in order to reach the vulnerable code. This proves that it will accept certificates from any CA. You should always validate your configuration by visiting an HTTPS site in the native browser and verifying you receive a certificate warning. For details, please see: https://developer.android.com/training/articles/security-ssl.html" ) results.append(issue) else: for b in t.body: if type(b) is m.Return: #TODO - This needs to be fleshed out more, but it will have to wait due to time constraints issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData( "Instance of checkServerTrusted, which only returns " + str(filename) + ". This means this application is likely vulnerable to Man-In-The-Middle attacks. This can be confirmed using the free version of Burpsuite. Simply set the Android device's proxy to use Burpsuite via the network settings, but DO NOT install the Portswigger CA certificate on the device. If you still see traffic in the proxy, the app is vulnerable. Note: You need to ensure you excercise this code path. If you are unsure, make sure you click through each part of the application which makes network requests. You may need to toggle the proxy on/off to get past sections that do validate certificates properly in order to reach the vulnerable code. This proves that it will accept certitificates from any CA. You should always validate your configuration by visiting an HTTPS site in the native browser and verifying you receive a certificate warning. For details, please see: https://developer.android.com/training/articles/security-ssl.html" ) results.append(issue) issue = ReportIssue() issue.setCategory(ExploitType.CERTIFICATE) issue.setDetails( "Instance of checkServerTrusted, which only returns " + str(filename) + ". This means this application is likely vulnerable to Man-In-The-Middle attacks. This can be confirmed using the free version of Burpsuite. Simply set the Android device's proxy to use Burpsuite via the network settings, but DO NOT install the Portswigger CA certificate on the device. If you still see traffic in the proxy, the app is vulnerable. Note: You need to ensure you excercise this code path. If you are unsure, make sure you click through each part of the application which makes network requests. You may need to toggle the proxy on/off to get past sections that do validate certificates properly in order to reach the vulnerable code. This proves that it will accept certitificates from any CA. You should always validate your configuration by visiting an HTTPS site in the native browser and verifying you receive a certificate warning. For details, please see: https://developer.android.com/training/articles/security-ssl.html" ) issue.setFile(filename) issue.setSeverity(Severity.WARNING) results.append(issue) else: break #TODO - only want to check once, to see if it's only a return, can probably be replaced by len() elif type(t) is list: for x in t: recursive_insecure_trust_manager(x, filename, results) elif hasattr(t, '_fields'): for f in t._fields: recursive_insecure_trust_manager(getattr(t, f), filename, results) return
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
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
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
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
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
def unverified_sessions(results): global sslSessions #This is untested because I could not find a vulnerable app, which didn't have a custom .verify method for s in sslSessions: issue = ReportIssue() issue.setCategory(ExploitType.CERTIFICATE) issue.setDetails("Potential Man-In-The-Middle vulnerability - There appear to be SSLSession (boolean) objects which are not checked using the HostnameVerifier.verify method. You should manually inspect these in: " + str(filename) + ". Please see this URL for details: https://developer.android.com/training/articles/security-ssl.html") issue.setSeverity(Severity.WARNING) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData("Potential Man-In-The-Middle vulnerability - There appear to be SSLSession (boolean) objects which are not checked using the HostnameVerifier.verify method. You should manually inspect these in: " + str(filename) + ". Please see this URL for details: https://developer.android.com/training/articles/security-ssl.html") results.append(issue) sslSessions=[] return
def unverified_sessions(results): global sslSessions #This is untested because I could not find a vulnerable app, which didn't have a custom .verify method for s in sslSessions: issue = ReportIssue() issue.setCategory(ExploitType.CERTIFICATE) issue.setDetails( "Potential Man-In-The-Middle vulnerability - There appear to be SSLSession (boolean) objects which are not checked using the HostnameVerifier.verify method. You should manually inspect these in: " + str(filename) + ". Please see this URL for details: https://developer.android.com/training/articles/security-ssl.html" ) issue.setSeverity(Severity.WARNING) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData( "Potential Man-In-The-Middle vulnerability - There appear to be SSLSession (boolean) objects which are not checked using the HostnameVerifier.verify method. You should manually inspect these in: " + str(filename) + ". Please see this URL for details: https://developer.android.com/training/articles/security-ssl.html" ) results.append(issue) sslSessions = [] return
def default_wv_config(wv, srcfile, sdk_ver,results): """ Finds default webview configurations """ #BUG - I believe we can remove the sdk_ver parameter here and use common.minSdk #BUG - Using common.minSdkVersion in comparisons fails to be evaluated properly issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData("WEBVIEW DEFAULTS DO NOT APPEAR TO BE OVERRIDDEN-DISPLAYING DEFAULTS:") results.append(issue) if sdk_ver<19: issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData(common.config.get('qarkhelper','WEBVIEW_SOP_WARNING')) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData(common.config.get('qarkhelper', 'JS_OK')) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData(common.config.get('qarkhelper', 'BURL_OK')) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData(common.config.get('qarkhelper', 'FILE_SYS_WARN1') + common.config.get('qarkhelper', 'FILE_SYS_WARN2') + " To validate this vulnerability, load the following url in this WebView: http://www.secbro.com/poc/html/FILE_SYS_WARN.html." + "Note: A local copy of this html file can also be found at <install_dir>/quark/poc/html/FILE_SYS_WARN.html") results.append(issue) issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData(common.config.get('qarkhelper', 'WV_CPA_WARNING') + " To validate this vulnerability, load the following url in this WebView: http://www.secbro.com/poc/html/WV_CPA_WARNING.html" + "Note: A local copy of this html file can also be found at <install_dir>/quark/poc/html/WV_CPA_WARNING.html") results.append(issue) if sdk_ver < 16: #minSdk <= 15 default is true; minSdk > 16 default is false issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData(common.config.get('qarkhelper', 'UNIV_FILE_WARNING') + " To validate this vulnerability, load the following url in this WebView: http://www.secbro.com/poc/html/UNIV_FILE_WARNING.html" + "Note: A local copy of this html file can also be found at <install_dir>/quark/poc/html/UNIV_FILE_WARNING.html") results.append(issue) #BUG - Need to double-check this, it doesn't appear to follow the same logic as the non-default checks if sdk_ver <16: issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData(common.config.get('qarkhelper', 'FURL_FILE_WARNING') + " To validate this vulnerability, load the following url in this WebView: http://www.secbro.com/poc/html/FURL_FILE_WARNING.html" + "Note: A local copy of this html file can also be found at <install_dir>/quark/poc/html/FURL_FILE_WARNING.html") results.append(issue) else: issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData(common.config.get('qarkhelper', 'FURL_FILE_OK')) results.append(issue) else: issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData(common.config.get('qarkhelper', 'UNIV_FILE_OK')) results.append(issue) skip_next=False #checking previous value above, as this is ignored if the above is true if sdk_ver < 18: issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData(common.config.get('qarkhelper', 'DEPRECATED_SINCE_9')) results.append(issue) else: issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData(common.config.get('qarkhelper', 'REMOVED_IN_18')) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData(common.config.get('qarkhelper', 'NO_JS_INT')) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData(common.config.get('qarkhelper', 'DOM_STORAGE_DIS')) results.append(issue) # TODO - Am I missing anything??? return
def recursive_allow_all_hostname_verifier(t, filename, results): #TODO - This can be fleshed out to be more of an accurate, exhaustive check, but will suffice for now if type(t) is m.Assignment: if type(t.rhs) is m.InstanceCreation: if hasattr(t.rhs, 'type'): if hasattr(t.rhs.type, 'name'): if hasattr(t.rhs.type.name, 'value'): if str(t.rhs.type.name.value ) == 'AllowAllHostnameVerifier': #TODO - The list below will eventually be used to check the code for bad verifiers, but will wait for now, due to time constraints if hasattr(t.lhs, 'value'): issue = ReportIssue() issue.setCategory(ExploitType.CERTIFICATE) issue.setDetails( "AllowAllHostnameVerifier: " + str(t.lhs.value) + " found in " + str(filename) + ". This can allow for impromper x.509 certificate validation wherein the DNS hostname does not match the Common or Subject Alternative Name(s) on the certificate, making the application vulnerable to Man-In-The-Middle attacks. This means the application may potentially accept a certificate from any trusted CA, regardless of the domain it was issued for. The can be validated using the free version of Burpsuite by installing the Portswigger CA certificate, thereby making it a trusted CA on the device. Set the device network settings to use the Burpsuite proxy, then go Proxy > Options > Edit the Proxy Listener by changing the Certificate tab to Generate a CA-signed certificate with a specific hostname and enter a domain like foobar.com which doesn't match the domain name(s) the app is connecting to normally. You should always verify your results by visiting an https site in the native browser and confirming you see a certificate warning. For details, please see: https://developer.android.com/training/articles/security-ssl.html" ) issue.setFile(filename) issue.setSeverity(Severity.WARNING) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData( "AllowAllHostnameVerifier: " + str(t.lhs.value) + " found in " + str(filename) + ". This can allow for impromper x.509 certificate validation wherein the DNS hostname does not match the Common or Subject Alternative Name(s) on the certificate, making the application vulnerable to Man-In-The-Middle attacks. This means the application may potentially accept a certificate from any trusted CA, regardless of the domain it was issued for. The can be validated using the free version of Burpsuite by installing the Portswigger CA certificate, thereby making it a trusted CA on the device. Set the device network settings to use the Burpsuite proxy, then go Proxy > Options > Edit the Proxy Listener by changing the Certificate tab to Generate a CA-signed certificate with a specific hostname and enter a domain like foobar.com which doesn't match the domain name(s) the app is connecting to normally. You should always verify your results by visiting an https site in the native browser and confirming you see a certificate warning. For details, please see: https://developer.android.com/training/articles/security-ssl.html" ) results.append(issue) elif type(t) is m.MethodInvocation: if hasattr(t, 'name'): if str(t.name) == 'setHostnameVerifier': if hasattr(t, 'arguments'): for a in t.arguments: if type(a) is m.Name: if hasattr(a, 'value'): if re.search(r'\.ALLOW_ALL_HOSTNAME_VERIFIER$', str(a.value)): issue = ReportIssue() issue.setCategory(ExploitType.CERTIFICATE) issue.setDetails( "ALLOW_ALL_HOSTNAME_VERIFIER invoked : " + str(a.value) + " in " + str(filename) + ". This can allow for impromper x.509 certificate validation wherein the DNS hostname does not match the Common or Subject Alternative Name(s) on the certificate, making the application vulnerable to Man-In-The-Middle attacks. This means the application may potentially accept a certificate from any trusted CA, regardless of the domain it was issued for. The can be validated using the free version of Burpsuite by installing the Portswigger CA certificate, thereby making it a trusted CA on the device. Set the device network settings to use the Burpsuite proxy, then go Proxy > Options > Edit the Proxy Listener by changing the Certificate tab to Generate a CA-signed certificate with a specific hostname and enter a domain like foobar.com which doesn't match the domain name(s) the app is connecting to normally. You should always verify your results by visiting an https site in the native browser and confirming you see a certificate warning. For details, please see: https://developer.android.com/training/articles/security-ssl.html" ) issue.setFile(filename) issue.setSeverity(Severity.WARNING) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData( "ALLOW_ALL_HOSTNAME_VERIFIER invoked : " + str(a.value) + " in " + str(filename) + ". This can allow for impromper x.509 certificate validation wherein the DNS hostname does not match the Common or Subject Alternative Name(s) on the certificate, making the application vulnerable to Man-In-The-Middle attacks. This means the application may potentially accept a certificate from any trusted CA, regardless of the domain it was issued for. The can be validated using the free version of Burpsuite by installing the Portswigger CA certificate, thereby making it a trusted CA on the device. Set the device network settings to use the Burpsuite proxy, then go Proxy > Options > Edit the Proxy Listener by changing the Certificate tab to Generate a CA-signed certificate with a specific hostname and enter a domain like foobar.com which doesn't match the domain name(s) the app is connecting to normally. You should always verify your results by visiting an https site in the native browser and confirming you see a certificate warning. For details, please see: https://developer.android.com/training/articles/security-ssl.html" ) results.append(issue) elif type(t) is list: for x in t: recursive_allow_all_hostname_verifier(x, filename, results) elif hasattr(t, '_fields'): for f in t._fields: recursive_allow_all_hostname_verifier(getattr(t, f), filename, results) return
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
def recursive_broadcast_finder(t, results): if type(t) is m.MethodDeclaration: if str(t.name) == 'sendBroadcast': common.logger.debug( "It appears the sendBroadcast method may be overridden in this class. The following findings for this class may be false positives" ) if str(t.name) == 'sendBroadcastAsUser': common.logger.debug( "It appears the sendBroadcastAsUser method may be overridden in this class. The following findings for this class may be false positives" ) if str(t.name) == 'sendOrderedBroadcast': common.logger.debug( "It appears the sendOrderedBroadcast method may be overridden in this class. The following findings for this class may be false positives" ) if str(t.name) == 'sendOrderedBroadcastAsUser': common.logger.debug( "It appears the sendOrderedBroadcastAsUser method may be overridden in this class. The following findings for this class may be false positives" ) if str(t.name) == 'sendStickyBroadcast': common.logger.debug( "It appears the sendStickyBroadcast method may be overridden in this class. The following findings for this class may be false positives" ) if str(t.name) == 'sendStickyBroadcastAsUser': common.logger.debug( "It appears the sendStickyBroadcastAsUser method may be overridden in this class. The following findings for this class may be false positives" ) if str(t.name) == 'sendStickyOrderedBroadcast': common.logger.debug( "It appears the sendStickyOrderedBroadcast method may be overridden in this class. The following findings for this class may be false positives" ) if str(t.name) == 'sendStickyOrderedBroadcastAsUser': common.logger.debug( "It appears the sendStickyOrderedBroadcastAsUser method may be overridden in this class. The following findings for this class may be false positives" ) if type(t) is m.MethodInvocation: if str(t.name) == 'sendBroadcast': if len(t.arguments) == 1: #We need to ensure this isn't a local broadcast #TODO - There is a lot more we need to do to fully qualify this, but should be good enough for now if local_broadcast_manager_imported() == True: common.logger.debug(tree) else: report.write_badger("manifest-issues", modules.common.Severity.INFO, "NO IMPORT") common.logger.debug("FOUND A sendBroadcast") issue = ReportIssue() issue.setCategory(ExploitType.BROADCAST_INTENT) issue.setDetails( "A broadcast is sent from this class: " + str(current_file) + ", which does not specify the receiverPermission. This means any application on the device can receive this broadcast. You should investigate this for potential data leakage." ) issue.setFile(str(current_file)) issue.setSeverity(Severity.WARNING) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData( "A broadcast is sent from this class: " + str(current_file) + ", which does not specify the receiverPermission. This means any application on the device can receive this broadcast. You should investigate this for potential data leakage." ) results.append(issue) elif len(t.arguments) == 2: if common.minSdkVersion < 21: issue = ReportIssue() issue.setCategory(ExploitType.BROADCAST_INTENT) issue.setDetails( "A broadcast is sent from this class: " + str(current_file) + ", which specifies the receiverPermission, but may still be vulnerable to interception, due to the permission squatting vulnerability in API levels before 21. This means any application, installed prior to the expected receiver(s) on the device can potentially receive this broadcast. You should investigate this for potential data leakage." ) issue.setFile(str(current_file)) issue.setSeverity(Severity.WARNING) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData( "A broadcast is sent from this class: " + str(current_file) + ", which specifies the receiverPermission, but may still be vulnerable to interception, due to the permission squatting vulnerability in API levels before 21. This means any application, installed prior to the expected receiver(s) on the device can potentially receive this broadcast. You should investigate this for potential data leakage." ) results.append(issue) else: issue = ReportIssue() issue.setCategory(ExploitType.BROADCAST_INTENT) issue.setDetails( "A broadcast is sent from this class: " + str(current_file) + ", which specifies the receiverPermission, but depending on the protection level of the permission (on the receiving app side), may still be vulnerable to interception, if the protection level of the permission is not set to signature or signatureOrSystem. You should investigate this for potential data leakage." ) issue.setFile(str(current_file)) issue.setSeverity(Severity.WARNING) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData( "A broadcast is sent from this class: " + str(current_file) + ", which specifies the receiverPermission, but depending on the protection level of the permission (on the receiving app side), may still be vulnerable to interception, if the protection level of the permission is not set to signature or signatureOrSystem. You should investigate this for potential data leakage." ) results.append(issue) elif str(t.name) == 'sendBroadcastAsUser': if len(t.arguments) == 2: issue = ReportIssue() issue.setCategory(ExploitType.BROADCAST_INTENT) issue.setDetails( "A broadcast, as a specific user, is sent from this class: " + str(current_file) + ", which does not specify the receiverPermission. This means any application on the device can receive this broadcast. You should investigate this for potential data leakage." ) issue.setFile(str(current_file)) issue.setSeverity(Severity.WARNING) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData( "A broadcast, as a specific user, is sent from this class: " + str(current_file) + ", which does not specify the receiverPermission. This means any application on the device can receive this broadcast. You should investigate this for potential data leakage." ) results.append(issue) elif len(t.arguments) == 3: if common.minSdkVersion < 21: issue = ReportIssue() issue.setCategory(ExploitType.BROADCAST_INTENT) issue.setDetails( "A broadcast, as a specific user, is sent from this class: " + str(current_file) + ", which specifies the receiverPermission, but may still be vulnerable to interception, due to the permission squatting vulnerability in API levels before 21. This means any application, installed prior to the expected receiver(s) on the device can potentially receive this broadcast. You should investigate this for potential data leakage." ) issue.setFile(str(current_file)) issue.setSeverity(Severity.WARNING) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData( "A broadcast, as a specific user, is sent from this class: " + str(current_file) + ", which specifies the receiverPermission, but may still be vulnerable to interception, due to the permission squatting vulnerability in API levels before 21. This means any application, installed prior to the expected receiver(s) on the device can potentially receive this broadcast. You should investigate this for potential data leakage." ) results.append(issue) else: issue = ReportIssue() issue.setCategory(ExploitType.BROADCAST_INTENT) issue.setDetails( "A broadcast, as a specific user, is sent from this class: " + str(current_file) + ", which specifies the receiverPermission, but depending on the protection level of the permission (on the receiving app side), may still be vulnerable to interception, if the protection level of the permission is not set to signature or signatureOrSystem. You should investigate this for potential data leakage." ) issue.setFile(str(current_file)) issue.setSeverity(Severity.WARNING) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData( "A broadcast, as a specific user, is sent from this class: " + str(current_file) + ", which specifies the receiverPermission, but depending on the protection level of the permission (on the receiving app side), may still be vulnerable to interception, if the protection level of the permission is not set to signature or signatureOrSystem. You should investigate this for potential data leakage." ) results.append(issue) elif str(t.name) == 'sendOrderedBroadcast': if ((len(t.arguments) == 2) or (len(t.arguments) == 7)): if common.minSdkVersion < 21: issue = ReportIssue() issue.setCategory(ExploitType.BROADCAST_INTENT) issue.setDetails( "An ordered broadcast, as a specific user, is sent from this class: " + str(current_file) + ", which specifies the receiverPermission, but may still be vulnerable to interception, due to the permission squatting vulnerability in API levels before 21. This means any application, installed prior to the expected receiver(s) on the device can potentially receive this broadcast. You should investigate this for potential data leakage." ) issue.setFile(str(current_file)) issue.setSeverity(Severity.WARNING) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData( "An ordered broadcast, as a specific user, is sent from this class: " + str(current_file) + ", which specifies the receiverPermission, but may still be vulnerable to interception, due to the permission squatting vulnerability in API levels before 21. This means any application, installed prior to the expected receiver(s) on the device can potentially receive this broadcast. You should investigate this for potential data leakage." ) results.append(issue) else: issue = ReportIssue() issue.setCategory(ExploitType.BROADCAST_INTENT) issue.setDetails( "An ordered broadcast, as a specific user, is sent from this class: " + str(current_file) + ", which specifies the receiverPermission, but may still be vulnerable to interception, due to the permission squatting vulnerability in API levels before 21. This means any application, installed prior to the expected receiver(s) on the device can potentially receive this broadcast. You should investigate this for potential data leakage." ) issue.setFile(str(current_file)) issue.setSeverity(Severity.WARNING) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData( "An ordered broadcast, as a specific user, is sent from this class: " + str(current_file) + ", which specifies the receiverPermission, but may still be vulnerable to interception, due to the permission squatting vulnerability in API levels before 21. This means any application, installed prior to the expected receiver(s) on the device can potentially receive this broadcast. You should investigate this for potential data leakage." ) results.append(issue) elif str(t.name) == 'sendOrderedBroadcastAsUser': if len(t.arguments) == 7: if common.minSdkVersion < 21: issue = ReportIssue() issue.setCategory(ExploitType.BROADCAST_INTENT) issue.setDetails( "An ordered broadcast, as a specific user, is sent from this class: " + str(current_file) + ", which specifies the receiverPermission, but may still be vulnerable to interception, due to the permission squatting vulnerability in API levels before 21. This means any application, installed prior to the expected receiver(s) on the device can potentially receive this broadcast. You should investigate this for potential data leakage." ) issue.setFile(str(current_file)) issue.setSeverity(Severity.WARNING) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData( "An ordered broadcast, as a specific user, is sent from this class: " + str(current_file) + ", which specifies the receiverPermission, but may still be vulnerable to interception, due to the permission squatting vulnerability in API levels before 21. This means any application, installed prior to the expected receiver(s) on the device can potentially receive this broadcast. You should investigate this for potential data leakage." ) results.append(issue) else: issue = ReportIssue() issue.setCategory(ExploitType.BROADCAST_INTENT) issue.setDetails( "An ordered broadcast, as a specific user, is sent from this class: " + str(current_file) + ", which specifies the receiverPermission, but depending on the protection level of the permission (on the receiving app side), may still be vulnerable to interception, if the protection level of the permission is not set to signature or signatureOrSystem. You should investigate this for potential data leakage." ) issue.setFile(str(current_file)) issue.setSeverity(Severity.WARNING) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData( "An ordered broadcast, as a specific user, is sent from this class: " + str(current_file) + ", which specifies the receiverPermission, but depending on the protection level of the permission (on the receiving app side), may still be vulnerable to interception, if the protection level of the permission is not set to signature or signatureOrSystem. You should investigate this for potential data leakage." ) results.append(issue) elif str(t.name) == 'sendStickyBroadcast': issue = ReportIssue() issue.setCategory(ExploitType.BROADCAST_INTENT) issue.setDetails( "A sticky broadcast is sent from this class: " + str(current_file) + ". These should not be used, as they provide no security (anyone can access them), no protection (anyone can modify them), and many other problems. For more info: http://developer.android.com/reference/android/content/Context.html" ) issue.setFile(str(current_file)) issue.setSeverity(Severity.VULNERABILITY) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.VULNERABILITY) issue.setData( "A sticky broadcast is sent from this class: " + str(current_file) + ". These should not be used, as they provide no security (anyone can access them), no protection (anyone can modify them), and many other problems. For more info: http://developer.android.com/reference/android/content/Context.html" ) results.append(issue) elif str(t.name) == 'sendStickyBroadcastAsUser': issue = ReportIssue() issue.setCategory(ExploitType.BROADCAST_INTENT) issue.setDetails( "A sticky user broadcast is sent from this class: " + str(current_file) + ". These should not be used, as they provide no security (anyone can access them), no protection (anyone can modify them), and many other problems. For more info: http://developer.android.com/reference/android/content/Context.html" ) issue.setFile(str(current_file)) issue.setSeverity(Severity.VULNERABILITY) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.VULNERABILITY) issue.setData( "A sticky user broadcast is sent from this class: " + str(current_file) + ". These should not be used, as they provide no security (anyone can access them), no protection (anyone can modify them), and many other problems. For more info: http://developer.android.com/reference/android/content/Context.html" ) results.append(issue) elif str(t.name) == 'sendStickyOrderedBroadcast': issue = ReportIssue() issue.setCategory(ExploitType.BROADCAST_INTENT) issue.setDetails( "A sticky ordered broadcast is sent from this class: " + str(current_file) + ". These should not be used, as they provide no security (anyone can access them), no protection (anyone can modify them), and many other problems. For more info: http://developer.android.com/reference/android/content/Context.html" ) issue.setFile(str(current_file)) issue.setSeverity(Severity.VULNERABILITY) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.VULNERABILITY) issue.setData( "A sticky ordered broadcast is sent from this class: " + str(current_file) + ". These should not be used, as they provide no security (anyone can access them), no protection (anyone can modify them), and many other problems. For more info: http://developer.android.com/reference/android/content/Context.html" ) results.append(issue) elif str(t.name) == 'sendStickyOrderedBroadcastAsUser': issue = ReportIssue() issue.setCategory(ExploitType.BROADCAST_INTENT) issue.setDetails( "A sticky ordered user broadcast is sent from this class: " + str(current_file) + ". These should not be used, as they provide no security (anyone can access them), no protection (anyone can modify them), and many other problems. For more info: http://developer.android.com/reference/android/content/Context.html" ) issue.setFile(str(current_file)) issue.setSeverity(Severity.VULNERABILITY) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.VULNERABILITY) issue.setData( "A sticky ordered user broadcast is sent from this class: " + str(current_file) + ". These should not be used, as they provide no security (anyone can access them), no protection (anyone can modify them), and many other problems. For more info: http://developer.android.com/reference/android/content/Context.html" ) results.append(issue) elif hasattr(t, '_fields'): for g in t._fields: recursive_broadcast_finder(getattr(t, g), results) elif type(t) is list: for l in t: recursive_broadcast_finder(l, results) elif hasattr(t, '_fields'): for f in t._fields: if type(getattr(t, f)) is not str: recursive_broadcast_finder(getattr(t, f), results) return
def default_wv_config(wv, srcfile, sdk_ver, results): """ Finds default webview configurations """ #BUG - I believe we can remove the sdk_ver parameter here and use common.minSdk #BUG - Using common.minSdkVersion in comparisons fails to be evaluated properly issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData( "WEBVIEW DEFAULTS DO NOT APPEAR TO BE OVERRIDDEN-DISPLAYING DEFAULTS:") results.append(issue) if sdk_ver < 19: issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData(common.config.get('qarkhelper', 'WEBVIEW_SOP_WARNING')) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData(common.config.get('qarkhelper', 'JS_OK')) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData(common.config.get('qarkhelper', 'BURL_OK')) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData( common.config.get('qarkhelper', 'FILE_SYS_WARN1') + common.config.get('qarkhelper', 'FILE_SYS_WARN2') + " To validate this vulnerability, load the following url in this WebView: http://www.secbro.com/poc/html/FILE_SYS_WARN.html." + "Note: A local copy of this html file can also be found at <install_dir>/quark/poc/html/FILE_SYS_WARN.html" ) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData( common.config.get('qarkhelper', 'WV_CPA_WARNING') + " To validate this vulnerability, load the following url in this WebView: http://www.secbro.com/poc/html/WV_CPA_WARNING.html" + "Note: A local copy of this html file can also be found at <install_dir>/quark/poc/html/WV_CPA_WARNING.html" ) results.append(issue) if sdk_ver < 16: #minSdk <= 15 default is true; minSdk > 16 default is false issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData( common.config.get('qarkhelper', 'UNIV_FILE_WARNING') + " To validate this vulnerability, load the following url in this WebView: http://www.secbro.com/poc/html/UNIV_FILE_WARNING.html" + "Note: A local copy of this html file can also be found at <install_dir>/quark/poc/html/UNIV_FILE_WARNING.html" ) results.append(issue) #BUG - Need to double-check this, it doesn't appear to follow the same logic as the non-default checks if sdk_ver < 16: issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData( common.config.get('qarkhelper', 'FURL_FILE_WARNING') + " To validate this vulnerability, load the following url in this WebView: http://www.secbro.com/poc/html/FURL_FILE_WARNING.html" + "Note: A local copy of this html file can also be found at <install_dir>/quark/poc/html/FURL_FILE_WARNING.html" ) results.append(issue) else: issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData(common.config.get('qarkhelper', 'FURL_FILE_OK')) results.append(issue) else: issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData(common.config.get('qarkhelper', 'UNIV_FILE_OK')) results.append(issue) skip_next = False #checking previous value above, as this is ignored if the above is true if sdk_ver < 18: issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData(common.config.get('qarkhelper', 'DEPRECATED_SINCE_9')) results.append(issue) else: issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData(common.config.get('qarkhelper', 'REMOVED_IN_18')) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData(common.config.get('qarkhelper', 'NO_JS_INT')) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData(common.config.get('qarkhelper', 'DOM_STORAGE_DIS')) results.append(issue) # TODO - Am I missing anything??? return
def recursive_ecb_check(t, filename, results): #TODO - review this for thoroughness #TODO - need to verify .getInstance is actually being invoked on a Cipher object #TODO - we could whittle down the possibilities by checking the imports as well if type(t) is m.MethodInvocation: if hasattr(t, 'name'): if str(t.name) == 'getInstance': if hasattr(t, 'arguments'): for a in t.arguments: if type(a) is m.Literal: #sets mode to ECB if re.search(r'.*\/ECB\/.*', str(a.value)): issue = ReportIssue() issue.setCategory(ExploitType.CRYPTO) issue.setDetails( "getInstance should not be called with ECB as the cipher mode, as it is insecure. " ) issue.setFile(str(filename)) issue.setSeverity(Severity.VULNERABILITY) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.VULNERABILITY) issue.setData( "getInstance should not be called with ECB as the cipher mode, as it is insecure. " ) results.append(issue) #sets mode to something other than ECB elif re.search(r'.*/.*/.*', str(a.value)): return #No mode set elif str(a.value) == '': issue = ReportIssue() issue.setCategory(ExploitType.CRYPTO) issue.setDetails( "getInstance should not be called without setting the cipher mode because the default mode on android is ECB, which is insecure. " ) issue.setFile(str(filename)) issue.setSeverity(Severity.VULNERABILITY) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.VULNERABILITY) issue.setData( "getInstance should not be called without setting the cipher mode because the default mode on android is ECB, which is insecure. " ) results.append(issue) if type(t) is list: for l in t: recursive_ecb_check(l, filename, results) elif hasattr(t, '_fields'): for f in t._fields: recursive_ecb_check(getattr(t, f), filename, results) ''' GetInstance ----------- Summary: Cipher.getInstance with ECB Priority: 9 / 10 Severity: Warning Category: Security Cipher#getInstance should not be called with ECB as the cipher mode or without setting the cipher mode because the default mode on android is ECB, which is insecure.''' return
def show_wv_vulns(s_list, i, results): """ Shows all identified web view vulnerabilities """ #BUG - This sometimes prints twice, successively which shouldn't happen #print "#"*100 issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData("WebView: " + str(i[0])) results.append(issue) #logger.info("WebView: " +str(i[0])) issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData("File: " + str(i[1]) + "\n") results.append(issue) #logger.info("File: " + str(i[1]) +"\n") if len(s_list) == 0: default_wv_config(i[0], i[1], int(common.minSdkVersion), results) return for f in s_list: sl = re.sub(r'WebSettings\s*', '', f) sl = re.sub(r'\s*[;=].*$', '', sl) sl = re.sub(r'final\s', '', sl) #strip string whitespace out sl = re.sub(r'^\W+', '', sl) sl = re.sub(r'\.\w+\(\w+\)$', '', sl) sl = sl.rstrip() #Regex to look for javascript being enabled #BUG I can reduce the number of files checked to only those that have the name / import WebViews #Probably need to check for alternative true/false value representations wv_js_check = sl + '.setJavaScriptEnabled(true)' wv_js_check = re.escape(wv_js_check) #check if webview JS in enabled #BUG - THis can run twice, perhaps it is an artifact of an empty first element? if wv_config(i[1], wv_js_check): issue = ReportIssue() issue.setCategory(ExploitType.WEBVIEW) issue.setDetails(common.config.get('qarkhelper', 'JS_WARNING')) issue.setFile(str(i[1])) issue.setSeverity(Severity.WARNING) issue.setExtras(IS_JS_ENABLED, True) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData( common.config.get('qarkhelper', 'TERMINAL_JS_WARNING') + " " + str(i[0]) + " " + common.config.get('qarkhelper', 'TERMINAL_JS_WARNING1') + " To validate this vulnerability, load the following url in this WebView: http://www.secbro.com/poc/html/JS_WARNING.html" + "Note: A local copy of this html file can also be found at <install_dir>/quark/poc/html/JS_WARNING.html\n" ) results.append(issue) else: issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData( common.config.get('qarkhelper', 'JS_OK') + " " + str(i[0]) + str(i[1])) results.append(issue) #BUG - this is actually set on WebView #Check whether webview sets arbitrary BaseURL wv_burl_check = re.escape(sl + '.loadDataWithBaseURL') if wv_config(i[1], wv_burl_check): issue = ReportIssue() issue.setCategory(ExploitType.WEBVIEW) issue.setDetails(common.config.get('qarkhelper', 'BURL_WARNING1')) issue.setFile(str(i[1])) issue.setSeverity(Severity.WARNING) issue.setExtras(IS_BASE_URL_DEFINED, False) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData( common.config.get('qarkhelper', 'TERMINAL_BURL_WARNING1') + " " + str(i[0]) + " " + common.config.get('qarkhelper', 'TERMINAL_BURL_WARNING2') + "To validate this vulnerability, load the following url in this WebView: http://www.secbro.com/poc/html/BURL_WARNING.html " + "Note: A local copy of this html file can also be found at <install_dir>/quark/poc/html/BURL_WARNING.html\n" ) results.append(issue) else: issue = ReportIssue() issue.setCategory(ExploitType.WEBVIEW) issue.setDetails(common.config.get('qarkhelper', 'BURL_OK')) issue.setFile(str(i[1])) issue.setSeverity(Severity.INFO) issue.setExtras(IS_BASE_URL_DEFINED, True) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData(common.config.get('qarkhelper', 'BURL_OK')) results.append(issue) #Checks whether file URI can access filesystem #true by default, so the check is inverted wv_file_check = re.escape(sl + '.setAllowFileAccess(false)') if wv_config(i[1], wv_file_check): issue = ReportIssue() issue.setCategory(ExploitType.WEBVIEW) issue.setDetails(common.config.get('qarkhelper', 'FILE_SYS_OK')) issue.setFile(str(i[1])) issue.setSeverity(Severity.WARNING) issue.setExtras(IS_FILE_ACCESS_ENABLED, False) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData( common.config.get('qarkhelper', 'FILE_SYS_OK') + str(i[0])) results.append(issue) else: issue = ReportIssue() issue.setCategory(ExploitType.WEBVIEW) issue.setDetails(common.config.get('qarkhelper', 'FILE_SYS_WARN1')) issue.setFile(str(i[1])) issue.setSeverity(Severity.WARNING) issue.setExtras(IS_FILE_ACCESS_ENABLED, True) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData( common.config.get('qarkhelper', 'TERMINAL_FILE_SYS_WARN1') + str(i[0]) + " " + common.config.get('qarkhelper', 'TERMINAL_FILE_SYS_WARN2') + " To validate this vulnerability, load the following url in this WebView: http://www.secbro.com/poc/html/FILE_SYS_WARN.html " + "Note: A local copy of this html file can also be found at <install_dir>/quark/poc/html/FILE_SYS_WARN.html\n" ) results.append(issue) #Regex to determine if WebViews have Content Provider access (default = true) #Checks whether WebView can access Content Providers #true by default, so the check is inverted #BUG - This can run twice, perhaps due to an empty element wv_cpa_check = re.escape(sl + '.setAllowContentAccess(false)') if wv_config(i[1], wv_cpa_check): issue = ReportIssue() issue.setCategory(ExploitType.WEBVIEW) issue.setDetails(common.config.get('qarkhelper', 'WV_CPA_OK')) issue.setFile(str(i[1])) issue.setSeverity(Severity.INFO) issue.setExtras(IS_CP_ACCESS_ENABLED, False) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData( common.config.get('qarkhelper', 'WV_CPA_OK') + str(i[0])) results.append(issue) else: issue = ReportIssue() issue.setCategory(ExploitType.WEBVIEW) issue.setDetails(common.config.get('qarkhelper', 'WV_CPA_WARNING')) issue.setFile(str(i[1])) issue.setSeverity(Severity.WARNING) issue.setExtras(IS_CP_ACCESS_ENABLED, True) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData( common.config.get('qarkhelper', 'TERMINAL_WV_CPA_WARNING') + str(i[0]) + "To validate this vulnerability, load the following url in this WebView: http://www.secbro.com/poc/html/WV_CPA_WARNING.html " + "Note: A local copy of this html file can also be found at <install_dir>/quark/poc/html/WV_CPA_WARNING.html\n" ) results.append(issue) #check for JS access from file URL can access content from any origin #minSdk <= 15 default is true; minSdk > 16 default is false #BUG - This check is wrong on the second if; If set to false and not found, it prints OK if int(common.minSdkVersion) < 16: wv_univ_file_access = re.escape( sl + '.setAllowUniversalAccessFromFileURLs(false)') if not wv_config(i[1], wv_univ_file_access): issue = ReportIssue() issue.setCategory(ExploitType.WEBVIEW) issue.setDetails( common.config.get('qarkhelper', 'UNIV_FILE_WARNING')) issue.setFile(str(i[1])) issue.setSeverity(Severity.WARNING) issue.setExtras(IS_FILE_ACCESS_ENABLED, True) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData( common.config.get('qarkhelper', 'TERMINAL_UNIV_FILE_WARNING') + str(i[0]) + " To validate this vulnerability, load the following url in this WebView: http://www.secbro.com/poc/html/UNIV_FILE_WARNING.html " + "Note: A local copy of this html file can also be found at <install_dir>/quark/poc/html/UNIV_FILE_WARNING.html\n" ) results.append(issue) skip_next = True else: issue = ReportIssue() issue.setCategory(ExploitType.WEBVIEW) issue.setDetails( common.config.get('qarkhelper', 'UNIV_FILE_OK')) issue.setFile(str(i[1])) issue.setSeverity(Severity.INFO) issue.setExtras(IS_FILE_ACCESS_ENABLED, False) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData( common.config.get('qarkhelper', 'UNIV_FILE_OK') + str(i[0])) results.append(issue) skip_next = False #checking previous value above, as this is ignored if the above is true #could I just put pass above? if skip_next: pass else: #minSdk <= 15 default is true; minSdk > 16 default is false wv_allow_file_access_furls = re.escape( sl + '.setAllowFileAccessFromFileURLs(false)') if wv_config(i[1], wv_allow_file_access_furls): issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData( "This WebView does not have access to File URLs - setAllowFileAccessFromFileURLs(false)" + str(i[0])) results.append(issue) issue = ReportIssue() issue.setCategory(ExploitType.WEBVIEW) issue.setDetails( "This WebView does not have access to File URLs - setAllowFileAccessFromFileURLs(false)" ) issue.setFile(str(i[1])) issue.setSeverity(Severity.WARNING) issue.setExtras(IS_FILE_ACCESS_ENABLED, False) results.append(issue) else: issue = ReportIssue() issue.setCategory(ExploitType.WEBVIEW) issue.setDetails( common.config.get('qarkhelper', 'UNIV_FILE_WARNING')) issue.setFile(str(i[1])) issue.setSeverity(Severity.WARNING) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setExtras(IS_FILE_ACCESS_ENABLED, True) issue.setData( common.config.get('qarkhelper', 'TERMINAL_UNIV_FILE_WARNING') + str(i[0]) + "To validate this vulnerability, load the following url in this WebView: http://www.secbro.com/poc/html/UNIV_FILE_WARNING2.html " + "Note: A local copy of this html file can also be found at <install_dir>/quark/poc/html/UNIV_FILE_WARNING2.html\n" ) results.append(issue) else: wv_univ_file_access = re.escape( sl + '.setAllowUniversalAccessFromFileURLs(true)') if wv_config(i[1], wv_univ_file_access): issue = ReportIssue() issue.setCategory(ExploitType.WEBVIEW) issue.setDetails( common.config.get('qarkhelper', 'UNIV_FILE_WARNING')) issue.setFile(str(i[1])) issue.setSeverity(Severity.WARNING) issue.setExtras(IS_UNIVERSAL_FILE_ACCESS_ENABLED, True) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData( common.config.get('qarkhelper', 'TERMINAL_UNIV_FILE_WARNING') + '1 ' + str(i[0]) + " To validate this vulnerability, load the following url in this WebView: http://www.secbro.com/poc/html/UNIV_FILE_WARNING.html " + "Note: A local copy of this html file can also be found at <install_dir>/quark/poc/html/UNIV_FILE_WARNING.html\n" ) results.append(issue) skip_next = True else: issue = ReportIssue() issue.setCategory(ExploitType.WEBVIEW) issue.setDetails( common.config.get('qarkhelper', 'UNIV_FILE_OK')) issue.setFile(str(i[1])) issue.setSeverity(Severity.INFO) issue.setExtras(IS_UNIVERSAL_FILE_ACCESS_ENABLED, False) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData( common.config.get('qarkhelper', 'UNIV_FILE_OK') + str(i[0])) results.append(issue) skip_next = False #checking previous value above, as this is ignored if the above is true if skip_next: pass else: #minSdk <= 15 default is true; minSdk > 16 default is false wv_allow_file_access_furls = re.escape( sl + '.setAllowFileAccessFromFileURLs(true)') if wv_config(i[1], wv_allow_file_access_furls): issue = ReportIssue() issue.setCategory(ExploitType.WEBVIEW) issue.setDetails( common.config.get('qarkhelper', 'FURL_FILE_WARNING')) issue.setFile(str(i[1])) issue.setSeverity(Severity.WARNING) issue.setExtras(IS_UNIVERSAL_FILE_ACCESS_ENABLED, True) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData( common.config.get('qarkhelper', 'TERMINAL_FURL_FILE_WARNING') + str(i[0]) + "To validate this vulnerability, load the following url in this WebView: http://www.secbro.com/poc/html/FURL_FILE_WARNING.html " + "Note: A local copy of this html file can also be found at <install_dir>/quark/poc/html/FURL_FILE_WARNING.html\n" ) results.append(issue) else: issue = ReportIssue() issue.setCategory(ExploitType.WEBVIEW) issue.setDetails( common.config.get('qarkhelper', 'FURL_FILE_OK')) issue.setFile(str(i[1])) issue.setSeverity(Severity.INFO) issue.setExtras(IS_UNIVERSAL_FILE_ACCESS_ENABLED, False) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData( common.config.get('qarkhelper', 'FURL_FILE_OK') + str(i[0])) results.append(issue) #Checking whether plugins are enabled for WebViews #setPluginsEnabled deprecated in API 9, removed in API 18 #setPluginState added in API 8, deprecated in API 18 wv_plugsinenabled = re.escape(sl + '.setPluginsEnabled(true)') wv_pluginstate = re.escape( sl + '.setPluginState(WebSettings.PluginState.ON*') if wv_config(i[1], wv_plugsinenabled): if int(common.minSdkVersion) < 18: issue = ReportIssue() issue.setCategory(ExploitType.WEBVIEW) issue.setDetails( common.config.get('qarkhelper', 'DEPRECATED_SINCE_9') + str(i[0]) + "<br>FILE: " + str(i[1])) issue.setFile(str(i[1])) issue.setSeverity(Severity.INFO) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData( common.config.get('qarkhelper', 'DEPRECATED_SINCE_9') + str(i[0])) results.append(issue) else: issue = ReportIssue() issue.setCategory(ExploitType.WEBVIEW) issue.setDetails( common.config.get('qarkhelper', 'REMOVED_IN_18') + str(i[0]) + "<br>FILE: " + str(i[1])) issue.setFile(str(i[1])) issue.setSeverity(Severity.INFO) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData( common.config.get('qarkhelper', 'REMOVED_IN_18') + str(i[0])) results.append(issue) logger.info( common.config.get('qarkhelper', 'REMOVED_IN_18') + str(i[0])) if wv_config(i[1], wv_pluginstate): if int(common.minSdkVersion) < 8: issue = ReportIssue() issue.setCategory(ExploitType.WEBVIEW) issue.setDetails( common.config.get('qarkhelper', 'ADDED_IN_8') + str(i[0]) + "<br>FILE: " + str(i[1])) issue.setFile(str(i[1])) issue.setSeverity(Severity.INFO) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData( common.config.get('qarkhelper', 'ADDED_IN_8') + str(i[0])) results.append(issue) logger.info( common.config.get('qarkhelper', 'ADDED_IN_8') + str(i[0])) else: issue = ReportIssue() issue.setCategory(ExploitType.WEBVIEW) issue.setDetails( common.config.get('qarkhelper', 'DEPRECATED_IN_18') + str(i[0]) + "<br>FILE: " + str(i[1])) issue.setFile(str(i[1])) issue.setSeverity(Severity.INFO) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData( common.config.get('qarkhelper', 'DEPRECATED_IN_18') + str(i[0])) results.append(issue) #Check if addJavascriptInterface is used in WebView #BUG - this is actually on WebView, not settings wv_ajs = re.escape(sl + '.addJavascriptInterface') if wv_config(i[1], wv_ajs): if int(common.minSdkVersion) < 17: issue = ReportIssue() issue.setCategory(ExploitType.WEBVIEW) issue.setDetails(common.config.get('qarkhelper', 'BAD_JS_INT')) issue.setFile(str(i[1])) issue.setSeverity(Severity.WARNING) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData( common.config.get('qarkhelper', 'TERMINAL_BAD_JS_INT') + " " + str(i[0]) + " To validate this vulnerability, load the following url in this WebView: http://www.secbro.com/poc/html/BAD_JS_INT.html " + "Note: A local copy of this html file can also be found at <install_dir>/quark/poc/html/BAD_JS_INT.html" + "\n") results.append(issue) else: issue = ReportIssue() issue.setCategory(ExploitType.WEBVIEW) issue.setDetails( common.config.get('qarkhelper', 'OK_JS_INT') + str(i[0]) + "<br>FILE: " + str(i[1])) issue.setFile(str(i[1])) issue.setSeverity(Severity.INFO) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData(common.config.get('qarkhelper', 'OK_JS_INT')) results.append(issue) else: issue = ReportIssue() issue.setCategory(ExploitType.WEBVIEW) issue.setDetails( common.config.get('qarkhelper', 'NO_JS_INT') + "<br>FILE: " + str(i[1])) issue.setFile(str(i[1])) issue.setSeverity(Severity.INFO) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData( common.config.get('qarkhelper', 'NO_JS_INT') + str(i[0])) results.append(issue) #Check if WebView has DOMStorage enabled wv_setdom = re.escape(sl + '.setDomStorageEnabled(true)') if wv_config(i[1], wv_setdom): issue = ReportIssue() issue.setCategory(ExploitType.WEBVIEW) issue.setDetails( common.config.get('qarkhelper', 'DOM_STORAGE_EN') + str(i[0]) + "<br>FILE: " + str(i[1])) issue.setFile(str(i[1])) issue.setSeverity(Severity.INFO) issue.setExtras(IS_DOM_STORAGE_ENABLED, True) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData(common.config.get('qarkhelper', 'DOM_STORAGE_EN')) results.append(issue) else: issue = ReportIssue() issue.setCategory(ExploitType.WEBVIEW) issue.setDetails( common.config.get('qarkhelper', 'DOM_STORAGE_DIS') + "<br>FILE: " + str(i[1])) issue.setFile(str(i[1])) issue.setSeverity(Severity.INFO) issue.setExtras(IS_DOM_STORAGE_ENABLED, False) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData( common.config.get('qarkhelper', 'DOM_STORAGE_DIS') + str(i[0])) results.append(issue) return
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
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
def start(queue,height): results = [] count = 0 #TODO - add check for getSharedPreferences specifically, to run before these more generalized ones #Check for world readable files file_wr=r'MODE_WORLD_READABLE' for i in text_scan(common.java_files,file_wr): if len(i)>0: report.write(IssueType.FileSystem, IssueSeverity.High, common.config.get('qarkhelper', 'WR_FILE') + str(i[0]) +"<br>" + str(i[1])) issue = ReportIssue() issue.setCategory(ExploitType.PERMISSION) issue.setDetails(common.config.get('qarkhelper', 'WR_FILE') + str(i[0]) + str(i[1])) issue.setFile(str(i[1])) issue.setSeverity(Severity.WARNING) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData(common.config.get('qarkhelper', 'WR_FILE') + str(i[0]) + str(i[1])) results.append(issue) #Check for world writable files file_ww=r'MODE_WORLD_WRITEABLE' for i in text_scan(common.java_files,file_ww): if len(i)>0: report.write(IssueType.FileSystem, IssueSeverity.High, common.config.get('qarkhelper', 'WW_FILE') + str(i[0]) +"<br>" + str(i[1])) issue = ReportIssue() issue.setCategory(ExploitType.PERMISSION) issue.setDetails(common.config.get('qarkhelper', 'WW_FILE') + str(i[0]) + " in file: " + str(i[1])) issue.setFile(str(i[1])) issue.setSeverity(Severity.WARNING) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData(common.config.get('qarkhelper', 'WW_FILE') + str(i[0]) + " in file: " + str(i[1])) results.append(issue) queue.put(results) ''' More checks from Android Lint to implement WorldReadableFiles ------------------ Summary: openFileOutput() call passing MODE_WORLD_READABLE Priority: 4 / 10 Severity: Warning Category: Security There are cases where it is appropriate for an application to write world readable files, but these should be reviewed carefully to ensure that they contain no private data that is leaked to other applications. WorldWriteableFiles ------------------- Summary: openFileOutput() call passing MODE_WORLD_WRITEABLE Priority: 4 / 10 Severity: Warning Category: Security There are cases where it is appropriate for an application to write world writeable files, but these should be reviewed carefully to ensure that they contain no private data, and that if the file is modified by a malicious application it does not trick or compromise your application. ''' return
def recursive_ecb_check(t,filename,results): #TODO - review this for thoroughness #TODO - need to verify .getInstance is actually being invoked on a Cipher object #TODO - we could whittle down the possibilities by checking the imports as well if type(t) is m.MethodInvocation: if hasattr(t,'name'): if str(t.name)=='getInstance': if hasattr(t,'arguments'): for a in t.arguments: if type(a) is m.Literal: #sets mode to ECB if re.search(r'.*\/ECB\/.*',str(a.value)): issue = ReportIssue() issue.setCategory(ExploitType.CRYPTO) issue.setDetails("getInstance should not be called with ECB as the cipher mode, as it is insecure. ") issue.setFile(str(filename)) issue.setSeverity(Severity.VULNERABILITY) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.VULNERABILITY) issue.setData("getInstance should not be called with ECB as the cipher mode, as it is insecure. ") results.append(issue) #sets mode to something other than ECB elif re.search(r'.*/.*/.*',str(a.value)): return #No mode set elif str(a.value)=='': issue = ReportIssue() issue.setCategory(ExploitType.CRYPTO) issue.setDetails("getInstance should not be called without setting the cipher mode because the default mode on android is ECB, which is insecure. ") issue.setFile(str(filename)) issue.setSeverity(Severity.VULNERABILITY) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.VULNERABILITY) issue.setData("getInstance should not be called without setting the cipher mode because the default mode on android is ECB, which is insecure. ") results.append(issue) if type(t) is list: for l in t: recursive_ecb_check(l,filename, results) elif hasattr(t,'_fields'): for f in t._fields: recursive_ecb_check(getattr(t,f),filename,results) ''' GetInstance ----------- Summary: Cipher.getInstance with ECB Priority: 9 / 10 Severity: Warning Category: Security Cipher#getInstance should not be called with ECB as the cipher mode or without setting the cipher mode because the default mode on android is ECB, which is insecure.''' return
def recursive_find_verify(q, filename, results): ''' Find all .verify methods ''' global sslSessions global tree global verifyIteration global warningGiven if len(sslSessions) > 0: if verifyIteration == 0: try: for type_decl in tree.type_declarations: if type(type_decl) is m.ClassDeclaration: for t in type_decl.body: if type(t) is m.MethodInvocation: if hasattr(t, 'name'): if str(t.name) == 'verify': if hasattr(t, 'arguments'): if len(t.arguments) != 2: if not warningGiven: issue = ReportIssue() issue.setCategory( ExploitType.CERTIFICATE ) issue.setDetails( "Custom verify method used in " + str(filename) + ". You should manually review certificate validation here." ) issue.setFile(filename) issue.setSeverity( Severity.WARNING) results.append(issue) issue = terminalPrint() issue.setLevel( Severity.WARNING) issue.setData( "Custom verify method used in " + str(filename) + ". You should manually review certificate validation here." ) results.append(issue) warningGiven = True else: for r in q.arguments: continue elif type(t) is m.MethodDeclaration: if hasattr(t, 'name'): if str(t.name) == 'verify': if not warningGiven: issue = ReportIssue() issue.setCategory( ExploitType.CERTIFICATE) issue.setDetails( "Custom verify method declared in " + str(filename) + ". You should manually review certificate validation here." ) issue.setFile(filename) issue.setSeverity(Severity.WARNING) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData( "Custom verify method declared in " + str(filename) + ". You should manually review certificate validation here." ) results.append(issue) warningGiven = True elif type(t) is list: for l in t: if type(l) is not None: verifyIteration = 1 recursive_find_verify( l, filename, results) elif hasattr(t, '_fields'): for f in t._fields: if type(getattr(t, f)) is not None: verifyIteration = 1 recursive_find_verify( getattr(t, f), filename, results) elif type(t) is list: for l in t: if type(l) is not None: verifyIteration = 1 recursive_find_verify( l, filename, results) elif hasattr(t, '_fields'): for f in t._fields: if type(getattr(t, f)) is not None: verifyIteration = 1 recursive_find_verify( getattr(t, f), filename, results) except Exception as e: common.logger.debug( "Something went wrong in certValidation.py's findVerify: " + str(e)) report.write( "parsingerror-issues-list", "Something went wrong in certValidation.py's findVerify: " + str(e), "strong") else: if type(q) is m.MethodInvocation: if hasattr(q, 'name'): if str(q.name) == 'verify': if hasattr(q, 'arguments'): if len(q.arguments) != 2: if not warningGiven: issue = ReportIssue() issue.setCategory(ExploitType.CERTIFICATE) issue.setDetails( "Custom verify method used in " + str(filename) + ". You should manually review certificate validation here." ) issue.setFile(filename) issue.setSeverity(Severity.WARNING) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData( "Custom verify method used in " + str(filename) + ". You should manually review certificate validation here." ) results.append(issue) warningGiven = True else: common.logger.debug("sslSessions Before: " + str(sslSessions)) if str(q.arguments[1]) in sslSessions: sslSessions.remove(str(q.arguments[1])) common.logger.debug("sslSessions After: " + str(sslSessions)) #For each verify method, check whether the session being verified is in sslSessions and if so, remove it(considering it verified) #This is not full proof at all, for several reasons, but we know it's definitely vulnerable if it's never verified, assuming no strange code #TODO - check that the .verify actually belongs to a HostnameVerifier #TODO - verify that .verify is not over ridden somewhere elif type(q) is m.MethodDeclaration: if hasattr(q, 'name'): if str(q.name) == 'verify': if not warningGiven: issue = ReportIssue() issue.setCategory(ExploitType.CERTIFICATE) issue.setDetails( "Custom verify method declared in " + str(filename) + ". You should manually review certificate validation here." ) issue.setFile(filename) issue.setSeverity(Severity.WARNING) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData( "Custom verify method declared in " + str(filename) + ". You should manually review certificate validation here." ) results.append(issue) warningGiven = True elif type(q) is list: for l in q: if type(l) is not None: recursive_find_verify(l, filename, results) elif hasattr(q, '_fields'): for f in q._fields: if type(getattr(q, f)) is not None: recursive_find_verify(getattr(q, f), filename, results) elif type(q) is list: for l in q: if type(l) is not None: recursive_find_verify(l, filename, results) elif hasattr(q, '_fields'): for f in q._fields: if type(getattr(q, f)) is not None: recursive_find_verify(getattr(q, f), filename, results) verifyIteration = 1 unverified_sessions(results) return
def recursive_broadcast_finder(t,results): if type(t) is m.MethodDeclaration: if str(t.name) == 'sendBroadcast': common.logger.debug("It appears the sendBroadcast method may be overridden in this class. The following findings for this class may be false positives") if str(t.name) == 'sendBroadcastAsUser': common.logger.debug("It appears the sendBroadcastAsUser method may be overridden in this class. The following findings for this class may be false positives") if str(t.name) == 'sendOrderedBroadcast': common.logger.debug("It appears the sendOrderedBroadcast method may be overridden in this class. The following findings for this class may be false positives") if str(t.name) == 'sendOrderedBroadcastAsUser': common.logger.debug("It appears the sendOrderedBroadcastAsUser method may be overridden in this class. The following findings for this class may be false positives") if str(t.name) == 'sendStickyBroadcast': common.logger.debug("It appears the sendStickyBroadcast method may be overridden in this class. The following findings for this class may be false positives") if str(t.name) == 'sendStickyBroadcastAsUser': common.logger.debug("It appears the sendStickyBroadcastAsUser method may be overridden in this class. The following findings for this class may be false positives") if str(t.name) == 'sendStickyOrderedBroadcast': common.logger.debug("It appears the sendStickyOrderedBroadcast method may be overridden in this class. The following findings for this class may be false positives") if str(t.name) == 'sendStickyOrderedBroadcastAsUser': common.logger.debug("It appears the sendStickyOrderedBroadcastAsUser method may be overridden in this class. The following findings for this class may be false positives") if type(t) is m.MethodInvocation: if str(t.name) == 'sendBroadcast': if len(t.arguments)==1: #We need to ensure this isn't a local broadcast #TODO - There is a lot more we need to do to fully qualify this, but should be good enough for now if local_broadcast_manager_imported()==True: common.logger.debug(tree) else: report.write_badger("manifest-issues", modules.common.Severity.INFO, "NO IMPORT") common.logger.debug("FOUND A sendBroadcast") issue = ReportIssue() issue.setCategory(ExploitType.BROADCAST_INTENT) issue.setDetails("A broadcast is sent from this class: " + str(current_file) + ", which does not specify the receiverPermission. This means any application on the device can receive this broadcast. You should investigate this for potential data leakage.") issue.setFile(str(current_file)) issue.setSeverity(Severity.WARNING) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData("A broadcast is sent from this class: " + str(current_file) + ", which does not specify the receiverPermission. This means any application on the device can receive this broadcast. You should investigate this for potential data leakage.") results.append(issue) elif len(t.arguments)==2: if common.minSdkVersion<21: issue = ReportIssue() issue.setCategory(ExploitType.BROADCAST_INTENT) issue.setDetails("A broadcast is sent from this class: " + str(current_file) + ", which specifies the receiverPermission, but may still be vulnerable to interception, due to the permission squatting vulnerability in API levels before 21. This means any application, installed prior to the expected receiver(s) on the device can potentially receive this broadcast. You should investigate this for potential data leakage.") issue.setFile(str(current_file)) issue.setSeverity(Severity.WARNING) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData("A broadcast is sent from this class: " + str(current_file) + ", which specifies the receiverPermission, but may still be vulnerable to interception, due to the permission squatting vulnerability in API levels before 21. This means any application, installed prior to the expected receiver(s) on the device can potentially receive this broadcast. You should investigate this for potential data leakage.") results.append(issue) else: issue = ReportIssue() issue.setCategory(ExploitType.BROADCAST_INTENT) issue.setDetails("A broadcast is sent from this class: " + str(current_file) + ", which specifies the receiverPermission, but depending on the protection level of the permission (on the receiving app side), may still be vulnerable to interception, if the protection level of the permission is not set to signature or signatureOrSystem. You should investigate this for potential data leakage.") issue.setFile(str(current_file)) issue.setSeverity(Severity.WARNING) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData("A broadcast is sent from this class: " + str(current_file) + ", which specifies the receiverPermission, but depending on the protection level of the permission (on the receiving app side), may still be vulnerable to interception, if the protection level of the permission is not set to signature or signatureOrSystem. You should investigate this for potential data leakage.") results.append(issue) elif str(t.name) == 'sendBroadcastAsUser': if len(t.arguments)==2: issue = ReportIssue() issue.setCategory(ExploitType.BROADCAST_INTENT) issue.setDetails("A broadcast, as a specific user, is sent from this class: " + str(current_file) + ", which does not specify the receiverPermission. This means any application on the device can receive this broadcast. You should investigate this for potential data leakage.") issue.setFile(str(current_file)) issue.setSeverity(Severity.WARNING) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData("A broadcast, as a specific user, is sent from this class: " + str(current_file) + ", which does not specify the receiverPermission. This means any application on the device can receive this broadcast. You should investigate this for potential data leakage.") results.append(issue) elif len(t.arguments)==3: if common.minSdkVersion<21: issue = ReportIssue() issue.setCategory(ExploitType.BROADCAST_INTENT) issue.setDetails("A broadcast, as a specific user, is sent from this class: " + str(current_file) + ", which specifies the receiverPermission, but may still be vulnerable to interception, due to the permission squatting vulnerability in API levels before 21. This means any application, installed prior to the expected receiver(s) on the device can potentially receive this broadcast. You should investigate this for potential data leakage.") issue.setFile(str(current_file)) issue.setSeverity(Severity.WARNING) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData("A broadcast, as a specific user, is sent from this class: " + str(current_file) + ", which specifies the receiverPermission, but may still be vulnerable to interception, due to the permission squatting vulnerability in API levels before 21. This means any application, installed prior to the expected receiver(s) on the device can potentially receive this broadcast. You should investigate this for potential data leakage.") results.append(issue) else: issue = ReportIssue() issue.setCategory(ExploitType.BROADCAST_INTENT) issue.setDetails("A broadcast, as a specific user, is sent from this class: " + str(current_file) + ", which specifies the receiverPermission, but depending on the protection level of the permission (on the receiving app side), may still be vulnerable to interception, if the protection level of the permission is not set to signature or signatureOrSystem. You should investigate this for potential data leakage.") issue.setFile(str(current_file)) issue.setSeverity(Severity.WARNING) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData("A broadcast, as a specific user, is sent from this class: " + str(current_file) + ", which specifies the receiverPermission, but depending on the protection level of the permission (on the receiving app side), may still be vulnerable to interception, if the protection level of the permission is not set to signature or signatureOrSystem. You should investigate this for potential data leakage.") results.append(issue) elif str(t.name) == 'sendOrderedBroadcast': if ((len(t.arguments)==2) or (len(t.arguments)==7)): if common.minSdkVersion<21: issue = ReportIssue() issue.setCategory(ExploitType.BROADCAST_INTENT) issue.setDetails("An ordered broadcast, as a specific user, is sent from this class: " + str(current_file) + ", which specifies the receiverPermission, but may still be vulnerable to interception, due to the permission squatting vulnerability in API levels before 21. This means any application, installed prior to the expected receiver(s) on the device can potentially receive this broadcast. You should investigate this for potential data leakage.") issue.setFile(str(current_file)) issue.setSeverity(Severity.WARNING) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData("An ordered broadcast, as a specific user, is sent from this class: " + str(current_file) + ", which specifies the receiverPermission, but may still be vulnerable to interception, due to the permission squatting vulnerability in API levels before 21. This means any application, installed prior to the expected receiver(s) on the device can potentially receive this broadcast. You should investigate this for potential data leakage.") results.append(issue) else: issue = ReportIssue() issue.setCategory(ExploitType.BROADCAST_INTENT) issue.setDetails("An ordered broadcast, as a specific user, is sent from this class: " + str(current_file) + ", which specifies the receiverPermission, but may still be vulnerable to interception, due to the permission squatting vulnerability in API levels before 21. This means any application, installed prior to the expected receiver(s) on the device can potentially receive this broadcast. You should investigate this for potential data leakage.") issue.setFile(str(current_file)) issue.setSeverity(Severity.WARNING) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData("An ordered broadcast, as a specific user, is sent from this class: " + str(current_file) + ", which specifies the receiverPermission, but may still be vulnerable to interception, due to the permission squatting vulnerability in API levels before 21. This means any application, installed prior to the expected receiver(s) on the device can potentially receive this broadcast. You should investigate this for potential data leakage.") results.append(issue) elif str(t.name) == 'sendOrderedBroadcastAsUser': if len(t.arguments)==7: if common.minSdkVersion<21: issue = ReportIssue() issue.setCategory(ExploitType.BROADCAST_INTENT) issue.setDetails("An ordered broadcast, as a specific user, is sent from this class: " + str(current_file) + ", which specifies the receiverPermission, but may still be vulnerable to interception, due to the permission squatting vulnerability in API levels before 21. This means any application, installed prior to the expected receiver(s) on the device can potentially receive this broadcast. You should investigate this for potential data leakage.") issue.setFile(str(current_file)) issue.setSeverity(Severity.WARNING) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData("An ordered broadcast, as a specific user, is sent from this class: " + str(current_file) + ", which specifies the receiverPermission, but may still be vulnerable to interception, due to the permission squatting vulnerability in API levels before 21. This means any application, installed prior to the expected receiver(s) on the device can potentially receive this broadcast. You should investigate this for potential data leakage.") results.append(issue) else: issue = ReportIssue() issue.setCategory(ExploitType.BROADCAST_INTENT) issue.setDetails("An ordered broadcast, as a specific user, is sent from this class: " + str(current_file) + ", which specifies the receiverPermission, but depending on the protection level of the permission (on the receiving app side), may still be vulnerable to interception, if the protection level of the permission is not set to signature or signatureOrSystem. You should investigate this for potential data leakage.") issue.setFile(str(current_file)) issue.setSeverity(Severity.WARNING) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData("An ordered broadcast, as a specific user, is sent from this class: " + str(current_file) + ", which specifies the receiverPermission, but depending on the protection level of the permission (on the receiving app side), may still be vulnerable to interception, if the protection level of the permission is not set to signature or signatureOrSystem. You should investigate this for potential data leakage.") results.append(issue) elif str(t.name) == 'sendStickyBroadcast': issue = ReportIssue() issue.setCategory(ExploitType.BROADCAST_INTENT) issue.setDetails("A sticky broadcast is sent from this class: " + str(current_file) + ". These should not be used, as they provide no security (anyone can access them), no protection (anyone can modify them), and many other problems. For more info: http://developer.android.com/reference/android/content/Context.html") issue.setFile(str(current_file)) issue.setSeverity(Severity.VULNERABILITY) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.VULNERABILITY) issue.setData("A sticky broadcast is sent from this class: " + str(current_file) + ". These should not be used, as they provide no security (anyone can access them), no protection (anyone can modify them), and many other problems. For more info: http://developer.android.com/reference/android/content/Context.html") results.append(issue) elif str(t.name) == 'sendStickyBroadcastAsUser': issue = ReportIssue() issue.setCategory(ExploitType.BROADCAST_INTENT) issue.setDetails("A sticky user broadcast is sent from this class: " + str(current_file) + ". These should not be used, as they provide no security (anyone can access them), no protection (anyone can modify them), and many other problems. For more info: http://developer.android.com/reference/android/content/Context.html") issue.setFile(str(current_file)) issue.setSeverity(Severity.VULNERABILITY) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.VULNERABILITY) issue.setData("A sticky user broadcast is sent from this class: " + str(current_file) + ". These should not be used, as they provide no security (anyone can access them), no protection (anyone can modify them), and many other problems. For more info: http://developer.android.com/reference/android/content/Context.html") results.append(issue) elif str(t.name) == 'sendStickyOrderedBroadcast': issue = ReportIssue() issue.setCategory(ExploitType.BROADCAST_INTENT) issue.setDetails("A sticky ordered broadcast is sent from this class: " + str(current_file) + ". These should not be used, as they provide no security (anyone can access them), no protection (anyone can modify them), and many other problems. For more info: http://developer.android.com/reference/android/content/Context.html") issue.setFile(str(current_file)) issue.setSeverity(Severity.VULNERABILITY) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.VULNERABILITY) issue.setData("A sticky ordered broadcast is sent from this class: " + str(current_file) + ". These should not be used, as they provide no security (anyone can access them), no protection (anyone can modify them), and many other problems. For more info: http://developer.android.com/reference/android/content/Context.html") results.append(issue) elif str(t.name) == 'sendStickyOrderedBroadcastAsUser': issue = ReportIssue() issue.setCategory(ExploitType.BROADCAST_INTENT) issue.setDetails("A sticky ordered user broadcast is sent from this class: " + str(current_file) + ". These should not be used, as they provide no security (anyone can access them), no protection (anyone can modify them), and many other problems. For more info: http://developer.android.com/reference/android/content/Context.html") issue.setFile(str(current_file)) issue.setSeverity(Severity.VULNERABILITY) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.VULNERABILITY) issue.setData("A sticky ordered user broadcast is sent from this class: " + str(current_file) + ". These should not be used, as they provide no security (anyone can access them), no protection (anyone can modify them), and many other problems. For more info: http://developer.android.com/reference/android/content/Context.html") results.append(issue) elif hasattr(t,'_fields'): for g in t._fields: recursive_broadcast_finder(getattr(t,g),results) elif type(t) is list: for l in t: recursive_broadcast_finder(l,results) elif hasattr(t,'_fields'): for f in t._fields: if type(getattr(t,f)) is not str: recursive_broadcast_finder(getattr(t,f),results) return
def recursive_find_verify(q,filename,results): ''' Find all .verify methods ''' global sslSessions global tree global verifyIteration global warningGiven if len(sslSessions)>0: if verifyIteration==0: try: for type_decl in tree.type_declarations: if type(type_decl) is m.ClassDeclaration: for t in type_decl.body: if type(t) is m.MethodInvocation: if hasattr(t,'name'): if str(t.name)=='verify': if hasattr(t,'arguments'): if len(t.arguments)!=2: if not warningGiven: issue = ReportIssue() issue.setCategory(ExploitType.CERTIFICATE) issue.setDetails("Custom verify method used in " + str(filename) + ". You should manually review certificate validation here." ) issue.setFile(filename) issue.setSeverity(Severity.WARNING) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData("Custom verify method used in " + str(filename) + ". You should manually review certificate validation here." ) results.append(issue) warningGiven=True else: for r in q.arguments: continue elif type(t) is m.MethodDeclaration: if hasattr(t,'name'): if str(t.name)=='verify': if not warningGiven: issue = ReportIssue() issue.setCategory(ExploitType.CERTIFICATE) issue.setDetails("Custom verify method declared in " + str(filename) + ". You should manually review certificate validation here." ) issue.setFile(filename) issue.setSeverity(Severity.WARNING) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData("Custom verify method declared in " + str(filename) + ". You should manually review certificate validation here." ) results.append(issue) warningGiven=True elif type(t) is list: for l in t: if type(l) is not None: verifyIteration=1 recursive_find_verify(l,filename,results) elif hasattr(t,'_fields'): for f in t._fields: if type(getattr(t,f)) is not None: verifyIteration=1 recursive_find_verify(getattr(t,f),filename,results) elif type(t) is list: for l in t: if type(l) is not None: verifyIteration=1 recursive_find_verify(l,filename,results) elif hasattr(t,'_fields'): for f in t._fields: if type(getattr(t,f)) is not None: verifyIteration=1 recursive_find_verify(getattr(t,f),filename,results) except Exception as e: common.logger.debug("Something went wrong in certValidation.py's findVerify: " + str(e)) report.write("parsingerror-issues-list", "Something went wrong in certValidation.py's findVerify: " + str(e), "strong") else: if type(q) is m.MethodInvocation: if hasattr(q,'name'): if str(q.name)=='verify': if hasattr(q,'arguments'): if len(q.arguments)!=2: if not warningGiven: issue = ReportIssue() issue.setCategory(ExploitType.CERTIFICATE) issue.setDetails("Custom verify method used in " + str(filename) + ". You should manually review certificate validation here." ) issue.setFile(filename) issue.setSeverity(Severity.WARNING) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData("Custom verify method used in " + str(filename) + ". You should manually review certificate validation here." ) results.append(issue) warningGiven=True else: common.logger.debug("sslSessions Before: " + str(sslSessions)) if str(q.arguments[1]) in sslSessions: sslSessions.remove(str(q.arguments[1])) common.logger.debug("sslSessions After: " + str(sslSessions)) #For each verify method, check whether the session being verified is in sslSessions and if so, remove it(considering it verified) #This is not full proof at all, for several reasons, but we know it's definitely vulnerable if it's never verified, assuming no strange code #TODO - check that the .verify actually belongs to a HostnameVerifier #TODO - verify that .verify is not over ridden somewhere elif type(q) is m.MethodDeclaration: if hasattr(q,'name'): if str(q.name)=='verify': if not warningGiven: issue = ReportIssue() issue.setCategory(ExploitType.CERTIFICATE) issue.setDetails("Custom verify method declared in " + str(filename) + ". You should manually review certificate validation here." ) issue.setFile(filename) issue.setSeverity(Severity.WARNING) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData("Custom verify method declared in " + str(filename) + ". You should manually review certificate validation here." ) results.append(issue) warningGiven=True elif type(q) is list: for l in q: if type(l) is not None: recursive_find_verify(l,filename,results) elif hasattr(q,'_fields'): for f in q._fields: if type(getattr(q,f)) is not None: recursive_find_verify(getattr(q,f),filename,results) elif type(q) is list: for l in q: if type(l) is not None: recursive_find_verify(l,filename,results) elif hasattr(q,'_fields'): for f in q._fields: if type(getattr(q,f)) is not None: recursive_find_verify(getattr(q,f),filename,results) verifyIteration=1 unverified_sessions(results) return
def show_wv_vulns(s_list,i,results): """ Shows all identified web view vulnerabilities """ #BUG - This sometimes prints twice, successively which shouldn't happen #print "#"*100 issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData("WebView: " +str(i[0])) results.append(issue) #logger.info("WebView: " +str(i[0])) issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData("File: " + str(i[1]) +"\n") results.append(issue) #logger.info("File: " + str(i[1]) +"\n") if len(s_list)==0: default_wv_config(i[0], i[1], int(common.minSdkVersion), results) return for f in s_list: sl=re.sub(r'WebSettings\s*','',f) sl=re.sub(r'\s*[;=].*$','',sl) sl=re.sub(r'final\s','',sl) #strip string whitespace out sl=re.sub(r'^\W+','',sl) sl=re.sub(r'\.\w+\(\w+\)$','',sl) sl=sl.rstrip() #Regex to look for javascript being enabled #BUG I can reduce the number of files checked to only those that have the name / import WebViews #Probably need to check for alternative true/false value representations wv_js_check=sl +'.setJavaScriptEnabled(true)' wv_js_check=re.escape(wv_js_check) #check if webview JS in enabled #BUG - THis can run twice, perhaps it is an artifact of an empty first element? if wv_config(i[1],wv_js_check): issue = ReportIssue() issue.setCategory(ExploitType.WEBVIEW) issue.setDetails(common.config.get('qarkhelper', 'JS_WARNING')) issue.setFile(str(i[1])) issue.setSeverity(Severity.WARNING) issue.setExtras(IS_JS_ENABLED, True) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData(common.config.get('qarkhelper', 'TERMINAL_JS_WARNING') +" "+str(i[0]) +" "+common.config.get('qarkhelper', 'TERMINAL_JS_WARNING1') + " To validate this vulnerability, load the following url in this WebView: http://www.secbro.com/poc/html/JS_WARNING.html" + "Note: A local copy of this html file can also be found at <install_dir>/quark/poc/html/JS_WARNING.html\n") results.append(issue) else: issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData(common.config.get('qarkhelper', 'JS_OK') + " "+str(i[0]) + str(i[1])) results.append(issue) #BUG - this is actually set on WebView #Check whether webview sets arbitrary BaseURL wv_burl_check=re.escape(sl +'.loadDataWithBaseURL') if wv_config(i[1],wv_burl_check): issue = ReportIssue() issue.setCategory(ExploitType.WEBVIEW) issue.setDetails(common.config.get('qarkhelper', 'BURL_WARNING1')) issue.setFile(str(i[1])) issue.setSeverity(Severity.WARNING) issue.setExtras(IS_BASE_URL_DEFINED, False) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData(common.config.get('qarkhelper', 'TERMINAL_BURL_WARNING1') + " "+str(i[0]) +" "+common.config.get('qarkhelper', 'TERMINAL_BURL_WARNING2') + "To validate this vulnerability, load the following url in this WebView: http://www.secbro.com/poc/html/BURL_WARNING.html " + "Note: A local copy of this html file can also be found at <install_dir>/quark/poc/html/BURL_WARNING.html\n") results.append(issue) else: issue = ReportIssue() issue.setCategory(ExploitType.WEBVIEW) issue.setDetails(common.config.get('qarkhelper', 'BURL_OK')) issue.setFile(str(i[1])) issue.setSeverity(Severity.INFO) issue.setExtras(IS_BASE_URL_DEFINED, True) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData(common.config.get('qarkhelper', 'BURL_OK')) results.append(issue) #Checks whether file URI can access filesystem #true by default, so the check is inverted wv_file_check=re.escape(sl+'.setAllowFileAccess(false)') if wv_config(i[1],wv_file_check): issue = ReportIssue() issue.setCategory(ExploitType.WEBVIEW) issue.setDetails(common.config.get('qarkhelper', 'FILE_SYS_OK')) issue.setFile(str(i[1])) issue.setSeverity(Severity.WARNING) issue.setExtras(IS_FILE_ACCESS_ENABLED, False) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData(common.config.get('qarkhelper', 'FILE_SYS_OK') + str(i[0])) results.append(issue) else: issue = ReportIssue() issue.setCategory(ExploitType.WEBVIEW) issue.setDetails(common.config.get('qarkhelper', 'FILE_SYS_WARN1')) issue.setFile(str(i[1])) issue.setSeverity(Severity.WARNING) issue.setExtras(IS_FILE_ACCESS_ENABLED, True) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData(common.config.get('qarkhelper', 'TERMINAL_FILE_SYS_WARN1') + str(i[0]) +" "+ common.config.get('qarkhelper', 'TERMINAL_FILE_SYS_WARN2') + " To validate this vulnerability, load the following url in this WebView: http://www.secbro.com/poc/html/FILE_SYS_WARN.html " + "Note: A local copy of this html file can also be found at <install_dir>/quark/poc/html/FILE_SYS_WARN.html\n") results.append(issue) #Regex to determine if WebViews have Content Provider access (default = true) #Checks whether WebView can access Content Providers #true by default, so the check is inverted #BUG - This can run twice, perhaps due to an empty element wv_cpa_check=re.escape(sl+'.setAllowContentAccess(false)') if wv_config(i[1],wv_cpa_check): issue = ReportIssue() issue.setCategory(ExploitType.WEBVIEW) issue.setDetails(common.config.get('qarkhelper', 'WV_CPA_OK')) issue.setFile(str(i[1])) issue.setSeverity(Severity.INFO) issue.setExtras(IS_CP_ACCESS_ENABLED, False) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData(common.config.get('qarkhelper', 'WV_CPA_OK') + str(i[0])) results.append(issue) else: issue = ReportIssue() issue.setCategory(ExploitType.WEBVIEW) issue.setDetails(common.config.get('qarkhelper', 'WV_CPA_WARNING')) issue.setFile(str(i[1])) issue.setSeverity(Severity.WARNING) issue.setExtras(IS_CP_ACCESS_ENABLED, True) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData(common.config.get('qarkhelper', 'TERMINAL_WV_CPA_WARNING') + str(i[0]) + "To validate this vulnerability, load the following url in this WebView: http://www.secbro.com/poc/html/WV_CPA_WARNING.html " + "Note: A local copy of this html file can also be found at <install_dir>/quark/poc/html/WV_CPA_WARNING.html\n") results.append(issue) #check for JS access from file URL can access content from any origin #minSdk <= 15 default is true; minSdk > 16 default is false #BUG - This check is wrong on the second if; If set to false and not found, it prints OK if int(common.minSdkVersion) <16: wv_univ_file_access=re.escape(sl+'.setAllowUniversalAccessFromFileURLs(false)') if not wv_config(i[1],wv_univ_file_access): issue = ReportIssue() issue.setCategory(ExploitType.WEBVIEW) issue.setDetails(common.config.get('qarkhelper', 'UNIV_FILE_WARNING')) issue.setFile(str(i[1])) issue.setSeverity(Severity.WARNING) issue.setExtras(IS_FILE_ACCESS_ENABLED, True) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData(common.config.get('qarkhelper', 'TERMINAL_UNIV_FILE_WARNING') +str(i[0]) + " To validate this vulnerability, load the following url in this WebView: http://www.secbro.com/poc/html/UNIV_FILE_WARNING.html " + "Note: A local copy of this html file can also be found at <install_dir>/quark/poc/html/UNIV_FILE_WARNING.html\n") results.append(issue) skip_next=True else: issue = ReportIssue() issue.setCategory(ExploitType.WEBVIEW) issue.setDetails(common.config.get('qarkhelper', 'UNIV_FILE_OK')) issue.setFile(str(i[1])) issue.setSeverity(Severity.INFO) issue.setExtras(IS_FILE_ACCESS_ENABLED, False) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData(common.config.get('qarkhelper', 'UNIV_FILE_OK') + str(i[0])) results.append(issue) skip_next=False #checking previous value above, as this is ignored if the above is true #could I just put pass above? if skip_next: pass else: #minSdk <= 15 default is true; minSdk > 16 default is false wv_allow_file_access_furls=re.escape(sl+'.setAllowFileAccessFromFileURLs(false)') if wv_config(i[1],wv_allow_file_access_furls): issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData("This WebView does not have access to File URLs - setAllowFileAccessFromFileURLs(false)" + str(i[0])) results.append(issue) issue = ReportIssue() issue.setCategory(ExploitType.WEBVIEW) issue.setDetails("This WebView does not have access to File URLs - setAllowFileAccessFromFileURLs(false)") issue.setFile(str(i[1])) issue.setSeverity(Severity.WARNING) issue.setExtras(IS_FILE_ACCESS_ENABLED, False) results.append(issue) else: issue = ReportIssue() issue.setCategory(ExploitType.WEBVIEW) issue.setDetails(common.config.get('qarkhelper', 'UNIV_FILE_WARNING')) issue.setFile(str(i[1])) issue.setSeverity(Severity.WARNING) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setExtras(IS_FILE_ACCESS_ENABLED, True) issue.setData(common.config.get('qarkhelper', 'TERMINAL_UNIV_FILE_WARNING') + str(i[0]) + "To validate this vulnerability, load the following url in this WebView: http://www.secbro.com/poc/html/UNIV_FILE_WARNING2.html "+ "Note: A local copy of this html file can also be found at <install_dir>/quark/poc/html/UNIV_FILE_WARNING2.html\n") results.append(issue) else: wv_univ_file_access=re.escape(sl+'.setAllowUniversalAccessFromFileURLs(true)') if wv_config(i[1],wv_univ_file_access): issue = ReportIssue() issue.setCategory(ExploitType.WEBVIEW) issue.setDetails(common.config.get('qarkhelper', 'UNIV_FILE_WARNING')) issue.setFile(str(i[1])) issue.setSeverity(Severity.WARNING) issue.setExtras(IS_UNIVERSAL_FILE_ACCESS_ENABLED, True) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData(common.config.get('qarkhelper', 'TERMINAL_UNIV_FILE_WARNING') + '1 '+str(i[0]) + " To validate this vulnerability, load the following url in this WebView: http://www.secbro.com/poc/html/UNIV_FILE_WARNING.html " + "Note: A local copy of this html file can also be found at <install_dir>/quark/poc/html/UNIV_FILE_WARNING.html\n") results.append(issue) skip_next=True else: issue = ReportIssue() issue.setCategory(ExploitType.WEBVIEW) issue.setDetails(common.config.get('qarkhelper', 'UNIV_FILE_OK')) issue.setFile(str(i[1])) issue.setSeverity(Severity.INFO) issue.setExtras(IS_UNIVERSAL_FILE_ACCESS_ENABLED, False) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData(common.config.get('qarkhelper', 'UNIV_FILE_OK') + str(i[0])) results.append(issue) skip_next=False #checking previous value above, as this is ignored if the above is true if skip_next: pass else: #minSdk <= 15 default is true; minSdk > 16 default is false wv_allow_file_access_furls=re.escape(sl+'.setAllowFileAccessFromFileURLs(true)') if wv_config(i[1],wv_allow_file_access_furls): issue = ReportIssue() issue.setCategory(ExploitType.WEBVIEW) issue.setDetails(common.config.get('qarkhelper', 'FURL_FILE_WARNING')) issue.setFile(str(i[1])) issue.setSeverity(Severity.WARNING) issue.setExtras(IS_UNIVERSAL_FILE_ACCESS_ENABLED, True) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData(common.config.get('qarkhelper', 'TERMINAL_FURL_FILE_WARNING') + str(i[0]) + "To validate this vulnerability, load the following url in this WebView: http://www.secbro.com/poc/html/FURL_FILE_WARNING.html " + "Note: A local copy of this html file can also be found at <install_dir>/quark/poc/html/FURL_FILE_WARNING.html\n") results.append(issue) else: issue = ReportIssue() issue.setCategory(ExploitType.WEBVIEW) issue.setDetails(common.config.get('qarkhelper', 'FURL_FILE_OK')) issue.setFile(str(i[1])) issue.setSeverity(Severity.INFO) issue.setExtras(IS_UNIVERSAL_FILE_ACCESS_ENABLED, False) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData(common.config.get('qarkhelper', 'FURL_FILE_OK') + str(i[0])) results.append(issue) #Checking whether plugins are enabled for WebViews #setPluginsEnabled deprecated in API 9, removed in API 18 #setPluginState added in API 8, deprecated in API 18 wv_plugsinenabled=re.escape(sl+'.setPluginsEnabled(true)') wv_pluginstate=re.escape(sl+'.setPluginState(WebSettings.PluginState.ON*') if wv_config(i[1],wv_plugsinenabled): if int(common.minSdkVersion) < 18: issue = ReportIssue() issue.setCategory(ExploitType.WEBVIEW) issue.setDetails(common.config.get('qarkhelper', 'DEPRECATED_SINCE_9') +str(i[0]) + "<br>FILE: " +str(i[1])) issue.setFile(str(i[1])) issue.setSeverity(Severity.INFO) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData(common.config.get('qarkhelper', 'DEPRECATED_SINCE_9') +str(i[0])) results.append(issue) else: issue = ReportIssue() issue.setCategory(ExploitType.WEBVIEW) issue.setDetails(common.config.get('qarkhelper', 'REMOVED_IN_18')+str(i[0]) + "<br>FILE: " +str(i[1])) issue.setFile(str(i[1])) issue.setSeverity(Severity.INFO) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData(common.config.get('qarkhelper', 'REMOVED_IN_18')+str(i[0])) results.append(issue) logger.info(common.config.get('qarkhelper', 'REMOVED_IN_18')+str(i[0])) if wv_config(i[1],wv_pluginstate): if int(common.minSdkVersion) < 8: issue = ReportIssue() issue.setCategory(ExploitType.WEBVIEW) issue.setDetails(common.config.get('qarkhelper', 'ADDED_IN_8')+str(i[0]) + "<br>FILE: " +str(i[1])) issue.setFile(str(i[1])) issue.setSeverity(Severity.INFO) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData(common.config.get('qarkhelper', 'ADDED_IN_8')+str(i[0])) results.append(issue) logger.info(common.config.get('qarkhelper', 'ADDED_IN_8')+str(i[0])) else: issue = ReportIssue() issue.setCategory(ExploitType.WEBVIEW) issue.setDetails(common.config.get('qarkhelper', 'DEPRECATED_IN_18')+str(i[0]) + "<br>FILE: " +str(i[1])) issue.setFile(str(i[1])) issue.setSeverity(Severity.INFO) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData(common.config.get('qarkhelper', 'DEPRECATED_IN_18')+str(i[0])) results.append(issue) #Check if addJavascriptInterface is used in WebView #BUG - this is actually on WebView, not settings wv_ajs=re.escape(sl+'.addJavascriptInterface') if wv_config(i[1],wv_ajs): if int(common.minSdkVersion)<17: issue = ReportIssue() issue.setCategory(ExploitType.WEBVIEW) issue.setDetails(common.config.get('qarkhelper', 'BAD_JS_INT')) issue.setFile(str(i[1])) issue.setSeverity(Severity.WARNING) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.WARNING) issue.setData(common.config.get('qarkhelper', 'TERMINAL_BAD_JS_INT') + " "+str(i[0]) + " To validate this vulnerability, load the following url in this WebView: http://www.secbro.com/poc/html/BAD_JS_INT.html " + "Note: A local copy of this html file can also be found at <install_dir>/quark/poc/html/BAD_JS_INT.html" +"\n") results.append(issue) else: issue = ReportIssue() issue.setCategory(ExploitType.WEBVIEW) issue.setDetails(common.config.get('qarkhelper', 'OK_JS_INT') + str(i[0]) + "<br>FILE: " +str(i[1])) issue.setFile(str(i[1])) issue.setSeverity(Severity.INFO) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData(common.config.get('qarkhelper', 'OK_JS_INT')) results.append(issue) else: issue = ReportIssue() issue.setCategory(ExploitType.WEBVIEW) issue.setDetails(common.config.get('qarkhelper', 'NO_JS_INT') + "<br>FILE: " +str(i[1])) issue.setFile(str(i[1])) issue.setSeverity(Severity.INFO) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData(common.config.get('qarkhelper', 'NO_JS_INT') + str(i[0])) results.append(issue) #Check if WebView has DOMStorage enabled wv_setdom=re.escape(sl+'.setDomStorageEnabled(true)') if wv_config(i[1],wv_setdom): issue = ReportIssue() issue.setCategory(ExploitType.WEBVIEW) issue.setDetails(common.config.get('qarkhelper', 'DOM_STORAGE_EN') + str(i[0]) + "<br>FILE: " +str(i[1])) issue.setFile(str(i[1])) issue.setSeverity(Severity.INFO) issue.setExtras(IS_DOM_STORAGE_ENABLED, True) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData(common.config.get('qarkhelper', 'DOM_STORAGE_EN')) results.append(issue) else: issue = ReportIssue() issue.setCategory(ExploitType.WEBVIEW) issue.setDetails(common.config.get('qarkhelper', 'DOM_STORAGE_DIS') + "<br>FILE: " +str(i[1])) issue.setFile(str(i[1])) issue.setSeverity(Severity.INFO) issue.setExtras(IS_DOM_STORAGE_ENABLED, False) results.append(issue) issue = terminalPrint() issue.setLevel(Severity.INFO) issue.setData(common.config.get('qarkhelper', 'DOM_STORAGE_DIS') + str(i[0])) results.append(issue) return