def run(self): result = { "title": "Application Does Not Use Prepared Statements", "details": "", "severity": "Low", "report": False } symb_module = SymbolsModule() symb_module.binary = self.binary symbols_result, symbols = symb_module.run(), None for key in symbols_result: if key.endswith("_symbols"): symbols = symbols_result[key] if not symbols: return {"print": "Couldn't get symbols from binary."} Log.info("Analysing Symbols") sqlite_matches = re.findall(self._sqlite_regex, symbols) matches = re.findall(self._regex, symbols) if sqlite_matches and not matches: result.update({ "report": True, "details": "Evidences of SQLite being used were found but no \ evidence of prepared statements being used was found." }) return {"{}_result".format(self.name()): result}
def run(self): result = { "title": "Application Does Not Check For Third-Party Keyboards", "details": "", "severity": "Medium", "report": False } symb_module = SymbolsModule() symb_module.binary = self.binary symbols_result, symbols = symb_module.run(), None for key in symbols_result: if key.endswith("_symbols"): symbols = symbols_result[key] if not symbols: return {"print": "Couldn't get symbols from binary."} Log.info("Analysing Symbols") if not re.search(self._regex, symbols): result.update({ "report": True, "details": "No evidence of third party keyboard detection \ functions found." }) return {"{}_result".format(self.name()): result}
def run(self): result = { "title": "Application Logs To Syslog", "details": "", "severity": "Low", "report": True } Log.info("Getting executable's name") info_module = InfoModule() info_module.identifier = self.identifier info_module.device = self.device info_result, info = info_module.run(), None for key in info_result: if key.endswith("_info"): info = info_result[key] if not info: return {"print": "Couldn't get Info from device."} executable_name = info["CFBundleExecutable"] Log.info("Getting application's logs") logs = self.device.logs(executable_name) if logs: result.update({ "report": True, "details": "The following logs were found:\n{}".format(logs) }) return {"{}_result".format(self.name()): result}
def run(self): result = { "title": "Application Does Not Target The Latest SDK", "details": "", "severity": "Low", "report": False } # create yaml apktool_module = YamlModule() apktool_module.decompiled_apk = self.decompiled_apk self.apktool = apktool_module.run() if "print" in self.apktool: return {"print": "Could not get the apktool yaml file"} self.apktool = self.apktool.popitem()[1] Log.info("Analysing application's apktool yaml") target_sdk = self.apktool.target_sdk() if target_sdk and int(target_sdk) < int(self.targetsdk): result.update({ "report": True, "details": "* Current target supported SDK \ version\ntargetSdkVersion=\"{}\"".format(target_sdk) }) return { "{}_result".format(self.name()): result, "{}_targetsdk".format(self.apktool.apk_filename()): target_sdk }
def run(self): result = { "title": "Application Does Not Check For Third-Party Keyboards", "details": "", "severity": "Low", "report": False } # preparing variable to run third_party_keyboard_evidence = {} ignore = [filepath.strip() for filepath in self.ignore.split(";")] Log.info("Identifying smali directories") dirs = smali_dirs(self.decompiled_apk) Log.info("Analysing application's smali code") for directory in dirs: smali = "{}/{}".format(self.decompiled_apk, directory) third_party_keyboard_evidence.update(pretty_grep( self.regex, smali)) # remove ignored paths to_remove = [] for filename in third_party_keyboard_evidence: if any(filepath in filename for filepath in ignore): to_remove += [filename] for filename in to_remove: third_party_keyboard_evidence.pop(filename) if not third_party_keyboard_evidence: result.update({"report": True}) return {"{}_result".format(self.name()): result}
def run(self): Log.info("Creating decompilation directory") # create decompiled directory identifier = self.apk.rsplit("/", 1)[-1].lower().rsplit(".", 1)[0] output_path = "{}/{}.decompiled".format(self.output, identifier) execute("mkdir -p {}".format(output_path)) # unzip Log.info("Decompiling application") decompile(self.apk, output_path) # get identifier manifest_module = ManifestModule() manifest_module.decompiled_apk = output_path self.manifest = manifest_module.run() if "print" not in self.manifest: identifier = self.manifest.popitem()[1].package() # move decompiled app to new path old_output_path = output_path output_path = "{}/{}.decompiled".format(self.output, identifier) execute("mv {} {}".format(old_output_path, output_path)) return { "{}_decompiled".format(identifier): output_path, "print": "Application decompiled to {}".format(output_path) }
def run(self): result = { "title": "Application Allows Files To Be Backed Up", "details": "", "severity": "Low", "report": False } Log.info("Checking if the application is installed") installed_apps = self.device.apps() if self.identifier not in installed_apps: return {"print": "Application not installed."} remote_data_path = installed_apps[self.identifier]["data"] files = self.device.find_files(remote_data_path) report_files = [] for file_path in files: if file_path: protection = self.device.backup_flag(file_path) if protection and "0" in protection: report_files += [file_path] if report_files: result.update({ "report": True, "details": "The following files were found to have the \ backup flag:\n* {}".format("\n* ".join(report_files)) }) return {"{}_result".format(self.name()): result}
def run(self): result = { "title": "Application Communicates Over Unencrypted Channels", "details": "", "severity": "Medium", "report": False } ignore = [url.strip() for url in self.ignore.split(";")] Log.info("Getting application's strings") strs = strings(self.binary) Log.info("Analysing strings") report_matches = [] matches = re.finditer(self._regex, strs) for item in matches: match = item.group() if any(iurl in match for iurl in ignore) or match == "http://": continue report_matches += [match] if report_matches: result.update({ "report": True, "details": "The following strings were found:\n* {}".format("\n* ".join( sorted(set(report_matches)))) }) return {"{}_result".format(self.name()): result}
def run(self): result = { "title": "Application Has World Writable Files", "details": "", "severity": "Medium", "report": False } if not self.device.installed(self.identifier): return {"print": "Application not installed"} Log.info("Starting the application") self.device.start(self.identifier) sleep(5) Log.info("Analysing application's data") target_paths = self.device.data_paths(self.identifier) world_writable_files = [] for data_path in target_paths: world_writable_files += self.device.world_files(data_path, "w") if world_writable_files: result.update({ "report": True, "details": "* World Writable Files:\n * {}".format( "\n* ".join(world_writable_files)) }) return {"{}_result".format(self.name()): result}
def run(self): result = { "title": "Application Does Not Implement Root Detection", "details": "", "severity": "High", "report": True } # preparing variable to run root_detection = {} ignore = [filepath.strip() for filepath in self.ignore.split(";")] Log.info("Identifying smali directories") dirs = smali_dirs(self.decompiled_apk) Log.info("Analysing application's smali code") for directory in dirs: smali = "{}/{}".format(self.decompiled_apk, directory) root_detection.update(pretty_grep(self.regex, smali)) if root_detection: result = { "title": "Application Has Root Detection", "details": pretty_grep_to_str(root_detection, self.decompiled_apk, ignore), "severity": "Low", "report": True } return {"{}_result".format(self.name()): result}
def run(self): result = { "title": "Application Uses Native Libraries", "details": "", "severity": "Low", "report": False } Log.info("Identifying application's libraries") libs_path = [lib.strip() for lib in self.libs.split(";")] libraries = [] if self.device.installed(self.identifier): app_path = self.device.packages()[self.identifier].rsplit("/", 1)[0] libs_path_str = " ".join( ["{}/{}".format(app_path, lib) for lib in libs_path]) libraries = [ lib for lib in self.device.root_execute("ls {}".format( libs_path_str)).split("\n") if lib and "No such file or directory" not in lib ] if libraries: result.update({ "report": True, "details": "* {}".format("\n* ".join(libraries)) }) return {"{}_result".format(self.name()): result}
def run(self): result = { "title": "Application Was Compiled Without ARC Support", "details": "", "severity": "Medium", "report": False } symb_module = SymbolsModule() symb_module.binary = self.binary symbols_result, symbols = symb_module.run(), None for key in symbols_result: if key.endswith("_symbols"): symbols = symbols_result[key] if not symbols: return {"print": "Couldn't get symbols from binary."} Log.info("Analysing Symbols") if not re.search(self._regex, symbols): result.update({ "report": True, "details": "No evidence of ARC functions found." }) return {"{}_result".format(self.name()): result}
def run(self): # create unzipped directory identifier = self.ipa.rsplit("/", 1)[-1].lower().rsplit(".", 1)[0] Log.info("Crating output directories") output_path = "{}/{}.unzipped".format(self.output, identifier) execute("mkdir -p {}".format(output_path)) # unzip Log.info("Unzipping application") unzip(self.ipa, output_path) # get new identifier app_path = application_path(output_path) # get info info_module = InfoModule() info_module.unzipped_ipa = output_path info = info_module.run() for key in info: if key.endswith("_info"): info = info[key] break # move to new directory if "CFBundleIdentifier" in info: identifier = info["CFBundleIdentifier"] old_output_path = output_path output_path = "{}/{}.unzipped".format(self.output, identifier) execute("mv {} {}".format(old_output_path, output_path)) return { "{}_unzipped".format(identifier): output_path, "print": "Application unzipped to {}".format(output_path) }
def run(self): result = { "title": "Application Makes Insecure Function Calls", "details": "", "severity": "Medium", "report": False } symb_module = SymbolsModule() symb_module.binary = self.binary symbols_result, symbols = symb_module.run(), None for key in symbols_result: if key.endswith("_symbols"): symbols = symbols_result[key] if not symbols: return {"print": "Couldn't get symbols from binary."} Log.info("Analysing Symbols") matches = re.findall(self.function_calls, symbols) if matches: result.update({ "report": True, "details": "The following function symbols were \ found: * {}".format("\n* ".join(sorted(set(matches)))) }) return {"{}_result".format(self.name()): result}
def run(self): result = { "title": "Application Uses Deprecated Ciphers", "details": "", "severity": "Low", "report": False } # preparing variable to run ciphers = {} ignore = [filepath.strip() for filepath in self.ignore.split(";")] Log.info("Identifying smali directories") dirs = smali_dirs(self.decompiled_apk) Log.info("Analysing application's smali code") for directory in dirs: smali = "{}/{}".format(self.decompiled_apk, directory) #ssl_socket_files = pretty_grep(self.file_regex, smali) ciphers.update(pretty_grep(self.regex, smali)) if ciphers: result.update({ "report": True, "details": pretty_grep_to_str(ciphers, self.decompiled_apk, ignore) }) return {"{}_result".format(self.name()): result}
def run(self): result = { "title": "Application Does Not Implement SSL Pinning", "details": "", "severity": "Medium", "report": False } Log.info("Getting application's strings") strs = strings(self.binary) Log.info("Analysing strings and class dump") matches = re.findall(self._regex, strs) evidence = pretty_grep(self._regex, self.class_dump) if matches: result.update({ "report": True, "details": "The following strings were found:\n* {}".format("\n* ".join( sorted(set(matches)))) }) if evidence: result.update({ "report": True, "details": "{}\nThe following was found in the class dump:\n\ {}".format(result["details"], pretty_grep_to_str(evidence, self.class_dump)) }) return {"{}_result".format(self.name()): result}
def run(self): result = { "title": "Application Does Not Disable Clipboard Access", "details": "", "severity": "Medium", "report": False } symb_module = SymbolsModule() symb_module.binary = self.binary symbols_result, symbols = symb_module.run(), None for key in symbols_result: if key.endswith("_symbols"): symbols = symbols_result[key] if not symbols: return {"print": "Couldn't get symbols from binary."} Log.info("Analysing Symbols") if not re.search(self._regex, symbols): result.update({ "report": True, "details": "No evidence of the application trying to disable \ clipboard access." }) return {"{}_result".format(self.name()): result}
def run(self): result = { "title": "Application Has Browsable Activities", "details": "", "severity": "Informational", "report": False } # create manifest manifest_module = ManifestModule() manifest_module.decompiled_apk = self.decompiled_apk self.manifest = manifest_module.run() if "print" in self.manifest: return {"print": "Could not get the manifest"} self.manifest = self.manifest.popitem()[1] Log.info("Getting browsable activities and uris") browsable_classes = self.manifest.browsable_activities() browsable_uris = self.manifest.browsable_uris() if browsable_classes or browsable_uris: details = "* URIs:\n * {}".format("\n * ".join(browsable_uris)) details += "\n\n* Classes:\n * {}".format( "\n * ".join(browsable_classes)) result.update({"report": True, "details": details}) return { "{}_result".format(self.name()): result, "{}_browsable_classes".format(self.manifest.package()): browsable_classes, "{}_browsable_uris".format(self.manifest.package()): browsable_uris }
def run(self): result = { "title": "Application Has Insecure ATS Configurations", "details": "", "severity": "Medium", "report": False } info_content = plist(self.info) Log.info("Parsing Info.plist file contents") ats_xml = plist_dict_to_xml(info_content, self._ats_key) Log.info("Analysing Info.plist file") if self._ats_key not in info_content or not info_content[ self._ats_key]: result.update({ "report": True, "details": "No evidence of ATS being implemented found." }) if any(option in ats_xml for option in self._insecure_options): result.update({ "report": True, "details": "The following insecure ATS configuration was \ found : {}".format(ats_xml) }) return {"{}_result".format(self.name()): result}
def run(self): # get the jar first jar_module = JarModule() jar_module.output = self.output jar_module.apk = self.apk result = jar_module.run() self.jar = [result[jar] for jar in result if jar.endswith("_jar")][0] if not self.jar: return {"print": "Could not decompile the application"} Log.info("Creating source directory") # create source directory identifier = self.jar.rsplit("/", 1)[-1].lower().rsplit(".", 1)[0] output_path = "{}/{}.source".format(self.output, identifier) execute("mkdir -p {}".format(output_path)) # unzip Log.info("Getting application's source") source(self.jar, output_path) return { "{}_source".format(identifier): output_path, "print": "Application source reversed to {}".format(output_path) }
def run(self): Log.info("Preparing to re-compile the application") # get identifier manifest_module = ManifestModule() manifest_module.decompiled_apk = self.decompiled_apk self.manifest = manifest_module.run() if "print" not in self.manifest: identifier = self.manifest.popitem()[1].package() recompiled_apk = "{}/{}-recompiled.apk".format(self.output, identifier) # unzip Log.info("Re-compiling application") output = recompile(self.decompiled_apk, recompiled_apk) if "Exception" in output: return { "print": "Failed to re-compile the application:\n{}".format(output) } return { "{}_recompiled".format(identifier): recompiled_apk, "print": "Application re-compiled to {}".format(recompiled_apk) }
def run(self): result = { "title": "Application Not Compiled With PIE Support", "details": "", "severity": "Low", "report": False } flags_module = FlagsModule() flags_module.binary = self.binary flags_result, flags = flags_module.run(), None for key in flags_result: if key.endswith("_flags"): flags = flags_result[key] if not flags: return {"print": "Couldn't get flags from binary."} Log.info("Analysing Flags") matches = re.findall(self._regex, flags) if not matches: result.update({ "report": True, "details": "PIE flag not found." }) return { "{}_result".format(self.name()): result }
def run(self): result = { "title": "Application Has Secret Codes", "details": "", "severity": "Low", "report": False } # create manifest manifest_module = ManifestModule() manifest_module.decompiled_apk = self.decompiled_apk self.manifest = manifest_module.run() if "print" in self.manifest: return {"print": "Could not get the manifest"} self.manifest = self.manifest.popitem()[1] Log.info("Analysing application's manifest for secret codes") secret_codes = self.manifest.secret_codes() if secret_codes: details = "* Secret Codes:\n * {}".format( "\n * ".join(secret_codes)) details += """ * Test the secret codes using the following command: adb shell su -c "am broadcast -a {} -d android_secret_code://CODE" """.format(self._secret_code_activity) result.update({"report": True, "details": details}) return { "{}_result".format(self.name()): result, "{}_secret_codes".format(self.manifest.package()): secret_codes }
def run(self): result = { "title": "Application Does Not Check If A Passcode Is Set", "details": "", "severity": "Low", "report": False } symb_module = SymbolsModule() symb_module.binary = self.binary symbols_result, symbols = symb_module.run(), None for key in symbols_result: if key.endswith("_symbols"): symbols = symbols_result[key] if not symbols: return {"print": "Couldn't get symbols from binary."} Log.info("Analysing Symbols") matches = re.findall(self._regex, symbols) if not matches: result.update({ "report": True, "details": "No evidence of checking for passcode set found." }) return {"{}_result".format(self.name()): result}
def run(self): Log.info("Preparing to sign the application") binaries_local_path = "{}/bin/android".format(_SCROUNGER_HOME) signjar = "{}/signapk.jar".format(binaries_local_path) key = "{}/key.pk8".format(binaries_local_path) cert = "{}/cert.x509.pem".format(binaries_local_path) # get identifier identifier = self.recompiled_apk.rsplit("/",1)[-1].rsplit(".", 1)[0] signed_apk = "{}/{}-signed.apk".format(self.output, identifier) # sign Log.info("Signinging application") output = sign(self.recompiled_apk, signed_apk, signjar, cert, key) if output and "Exception" in output: return { "print": "Failed to sign the application:\n{}".format(output) } return { "{}_signed".format(identifier): signed_apk, "print": "Application signed to {}".format(signed_apk) }
def run(self): result = { "title": "Application Uses Weak Random Functions", "details": "", "severity": "Low", "report": False } symb_module = SymbolsModule() symb_module.binary = self.binary symbols_result, symbols = symb_module.run(), None for key in symbols_result: if key.endswith("_symbols"): symbols = symbols_result[key] if not symbols: return {"print": "Couldn't get symbols from binary."} Log.info("Analysing Symbols") matches = re.findall(self._regex, symbols) if matches: result.update({ "report": True, "details": "The following evidence were found:\n* {}".format("\n* ".join( sorted(set(matches)))) }) return {"{}_result".format(self.name()): result}
def run(self): result = { "title": "Application's Providers Are Vulnerable To Path Traversal", "details": "", "severity": "High", "report": False } Log.info("Extracting and translating providers") providers = parsed_providers(self.decompiled_apk) Log.info("Analysing providers") vulnerable_providers = [] example_result = None for provider in providers: exec_result = self.device.read_provider(provider, self.exploit_path) if exec_result and "Exception" not in exec_result: vulnerable_providers += [provider] example_result = exec_result if vulnerable_providers: details = "* Vulnerable Providers:\n* {}".format( "\n* ".join(vulnerable_providers)) details += "\n\nAn example of exploitation success:\n{}".format( example_result) result.update({"report": True, "details": details}) return {"{}_result".format(self.name()): result}
def run(self): result = { "title": "Application Allows Backups", "details": "", "severity": "Low", "report": False } # create manifest manifest_module = ManifestModule() manifest_module.decompiled_apk = self.decompiled_apk manifest = manifest_module.run() if "print" in manifest: return {"print": "Could not get the manifest"} manifest = manifest.popitem()[1] Log.info("Analysing application's manifest") if manifest.allow_backup(): result.update({"report": True}) return { "{}_result".format(self.name()): result }
def run(self): Log.info("Dumping classes with otool") class_dump = otool_class_dump_to_dict( self.device.otool("-ov", self.binary)[0]) # stdout dump_name = self.binary.rsplit("/", 1)[-1].replace(" ", ".") result = { "{}_class_dump".format(dump_name.replace(".", "_")): class_dump } if hasattr(self, "output") and self.output: Log.info("Saving classes to file") dump_path = "{}/{}.class.dump".format(self.output, dump_name) # create output folder execute("mkdir -p {}".format(dump_path)) save_class_dump(class_dump, dump_path) result.update({ "{}_dump_path".format(dump_name.replace(".", "_")): dump_path, "print": "Dump saved in {}.".format(dump_path) }) return result
def run(self): Log.info("Starting application") if self.device.installed(self.identifier): self.device.start(self.identifier) return {"print": "Application {} started".format(self.identifier)} return {"print": "Application not installed"}