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 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 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): result = { "title": "Application Does Not Implement SSL Pinning", "details": "", "severity": "High", "report": False } # preparing variable to run ssl_keywords = {} 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 for SSL evidences") for directory in dirs: smali = "{}/{}".format(self.decompiled_apk, directory) ssl_keywords.update(pretty_grep(self.regex, smali)) if not ssl_keywords: result.update({ "report": True, "details": "Found no evidences of a `TrustManager`." }) Log.info("Analysing SSL evidences") for filename in ssl_keywords: if any(filepath in filename for filepath in ignore): continue with open(filename, "r") as fp: smali = fp.read() if re.search(self.mock_check_server, smali): result.update({ "report": True, "details": "{}\n* {}:{}\n".format( result["details"], filename.replace(self.decompiled_apk, ""), extract_smali_method("checkServerTrusted", filename)) }) if re.search(self.mock_accepted_issuers, smali): result.update({ "report": True, "details": "{}\n* {}:{}\n".format( result["details"], filename.replace(self.decompiled_apk, ""), extract_smali_method("getAcceptedIssuers", filename)) }) return {"{}_result".format(self.name()): result}
def run(self): result = { "title": "Application's WebViews Enable JavaScript", "details": "", "severity": "Medium", "report": False } # preparing variable to run filenames = {} 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) filenames.update(pretty_grep(self.regex, smali)) report = {} # check var setting for file_name in filenames: report[file_name] = [] for instance in filenames[file_name]: var_name = instance["details"].split( "}", 1)[0].split(",", 1)[-1].strip() var_setting = track_variable( var_name, instance["line"], file_name) for setting_line in var_setting: if "0x1" in setting_line["details"]: report[file_name] += var_setting for file_name in report: filenames[file_name] += report[file_name] if filenames: result.update({ "report": True, "details": pretty_grep_to_str( filenames, self.decompiled_apk, ignore) }) return { "{}_result".format(self.name()): result }
def run(self): result = { "title": "Application Communicates Over Unencrypted Channels", "details": "", "severity": "High", "report": False } # preparing variable to run pretty_result = "" ignore = [url.strip() for url 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) urls = pretty_grep(self.regex, smali) to_remove = [] for url in urls: for detail in urls[url]: if any(iurl in detail["details"] for iurl in ignore) or \ detail["details"] == "http://": urls[url].remove(detail) if not urls[url]: to_remove += [url] for filename in to_remove: urls.pop(filename) pretty_result += pretty_grep_to_str(urls, smali) if pretty_result: result.update({ "report": True, "details": pretty_result }) return { "{}_result".format(self.name()): result }
def run(self): result = { "title": "Application's WebViews Implement Javascript Bridges", "details": "", "severity": "Medium", "report": False } # preparing variable to run bridges = {} 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) bridges.update(pretty_grep(self.js_interface_regex, smali)) report = {} # check var setting for file_name in bridges: report[file_name] = [] for instance in bridges[file_name]: report[file_name] += method_name(instance["line"], file_name) bridges = {} # TODO: check this works for file_name in report: bridges[file_name] += report[file_name] if bridges: result.update({ "report": True, "details": pretty_grep_to_str(bridges, self.decompiled_apk, ignore) }) return {"{}_result".format(self.name()): result}
def run(self): result = { "title": "Application Does Not Prevent Screenshots", "details": "", "severity": "Low", "report": False } # preparing variable to run report_activities = [] activities = {} 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) activities.update(pretty_grep(self.activities_regex, smali)) if activities: safe_activities = pretty_grep( self.regex, " ".join(list(activities))) report_activities = list(set(activities) - set(safe_activities)) if report_activities: result.update({ "report": True, "details": "* {}".format("\n* ".join( [activity.replace(self.decompiled_apk, "") for activity in report_activities if not any( i in activity for i in ignore) ]) ) }) return { "{}_result".format(self.name()): result }
def run(self): result = { "title": "Application's WebViews Are Vulnerable To Arbitrary \ Redirection", "details": "", "severity": "Low", "report": False } # preparing variable to run webview_files = {} overrride_url_files = {} 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) webview_files.update(pretty_grep(self.use_webview_regex, smali)) overrride_url_files.update(pretty_grep(self.regex, smali)) Log.info("Analysing WebViews") for filename in overrride_url_files: webview_files.pop(filename) if webview_files: result.update({ "report": True, "details": pretty_grep_to_str(webview_files, self.decompiled_apk, ignore) }) return {"{}_result".format(self.name()): result}
def run(self): result = { "title": "Application Is Vulnerable To Fragment Injection", "details": "", "severity": "Medium", "report": False } # create yaml apktool_module = YamlModule() apktool_module.decompiled_apk = self.decompiled_apk apktool = apktool_module.run() if "print" in apktool: return {"print": "Could not get the apktool yaml file"} apktool = apktool.popitem()[1] # preparing variable to run activities = {} 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 apktool yaml and smali") for directory in dirs: smali = "{}/{}".format(self.decompiled_apk, directory) activities.update(pretty_grep(self.regex, smali)) if activities and int(apktool.min_sdk()) < 18: result.update({ "report": True, "details": pretty_grep_to_str(activities, self.decompiled_apk, ignore) }) return {"{}_result".format(self.name()): result}
def run(self): result = { "title": "Application Does Not Delete Cached Files On Exit", "details": "", "severity": "Low", "report": False } # preparing variable to run webview_files = {} clear_cache = {} 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) webview_files.update(pretty_grep(self.use_webview_regex, smali)) clear_cache.update(pretty_grep(self.regex, smali)) Log.info("Analysing WebViews") for filename in clear_cache: webview_files.pop(filename) if webview_files: result.update({ "report": True, "details": pretty_grep_to_str(webview_files, self.decompiled_apk, ignore) }) return {"{}_result".format(self.name()): result}
def run(self): result = { "title": "Application Does Not Detect Emulators", "details": "", "severity": "Medium", "report": True } # preparing variable to run emulator_detection = {} ignore = [filepath.strip() for filepath in self.ignore.split(";")] Log.info("Identifying smali directories") dirs = smali_dirs(self.decompiled_apk) Log.info("Analysing smali code for emulator detection mechanisms") for directory in dirs: smali = "{}/{}".format(self.decompiled_apk, directory) emulator_detection.update(pretty_grep(self.regex, smali)) if emulator_detection: result = { "title": "Application Detects Emulators", "details": "{}\n\n{}".format( result["details"], pretty_grep_to_str(emulator_detection, self.decompiled_apk, ignore)), "severity": "Medium", "report": True } # dynamic testing Log.info("Checking requirements for dynamic testing") if hasattr(self, "apk") and hasattr(self, "avd") and \ hasattr(self, "identifier") and self.identifier and \ self.apk and self.avd: # get available devices before starting the emulator available_devices = devices() # start emulator Log.info("Starting the emulator") emulator_process = process("emulator -avd {}".format(self.avd)) # wait for emulator to start sleep(60) # diff devices -> get emulator emulator_id = list(set(devices()) - set(available_devices)) if len(emulator_id) != 1: Log.warn("Could not find the emulator in the device list") emulator_process.kill() return { "{}_result".format(self.name()): result, "print": "Coud not start emulator or find defined avd" } device = AndroidDevice(emulator_id) Log.info("Installing the apk in the device") device.install(self.apk) if device.installed(self.identifier): while not device.unlocked(): Log.info("Please unlock the emulator") sleep(5) Log.info("Starting the application") device.start(identifier) sleep(15) if self.identifier not in device.processes(): result.update({"report": False}) emulator_process.kill() return {"{}_result".format(self.name()): result}
def run(self): from time import sleep result = { "title": "Application Does Not Implement SSL Pinning", "details": "", "severity": "High", "report": False } # preparing variable to run ssl_keywords = {} 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 for SSL evidences") for directory in dirs: smali = "{}/{}".format(self.decompiled_apk, directory) ssl_keywords.update(pretty_grep(self.regex, smali)) if not ssl_keywords: result.update({ "report": True, "details": "Found no evidences of a `TrustManager`." }) Log.info("Analysing SSL evidences") for filename in ssl_keywords: if any(filepath in filename for filepath in ignore): continue with open(filename, "r") as fp: smali = fp.read() if re.search(self.mock_check_server, smali): result.update({ "report": True, "details": "{}\n* {}:{}\n".format( result["details"], filename.replace(self.decompiled_apk, ""), extract_smali_method("checkServerTrusted", filename)) }) if re.search(self.mock_accepted_issuers, smali): result.update({ "report": True, "details": "{}\n* {}:{}\n".format( result["details"], filename.replace(self.decompiled_apk, ""), extract_smali_method("getAcceptedIssuers", filename)) }) if self.device and self.identifier and \ self.proxy_host != None and self.proxy_port != None: Log.info("Testing SSL Pinning using a proxy") Log.info( "Make sure your device trusts the CA in: {}/ca.crt".format( _CERT_PATH)) Log.info("Waiting for {} seconds to allow time to setup the \ proxy on the remote device".format(self.wait_time)) sleep(int(self.wait_time)) Log.info("Killing the application") self.device.stop(self.identifier) Log.info("Starting the SSL proxy") proxy_server = create_server(self.proxy_host, self.proxy_port, _CERT_PATH) Log.info("Starting the Application") self.device.start(self.identifier) Log.info("Waiting for the Application to start and make requests") sleep(10) pinned = list( set(proxy_server.server.connected) - set(proxy_server.server.requested)) if not proxy_server.server.connected: Log.error("No connections made by the application") if pinned: result.update({ "title": "Application Implements SSL Pinning", "report": True, "details": "{}\n\nThe application started a connection but \ made no requests to the following domains:\n* {}".format( result["details"], "\n* ".join(pinned)) }) proxy_server.stop() return {"{}_result".format(self.name()): result}
def run(self): result = { "title": "Application Does Not Detect Debuggers", "details": "", "severity": "Medium", "report": False } ignore = [filepath.strip() for filepath in self.ignore.split(";")] Log.info("Identifying smali directories") dirs = smali_dirs(self.decompiled_apk) Log.info("Looking for evidence in smali code") debug_evidence = {} for directory in dirs: smali = "{}/{}".format(self.decompiled_apk, directory) debug_evidence.update(pretty_grep(self.debug_regex, smali)) if debug_evidence: result.update({ "title": "Application Destects Debuggers", "report": True, "details": "The following evidence was found in the smali \ code:\n{}".format( pretty_grep_to_str(debug_evidence, self.decompiled_apk, ignore)) }) else: result.update({ "details": "No evidence of debug detection was found in the \ smali code.", "report": True }) if self.repackage: Log.info("Trying to modify the application to be debuggable") # make the application debuggable debug_module = DModule() debug_module.decompiled_apk = self.decompiled_apk debug_module.device = self.device debug_module.output = None # will default to /tmp debug_module.install = True debug_module.run() Log.info("Starting the application and identifying the process ID") self.device.start(self.identifier) pid = self.device.pid(self.identifier) if pid: Log.info("Forwarding local ports") forward(54321, pid) Log.info("Starting JDB") jdb = JDB("127.0.0.1", 54321) if not jdb.running(): result.update({ "report": True, "details": "{}\n\nScrounger was unable to attach a debugger\ to the application.".format(result["details"]) }) else: result.update({ "report": True, "details": "{}\n\nScrounger was able to attach a debugger \ to the application:\n\n{}".format(result["details"], jdb.read()) }) Log.info("Removing forwarded ports and exiting jdb") remove_forward() jdb.exit() else: Log.error("The application is not running") return {"{}_result".format(self.name()): result}