def target(self, queue): files = common.java_files global parser, tree, filepath parser = plyj.Parser() tree = '' res = [] count = 0 for f in files: count += 1 pub.sendMessage('progress', bar=self.name, percent=round(count * 100 / len(files))) filepath = str(f) try: # Parse the java file to an AST tree = parser.parse_file(f) except Exception as e: common.logger.exception("Unable to parse the file and generate as AST. Error: " + str(e)) continue try: for import_decl in tree.import_declarations: # Check if DexClassLoader is called in the import statement; example import dalvik.system.DexClassLoader if self.DEX_CLASS_LOADER in import_decl.name.value: for type_decl in tree.type_declarations: # Check class declaration within the java source code if type(type_decl) is m.ClassDeclaration: # Traverse through every field declared in the class for fields in type_decl.body: try: self.recursive_classloader_function(fields, f, res) except Exception as e: common.logger.error("Unable to run class loader plugin " + str(e)) except Exception as e: common.logger.debug("Plyj parser failed while parsing the file: " + filepath + "\nError" + str(e)) continue try: for type_decl in tree.type_declarations: # Check class declaration within the java source code if type(type_decl) is m.ClassDeclaration: # Traverse through every field declared in the class for fields in type_decl.body: try: self.recursive_register_receiver_function(fields, f, res) except Exception as e: common.logger.error("Unable to run register receiver function plugin " + str(e)) except Exception as e: common.logger.debug("Plyj parser failed while parsing the file: " + filepath + "\nError" + str(e)) continue # Arrange the Broadcast Receivers created Dynamically in column format and store it in the variable -> Broadcast_Receiver br_list = "\n".join(receivers_list) if receivers_list: # Report the issue in the file and display it on the terminal PluginUtil.reportWarning(filepath, broadcast_receiver(br_list), res) queue.put(res)
def testReportIssue(): res = [] PluginUtil.reportIssue('fileName', 'details', res) assert len(res) == 2 assert res[0].getCategory() == ExploitType.PLUGIN assert res[0].getSeverity() == Severity.VULNERABILITY assert res[0].getFile() == 'fileName' assert res[0].getDetails() == 'details' assert res[1].getLevel() == Severity.VULNERABILITY assert res[1].getData() == 'details'
def recursive_insecure_call_function(self, fields, file, res): if type(fields) is m.MethodDeclaration: if str(fields.name) == self.CALL_FUNCTION: PluginUtil.reportInfo(filepath, insecure_function(filepath), res) elif type(fields) is list: for fieldname in fields: self.recursive_insecure_call_function(fieldname, file, res) elif hasattr(fields, '_fields'): for fieldname in fields._fields: self.recursive_insecure_call_function(getattr(fields, fieldname), file, res) return
def target(self, queue): f = str(common.manifest) res = [] count = 0 ordered_broadcast = [] path_variable_list =[] launch_mode_list =[] global fileName # full path to app manifest fileName = qarkMain.find_manifest_in_source() receivers = self.UserCreatedReceivers() for receiver in receivers: if "exported" and "true" in str(receiver): if not any(re.findall(self.PRIORITY_REGEX, str(receiver))): ordered_broadcast.append(str(receiver)) # Arrange exported broadcast receiver without priority set in column format list_orderedBR = " \n".join(ordered_broadcast) if ordered_broadcast: PluginUtil.reportWarning(fileName, self.OrderedBroadcastIssueDetails(list_orderedBR), res) for line in f.splitlines(): count += 1 # update progress bar pub.sendMessage('progress', bar=self.name, percent=round(count * 100 / len(f.splitlines()))) if any(re.findall(self.PATH_USAGE, line)): path_variable_list.append(line) if any(re.findall(self.LAUNCH_MODE, line)): launch_mode_list.append(line) if any(re.findall(self.TASK_REPARENTING, line)): PluginUtil.reportInfo(fileName, self.TaskReparentingIssue(fileName), res) # Arrange identified path variable and launch mode usage in column format path_variable = " \n".join(path_variable_list) launch_mode_variable = "\n".join(launch_mode_list) if path_variable_list: PluginUtil.reportWarning(fileName, self.PathUsageIssue(path_variable), res) if launch_mode_list: PluginUtil.reportInfo(fileName, self.LaunchModeIssue(launch_mode_variable), res) # Check for google safebrowsing API if "WebView" in f.splitlines(): if "EnableSafeBrowsing" and "true" not in f.splitlines(): PluginUtil.reportInfo(fileName, self.SafebrowsingIssueDetails(fileName), res) # send all results back to main thread queue.put(res)
def recursive_classloader_function(self, fields, f, res): if type(fields) is m.MethodDeclaration: if str(fields.name) == self.CLASS_LOADER: PluginUtil.reportInfo(filepath, class_loader(filepath), res) elif self.CLASS_LOADER in str(fields): PluginUtil.reportInfo(filepath, class_loader(filepath), res) elif type(fields) is list: for tree_object_fields in fields: self.recursive_classloader_function(tree_object_fields, f, res) elif hasattr(fields, '_fields'): for values in fields._fields: self.recursive_classloader_function(getattr(fields, values), f, res) return
def target(self, queue): # get all decompiled files that contains usage of TelephonyManager files = common.text_scan(common.java_files, self.telephonyManagerRegex) res = [] count = 0 for f in files: count += 1 pub.sendMessage('progress', bar=self.getName(), percent=round(count * 100 / len(files))) # get decompiled file body fileName = f[1] with open(fileName, 'r') as fi: fileBody = fi.read() # report if file contains inline call if PluginUtil.contains(self.inlineRegex, fileBody): PluginUtil.reportInfo(fileName, self.PhoneIdentifierIssueDetails(fileName), res) break # report if any TelephonyManager variables invokes calls to get phone identifiers for varName in PluginUtil.returnGroupMatches(self.varNameRegex, 2, fileBody): if PluginUtil.contains(r'%s\.(getLine1Number|getDeviceId)\(.*?\)' % varName, fileBody): PluginUtil.reportInfo(fileName, self.PhoneIdentifierIssueDetails(fileName), res) break queue.put(res)
def target(self, queue): # get all decompiled files that contains usage of WebView files = common.text_scan(common.java_files, self.webViewRegex) res = [] count = 0 for f in files: count += 1 pub.sendMessage('progress', bar=self.getName(), percent=round(count * 100 / len(files))) # get decompiled file body fileName = f[1] with open(fileName, 'r') as fi: fileBody = fi.read() # report if file contains any inline calls if PluginUtil.contains(self.inlineRegex, fileBody): PluginUtil.reportIssue(fileName, self.createIssueDetails(fileName), res) break # report if any WebView variables invoke calls for varName in PluginUtil.returnGroupMatches(self.varNameRegex, 2, fileBody): if PluginUtil.contains(r'%s\.addJavascriptInterface\(.*?\)' % varName, fileBody): PluginUtil.reportIssue(fileName, self.createIssueDetails(fileName), res) break queue.put(res)
def target(self, queue): files = common.java_files global filepath, tree parser = plyj.Parser() tree = '' res = [] count = 0 for f in files: count += 1 pub.sendMessage('progress', bar=self.name, percent=round(count * 100 / len(files))) filepath = str(f) try: tree = parser.parse_file(f) except Exception as e: common.logger.exception( "Unable to parse the file and generate as AST. Error: " + str(e)) continue try: for import_decl in tree.import_declarations: # Check if Intent is called in the import statement if 'Intent' in import_decl.name.value: with open(filepath, 'r') as r: file_body = r.read() if PluginUtil.contains(self.NEW_TASK, file_body): PluginUtil.reportInfo(filepath, new_task(filepath), res) break if PluginUtil.contains(self.MULTIPLE_TASK_TASK, file_body): PluginUtil.reportInfo(filepath, multiple_task(filepath), res) break except Exception as e: common.logger.debug("Plyj parser failed while parsing the file: " + filepath + "\nError" + str(e)) continue queue.put(res)
def target(self, queue): files = common.java_files global parser parser = plyj.Parser() global tree global fileName tree = '' res = [] count = 0 for f in files: count += 1 pub.sendMessage('progress', bar=self.name, percent=round(count * 100 / len(files))) fileName = str(f) try: tree = parser.parse_file(f) except Exception: continue try: global url url = [] for import_decl in tree.import_declarations: if 'HttpURLConnection' in import_decl.name.value or 'URL' in import_decl.name.value: textfile = str(open(fileName, 'r').read()) search = "http://" http_result = re.findall('\\b'+search+'\\b', textfile) if http_result: url = re.findall(self.http_url_regex, textfile) http_url_list = " \n".join(url) PluginUtil.reportInfo(fileName, self.HardcodedHTTPUrlsIssueDetails((fileName, http_url_list)), res) break else: continue except Exception: continue queue.put(res)
def test_check_perm_regex7(): assert PluginUtil.contains(plugin.CHECK_PERMISSION, 'SelfUriPermission') is False
def test_check_perm_regex2(): assert PluginUtil.contains(plugin.CHECK_PERMISSION, 'checkPermission') is True
def test_regex12(): text = 'priority' assert PluginUtil.contains(plugin.PRIORITY_REGEX, text) is True
def testGetVarNameWithoutPackageName(): text = 'TelephonyManager paramContext;' res = PluginUtil.returnGroupMatches(plugin.varNameRegex, 2, text) assert len(res) == 1 assert res[0] == 'paramContext'
def test_regex5(): assert not PluginUtil.contains(plugin.CHECK_PUBLIC_DIR, 'GetExternalStoragePublicDirectory')
def test_regex2(): text = 'intent.setFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);' assert not PluginUtil.contains(plugin.NEW_TASK, text)
def test_regex2(): assert PluginUtil.contains(plugin.CLASS_LOADER, 'loadClass') is True
def test_regex(): text = 'intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);' assert PluginUtil.contains(plugin.NEW_TASK, text)
def test_regex5(): text = 'intent.setFlags(Intent.FLAGACTIVITYMULTIPLETASK);' assert not PluginUtil.contains(plugin.MULTIPLE_TASK, text)
def testTwoGroupMatches(): res = PluginUtil.returnGroupMatches(r'(test123)', 1, 'test123test321test123') assert len(res) == 2 assert res[0] == 'test123' assert res[1] == 'test123'
def testOneGroupMatch(): res = PluginUtil.returnGroupMatches(r'(test123)', 1, 'test321test123test321') assert len(res) == 1 assert res[0] == 'test123'
def testZeroGroupMatches(): assert len(PluginUtil.returnGroupMatches(r'(test123)', 1, 'test321')) == 0
def test_enforce_perm_regex2(): text = 'enforcePermission' assert PluginUtil.contains(plugin.ENFORCE_PERMISSION, text) is True
def test_regex3(): assert PluginUtil.contains(plugin.CLASS_LOADER, 'Classload') is False
def test_enforce_perm_regex8(): text = 'enforcePermission("santos.benign.permission","Not allowed to start MyService")' assert PluginUtil.contains(plugin.ENFORCE_PERMISSION, text) is True
def test_regex5(): assert PluginUtil.contains(plugin.DYNAMIC_BROADCAST_RECEIVER, 'RegisterReceiver') is False
def test_regex1(): text = 'intent.setFlags(Intent.FLAGACTIVITYNEWTASK);' assert not PluginUtil.contains(plugin.NEW_TASK, text)
def test_regex(): assert PluginUtil.contains(plugin.DEX_CLASS_LOADER, 'DexClassLoader') is True
def testInlineWithoutPackageName(): text = '((TelephonyManager)paramContext.getSystemService("phone")).getLine1Number();' assert PluginUtil.contains(plugin.inlineRegex, text) is True
def test_regex1(): assert PluginUtil.contains(plugin.DEX_CLASS_LOADER, 'ClassLoader') is False
def testGetVarNameInstantiation(): text = 'TelephonyManager paramContext = (TelephonyManager)paramContext.getSystemService("phone"));' res = PluginUtil.returnGroupMatches(plugin.varNameRegex, 2, text) assert len(res) == 1 assert res[0] == 'paramContext'
def target(self, queue): f = str(common.manifest) res = [] count = 0 ordered_broadcast = [] path_variable_list = [] launch_mode_list = [] global fileName # full path to app manifest fileName = qarkMain.find_manifest_in_source() receivers = self.UserCreatedReceivers() for receiver in receivers: if "exported" and "true" in str(receiver): if not any(re.findall(self.PRIORITY_REGEX, str(receiver))): ordered_broadcast.append(str(receiver)) # Arrange exported broadcast receiver without priority set in column format list_orderedBR = " \n".join(ordered_broadcast) if ordered_broadcast: PluginUtil.reportWarning( fileName, self.OrderedBroadcastIssueDetails(list_orderedBR), res) for line in f.splitlines(): count += 1 # update progress bar pub.sendMessage('progress', bar=self.name, percent=round(count * 100 / len(f.splitlines()))) if any(re.findall(self.PATH_USAGE, line)): path_variable_list.append(line) if any(re.findall(self.LAUNCH_MODE, line)): launch_mode_list.append(line) if any(re.findall(self.TASK_REPARENTING, line)): PluginUtil.reportInfo(fileName, self.TaskReparentingIssue(fileName), res) # Arrange identified path variable and launch mode usage in column format path_variable = " \n".join(path_variable_list) launch_mode_variable = "\n".join(launch_mode_list) if path_variable_list: PluginUtil.reportWarning(fileName, self.PathUsageIssue(path_variable), res) if launch_mode_list: PluginUtil.reportInfo(fileName, self.LaunchModeIssue(launch_mode_variable), res) # Check for google safebrowsing API if "WebView" in f.splitlines(): if "EnableSafeBrowsing" and "true" not in f.splitlines(): PluginUtil.reportInfo(fileName, self.SafebrowsingIssueDetails(fileName), res) # send all results back to main thread queue.put(res)
def testContains(): assert PluginUtil.contains(r'test123', 'test123') is True
def test_regex2(): text = '"NtY163ManCAb"' assert not PluginUtil.contains(plugin.API_KEY_REGEX, text)
def testlog_regex1(): assert PluginUtil.contains(plugin.debug_regex, 'd') is False
def test_regex4(): text = 'public static final String API_TOKEN = "1234thisisaninvalidapitoken937235"' assert PluginUtil.contains(plugin.API_KEY_REGEX, text)
def test_check_perm_regex6(): assert PluginUtil.contains(plugin.CHECK_PERMISSION, 'checkCalling') is False
def test_regex5(): text = 'public static final String API_TOKEN = "$%#%~!^"' assert PluginUtil.contains(plugin.SPECIAL_CHAR_REGEX, text)
def test_enforce_perm_regex1(): text = 'enforceCallingOrSelfUriPermission' assert PluginUtil.contains(plugin.ENFORCE_PERMISSION, text) is True
def test_regex1(): text = 'public static final String API_TOKEN = "Nti4kWY-qRHTYq3dsbeip0P1tbGCzs2BAY163ManCAb"' assert PluginUtil.contains(plugin.API_KEY_REGEX, text)
def test_enforce_perm_regex6(): text = 'enforceCallingPermission' assert PluginUtil.contains(plugin.ENFORCE_PERMISSION, text) is False
def test_regex1(): assert PluginUtil.contains(plugin.PATH_USAGE, 'android:pathPrefix=') is False
def test_check_perm_regex1(): assert PluginUtil.contains(plugin.CHECK_PERMISSION, 'checkCallingOrSelfUriPermission') is True
def test_regex2(): assert PluginUtil.contains(plugin.PATH_USAGE, 'android:pathPattern') is False
def test_regex3(): text = "android:launchMode='singleTask'" assert PluginUtil.contains(plugin.LAUNCH_MODE, text) is True
def test_regex3(): assert not PluginUtil.contains(plugin.CHECK_EXTERNAL_MEDIA, 'GetExternalMediaDirs')
def target(self, queue): global filepath, tree files = common.java_files parser = plyj.Parser() tree = '' external_pub_dir, external_media, external_storage, res = ( [] for _ in xrange(4)) count = 0 for f in files: count += 1 pub.sendMessage('progress', bar=self.name, percent=round(count * 100 / len(files))) filepath = str(f) try: tree = parser.parse_file(f) except Exception as e: common.logger.exception( "Unable to parse the file and generate as AST. Error: " + str(e)) continue try: for import_decl in tree.import_declarations: if 'File' in import_decl.name.value: with open(filepath, 'r') as fr: file_body = fr.read() if PluginUtil.contains(self.CHECK_EXTERNAL_STORAGE, file_body): external_storage.append(filepath) break if PluginUtil.contains(self.CHECK_EXTERNAL_MEDIA, file_body): external_media.append(filepath) break if PluginUtil.contains(self.CHECK_PUBLIC_DIR, file_body): external_pub_dir.append(filepath) break except Exception as e: common.logger.debug( "Plyj parser failed while parsing the file: " + filepath + "\nError" + str(e)) continue # Store the content obtained above in a column format storage = "\n".join(external_storage) media = "\n".join(external_media) pub_dir = "\n".join(external_pub_dir) if external_storage: PluginUtil.reportWarning(filepath, check_external_storage(storage), res) if external_media: PluginUtil.reportWarning(filepath, check_media_directory(media), res) if external_pub_dir: PluginUtil.reportWarning(filepath, check_public_directory(pub_dir), res) queue.put(res)
def test_regex(): assert PluginUtil.contains(plugin.CHECK_EXTERNAL_STORAGE, 'getExternalFilesDir')
def test_regex5(): text = "android:allowTaskReparenting='true'" assert PluginUtil.contains(plugin.TASK_REPARENTING, text) is True
def testInlineGetDeviceId(): text = '((android.telephony.TelephonyManager)paramContext.getSystemService("phone")).getDeviceId();' assert PluginUtil.contains(plugin.inlineRegex, text) is True
def test_regex6(): text = 'android:allowTaskReparenting="true"' assert PluginUtil.contains(plugin.TASK_REPARENTING, text) is True
def testGetVarNameLastArgument(): text = 'void func(int i, TelephonyManager paramContext)' res = PluginUtil.returnGroupMatches(plugin.varNameRegex, 2, text) assert len(res) == 1 assert res[0] == 'paramContext'
def test_regex8(): text = '<receiver android:name=".FormatOutgoingCallReceiver" android:enabled="true" android:exported="true"' assert PluginUtil.contains(plugin.RECEIVER_REGEX, text) is False
def testTelephonyManagerRegex(): assert PluginUtil.contains(plugin.telephonyManagerRegex, 'import android.telephony.TelephonyManager') is True
def test_regex11(): text = 'Priority' assert PluginUtil.contains(plugin.PRIORITY_REGEX, text) is False
def test_regex4(): text = 'android:launchMode="singleTask"' assert PluginUtil.contains(plugin.LAUNCH_MODE, text) is True
def testNotContains(): assert PluginUtil.contains(r'test123', 'test321') is False