def get_domains(urls): """Get Domains""" try: domains = list() for url in urls: parsed_uri = urlparse(url) domain = '{uri.netloc}'.format(uri=parsed_uri) if ((domain not in domains) and (len(domain) > 2) and ("." in domain) and (domain.endswith(".") is False and re.search('[a-zA-Z0-9]', domain))): domains.append(domain) return domains except: PrintException("[ERROR] Extracting Domain form URL") pass
def capfuzz_start(request): """Start CapFuzz UI""" print("[INFO] Starting CapFuzz Web UI") try: stop_capfuzz(settings.PORT) start_fuzz_ui(settings.PORT) time.sleep(3) print("[INFO] CapFuzz UI Started") if request.GET['project']: project = request.GET['project'] else: project = "" return HttpResponseRedirect('http://localhost:' + str(settings.PORT) + "/dashboard/" + project) except: PrintException("[ERROR] Starting CapFuzz Web UI") return HttpResponseRedirect('/error/')
def delete_avd(avd_path, avd_name): """Delete AVD""" print "\n[INFO] Deleting emulator files" try: config_file = os.path.join(avd_path, avd_name + '.ini') if os.path.exists(config_file): os.remove(config_file) ''' # todo: Sometimes there is an error here because of the locks that avd # does - check this out ''' avd_folder = os.path.join(avd_path, avd_name + '.avd') if os.path.isdir(avd_folder): shutil.rmtree(avd_folder) except: PrintException("[ERROR] Deleting emulator files")
def get_icon(apk_path, res_dir): """Returns a dict with isHidden boolean and a relative path path is a full path (not relative to resource folder) """ try: logger.info("Fetching icon path") a = apk.APK(apk_path) icon_resolution = 0xFFFE - 1 icon_name = a.get_app_icon(max_dpi=icon_resolution) if icon_name: return { 'path': os.path.join(os.path.dirname(apk_path), icon_name), 'hidden': False } return {'path': guess_icon_path(res_dir), 'hidden': True} except: PrintException("Fetching icon function")
def adb_command(cmd_list, shell=False, silent=False): emulator = get_identifier() adb = getADB() args = [adb, "-s", emulator] if shell: args += ['shell'] args += cmd_list try: result = subprocess.check_output(args) return result except: if not silent: PrintException("[ERROR] adb_command") return None
def strings_jar(app_file, app_dir): """Extract the strings from an app.""" try: print("[INFO] Extracting Strings from APK") dat = [] apk_file = os.path.join(app_dir, app_file) and_a = apk.APK(apk_file) rsrc = and_a.get_android_resources() pkg = rsrc.get_packages_names()[0] rsrc.get_strings_resources() for i in rsrc.values[pkg].keys(): for duo in rsrc.values[pkg][i]['string']: dat.append('"' + duo[0] + '" : "' + duo[1] + '"') return dat except: PrintException("[ERROR] Extracting Strings from APK")
def run(request): """Show the java code.""" try: match = re.match('^[0-9a-f]{32}$', request.GET['md5']) typ = request.GET['type'] if match: md5 = request.GET['md5'] if typ == 'eclipse': src = os.path.join(settings.UPLD_DIR, md5 + '/src/') elif typ == 'studio': src = os.path.join(settings.UPLD_DIR, md5 + '/app/src/main/java/') elif typ == 'apk': src = os.path.join(settings.UPLD_DIR, md5 + '/java_source/') else: return HttpResponseRedirect('/error/') html = '' # pylint: disable=unused-variable # Needed by os.walk for dir_name, sub_dir, files in os.walk(src): for jfile in files: if jfile.endswith(".java"): file_path = os.path.join(src, dir_name, jfile) if "+" in jfile: fp2 = os.path.join(src, dir_name, jfile.replace("+", "x")) shutil.move(file_path, fp2) file_path = fp2 fileparam = file_path.replace(src, '') if any(cls in fileparam for cls in settings.SKIP_CLASSES) is False: html += ("<tr><td><a href='../ViewSource/?file=" + escape(fileparam) + "&md5=" + md5 + "&type=" + typ + "'>" + escape(fileparam) + "</a></td></tr>") context = { 'title': 'Java Source', 'files': html, 'md5': md5, 'type': typ, } template = "static_analysis/java.html" return render(request, template, context) except: PrintException("[ERROR] Getting Java Files") return HttpResponseRedirect('/error/')
def run(request): """View the source of a file.""" try: fil = '' match = re.match('^[0-9a-f]{32}$', request.GET['md5']) if match and ( request.GET['file'].endswith('.java') or request.GET['file'].endswith('.smali') ): fil = request.GET['file'] md5 = request.GET['md5'] if ("../" in fil) or ("%2e%2e" in fil) or (".." in fil) or ("%252e" in fil): return HttpResponseRedirect('/error/') else: if fil.endswith('.java'): typ = request.GET['type'] if typ == 'eclipse': src = os.path.join(settings.UPLD_DIR, md5+'/src/') elif typ == 'studio': src = os.path.join(settings.UPLD_DIR, md5+'/app/src/main/java/') elif typ == 'apk': src = os.path.join(settings.UPLD_DIR, md5+'/java_source/') else: return HttpResponseRedirect('/error/') elif fil.endswith('.smali'): src = os.path.join(settings.UPLD_DIR, md5+'/smali_source/') sfile = os.path.join(src, fil) dat = '' with io.open( sfile, mode='r', encoding="utf8", errors="ignore" ) as file_pointer: dat = file_pointer.read() else: return HttpResponseRedirect('/error/') context = { 'title': escape(ntpath.basename(fil)), 'file': escape(ntpath.basename(fil)), 'dat': dat } template = "static_analysis/view_source.html" return render(request, template, context) except: PrintException("[ERROR] Viewing Source") return HttpResponseRedirect('/error/')
def get_env(request): """Get Dynamic Analysis Environment for Android""" print("\n[INFO] Setting up Dynamic Analysis Environment") try: if request.method == 'POST': data = {} md5_hash = request.POST['md5'] package = request.POST['pkg'] launcher = request.POST['lng'] if re.findall(r";|\$\(|\|\||&&", package) or re.findall(r";|\$\(|\|\||&&", launcher): print("[ATTACK] Possible RCE") return HttpResponseRedirect('/error/') if re.match('^[0-9a-f]{32}$', md5_hash): base_dir = settings.BASE_DIR app_dir = os.path.join( settings.UPLD_DIR, md5_hash + '/') # APP DIRECTORY app_file = md5_hash + '.apk' # NEW FILENAME app_path = app_dir + app_file # APP PATH adb = getADB() if settings.ANDROID_DYNAMIC_ANALYZER == "MobSF_AVD": proxy_ip = '127.0.0.1' else: proxy_ip = settings.PROXY_IP # Proxy IP start_proxy(settings.PORT, package) # vm needs the connect function try: if not settings.ANDROID_DYNAMIC_ANALYZER == "MobSF_AVD": connect() except Exception as exp: data = {'ready': 'no', 'msg': 'Cannot Connect to the VM/Device.', 'error': str(exp)} return HttpResponse(json.dumps(data), content_type='application/json') # Change True to support non-activity components install_and_run(app_path, package, launcher, True) screen_width, screen_width = get_res() data = {'ready': 'yes', 'screen_witdth': screen_width, 'screen_height': screen_width, } return HttpResponse(json.dumps(data), content_type='application/json') else: return HttpResponseRedirect('/error/') else: return HttpResponseRedirect('/error/') except: PrintException("[ERROR] Setting up Dynamic Analysis Environment") return HttpResponseRedirect('/error/')
def cert_info(app_dir, tools_dir): """Return certificate information.""" try: print("[INFO] Reading Code Signing Certificate") cert = os.path.join(app_dir, 'META-INF/') cp_path = tools_dir + 'CertPrint.jar' files = [f for f in os.listdir( cert) if os.path.isfile(os.path.join(cert, f))] certfile = None dat = '' manidat = '' manifestfile = None if "CERT.RSA" in files: certfile = os.path.join(cert, "CERT.RSA") else: for file_name in files: if file_name.lower().endswith(".rsa"): certfile = os.path.join(cert, file_name) elif file_name.lower().endswith(".dsa"): certfile = os.path.join(cert, file_name) if certfile: args = [settings.JAVA_PATH + 'java', '-jar', cp_path, certfile] issued = 'good' dat = subprocess.check_output(args) unicode_output = str(dat, encoding="utf-8", errors="replace") dat = escape(unicode_output).replace('\n', '</br>') else: dat = 'No Code Signing Certificate Found!' issued = 'missing' if re.findall(r"Issuer: CN=Android Debug|Subject: CN=Android Debug", dat): issued = 'bad' if re.findall(r"\[SHA1withRSA\]", dat): issued = 'bad hash' if "MANIFEST.MF" in files: manifestfile = os.path.join(cert, "MANIFEST.MF") if manifestfile: with open(manifestfile,'r') as manifile: manidat = manifile.read() sha256Digest = bool(re.findall(r"SHA-256-Digest", manidat)) cert_dic = { 'cert_info': dat, 'issued': issued, 'sha256Digest': sha256Digest } return cert_dic except: PrintException("[ERROR] Reading Code Signing Certificate")
def view(request): """View File""" logger.info("Viewing File") try: typ = '' fil = '' rtyp = '' dat = '' if re.match('^[0-9a-f]{32}$', request.GET['md5']): fil = request.GET['file'] md5_hash = request.GET['md5'] typ = request.GET['type'] src = os.path.join(settings.UPLD_DIR, md5_hash + '/DYNAMIC_DeviceData/') sfile = os.path.join(src, fil) # Prevent Directory Traversal Attacks if ("../" in fil) or ("%2e%2e" in fil) or (".." in fil) or ("%252e" in fil): return print_n_send_error_response( request, "Path Traversal Attack Detected") else: with io.open(sfile, mode='r', encoding="utf8", errors="ignore") as flip: dat = flip.read() if (fil.endswith('.xml')) and (typ == 'xml'): rtyp = 'xml' elif typ == 'db': dat = handle_sqlite(sfile) rtyp = 'asciidoc' elif typ == 'others': rtyp = 'asciidoc' else: return print_n_send_error_response( request, "File Type not supported") context = { 'title': escape(ntpath.basename(fil)), 'file': escape(ntpath.basename(fil)), 'dat': dat, 'type': rtyp, } template = "general/view.html" return render(request, template, context) else: return print_n_send_error_response(request, "Invalid Scan Hash") except: PrintException("Viewing File") return print_n_send_error_response(request, "ERROR Viewing File")
def FinalTest(request): #Closing Services in VM/Device global tcp_server_mode print "\n[INFO] Collecting Data and Cleaning Up" try: if request.method == 'POST': data = {} MD5=request.POST['md5'] PACKAGE=request.POST['pkg'] if re.findall(";|\$\(|\|\||&&",PACKAGE): print "[ATTACK] Possible RCE" return HttpResponseRedirect('/error/') m=re.match('^[0-9a-f]{32}$',MD5) if m: #Stop ScreenCast Client if it is running tcp_server_mode = "off" DIR=settings.BASE_DIR APKDIR=os.path.join(settings.UPLD_DIR, MD5+'/') TOOLSDIR=os.path.join(DIR, 'DynamicAnalyzer/tools/') #TOOLS DIR adb=getADB(TOOLSDIR) #Change to check output of subprocess when analysis is done #Can't RCE os.system(adb+' -s '+getIdentifier()+' logcat -d dalvikvm:W ActivityManager:I > "'+APKDIR + 'logcat.txt"') print "\n[INFO] Downloading Logcat logs" #os.system(adb+' -s '+getIdentifier()+' logcat -d Xposed:I *:S > "'+APKDIR + 'x_logcat.txt"') subprocess.call([adb, "-s", getIdentifier(), "pull", "/data/data/de.robv.android.xposed.installer/log/error.log", APKDIR + "x_logcat.txt"]) print "\n[INFO] Downloading Droidmon API Monitor Logcat logs" #Can't RCE os.system(adb+' -s '+getIdentifier()+' shell dumpsys > "'+APKDIR + 'dump.txt"'); print "\n[INFO] Downloading Dumpsys logs" subprocess.call([adb, "-s", getIdentifier(), "shell", "am", "force-stop", PACKAGE]) print "\n[INFO] Stopping Application" subprocess.call([adb, "-s", getIdentifier(), "shell", "am", "force-stop", "opensecurity.screencast"]) print "\n[INFO] Stopping ScreenCast Service" data = {'final': 'yes'} return HttpResponse(json.dumps(data), content_type='application/json') else: return HttpResponseRedirect('/error/') else: return HttpResponseRedirect('/error/') except: PrintException("[ERROR] Clean Up") return HttpResponseRedirect('/error/')
def iOS_ListFiles(SRC, MD5, BIN, MODE): try: print "[INFO] Get Files, BIN Plist -> XML, and Normalize" # Multi function, Get Files, BIN Plist -> XML, normalize + to x filez = [] certz = '' sfiles = '' db = '' plist = '' certz = '' for dirName, subDir, files in os.walk(SRC): for jfile in files: if not jfile.endswith(".DS_Store"): file_path = os.path.join(SRC, dirName, jfile) if "+" in jfile: plus2x = os.path.join(SRC, dirName, jfile.replace("+", "x")) shutil.move(file_path, plus2x) file_path = plus2x fileparam = file_path.replace(SRC, '') filez.append(fileparam) ext = jfile.split('.')[-1] if re.search("cer|pem|cert|crt|pub|key|pfx|p12", ext): certz += escape(file_path.replace(SRC, '')) + "</br>" if re.search("db|sqlitedb|sqlite", ext): db += "<a href='../ViewFile/?file=" + \ escape(fileparam) + "&type=db&mode=" + MODE + "&md5=" + \ MD5 + "''> " + escape(fileparam) + " </a></br>" if jfile.endswith(".plist"): if BIN: readBinXML(file_path) plist += "<a href='../ViewFile/?file=" + \ escape(fileparam) + "&type=xml&mode=" + MODE + "&md5=" + \ MD5 + "''> " + escape(fileparam) + " </a></br>" if len(db) > 1: db = "<tr><td>SQLite Files</td><td>" + db + "</td></tr>" sfiles += db if len(plist) > 1: plist = "<tr><td>Plist Files</td><td>" + plist + "</td></tr>" sfiles += plist if len(certz) > 1: certz = "<tr><td>Certificate/Key Files Hardcoded inside the App.</td><td>" + \ certz + "</td><tr>" sfiles += certz return filez, sfiles except: PrintException("[ERROR] iOS List Files")
def install_and_run(apk_path, package, launcher, is_activity): """Install APK and Run it""" logger.info("Starting App for Dynamic Analysis") try: adb = getADB() logger.info("Installing APK") adb_command(["install", "-r", apk_path]) if is_activity: run_app = package + "/" + launcher logger.info("Launching APK Main Activity") adb_command(["am", "start", "-n", run_app], True) else: logger.info("App Doesn't have a Main Activity") # Handle Service or Give Choice to Select in Future. logger.info("Testing Environment is Ready!") except: PrintException("Starting App for Dynamic Analysis")
def View(request): print "\n[INFO] Viewing File" try: typ = '' fil = '' rtyp = '' dat = '' m = re.match('^[0-9a-f]{32}$', request.GET['md5']) if m: fil = request.GET['file'] MD5 = request.GET['md5'] typ = request.GET['type'] SRC = os.path.join(settings.UPLD_DIR, MD5 + '/DYNAMIC_DeviceData/') sfile = os.path.join(SRC, fil) #Prevent Directory Traversal Attacks if (("../" in fil) or ("%2e%2e" in fil) or (".." in fil) or ("%252e" in fil)): return HttpResponseRedirect('/error/') else: with io.open(sfile, mode='r', encoding="utf8", errors="ignore") as f: dat = f.read() if ((fil.endswith('.xml')) and (typ == 'xml')): rtyp = 'xml' elif typ == 'db': dat = HandleSqlite(sfile) dat = dat.decode("windows-1252").encode("utf8") rtyp = 'plain' elif typ == 'others': rtyp = 'plain' else: return HttpResponseRedirect('/error/') context = { 'title': escape(ntpath.basename(fil)), 'file': escape(ntpath.basename(fil)), 'dat': dat, 'type': rtyp, } template = "view.html" return render(request, template, context) else: return HttpResponseRedirect('/error/') except: PrintException("[ERROR] Viewing File") return HttpResponseRedirect('/error/')
def RefreshVM(uuid, snapshot_uuid, vbox_exe): print "\n[INFO] Refreshing MobSF VM" try: #Close VM args = [vbox_exe, 'controlvm', uuid, 'poweroff'] subprocess.call(args) print "\n[INFO] VM Closed" #Restore Snapshot args = [vbox_exe, 'snapshot', uuid, 'restore', snapshot_uuid] subprocess.call(args) print "\n[INFO] VM Restore Snapshot" #Start Fresh VM args = [vbox_exe, 'startvm', uuid] subprocess.call(args) print "\n[INFO] VM Starting" except: PrintException("[ERROR] Refreshing MobSF VM")
def strings_on_ipa(bin_path): """Extract Strings from IPA""" try: print "[INFO] Running strings against the Binary" unique_str = [] list_of_strings = list(strings(bin_path)) unique_str = list(set(list_of_strings)) # Make unique unique_str = [ ipa_str if isinstance(ipa_str, unicode) else unicode( ipa_str, encoding="utf-8", errors="replace") for ipa_str in unique_str ] unique_str = [escape(ip_str) for ip_str in unique_str] # Escape evil strings return unique_str except: PrintException("[ERROR] - Running strings against the Binary")
def check_config(): try: for path in [settings.AVD_EMULATOR, settings.ADB_BINARY]: if not path: print( "\n[ERROR] ADB binary not configured, please refer to the official documentation" ) return False if settings.ANDROID_DYNAMIC_ANALYZER != 'MobSF_AVD': print( "\n[ERROR] Wrong configuration - ANDROID_DYNAMIC_ANALYZER, please refer to the official documentation" ) return False return True except: PrintException("[ERROR] check_config") return False
def ConnectInstallRun(TOOLSDIR, ADB_CON_ID, APKPATH, PACKAGE, LAUNCH, isACT): print "\n[INFO] Starting App for Dynamic Analysis" try: adb = getADB(TOOLSDIR) subprocess.call([adb, "kill-server"]) subprocess.call([adb, "start-server"]) print "\n[INFO] ADB Started" Wait(5) print "\n[INFO] Connecting to VM/Device" subprocess.call([adb, "connect", ADB_CON_ID]) subprocess.call([adb, "wait-for-device"]) print "\n[INFO] Mounting" if settings.REAL_DEVICE: subprocess.call([ adb, "-s", getIdentifier(), "shell", "su", "-c", "mount -o rw,remount,rw /system" ]) else: subprocess.call([ adb, "-s", getIdentifier(), "shell", "su", "-c", "mount -o rw,remount,rw /system" ]) #This may not work for VMs other than the default MobSF VM subprocess.call([ adb, "-s", getIdentifier(), "shell", "mount", "-o", "rw,remount", "-t", "rfs", "/dev/block/sda6", "/system" ]) print "\n[INFO] Installing APK" subprocess.call([adb, "-s", getIdentifier(), "install", "-r", APKPATH]) if isACT: runApp = PACKAGE + "/" + LAUNCH print "\n[INFO] Launching APK Main Activity" subprocess.call([ adb, "-s", getIdentifier(), "shell", "am", "start", "-n", runApp ]) else: print "\n[INFO] App Doesn't have a Main Activity" #Handle Service or Give Choice to Select in Future. pass print "[INFO] Testing Environment is Ready!" except: PrintException("[ERROR] Starting App for Dynamic Analysis")
def screencast_service(): """Start or Stop ScreenCast Services""" global TCP_SERVER_MODE print("\n[INFO] ScreenCast Service Status: " + TCP_SERVER_MODE) try: screen_dir = settings.SCREEN_DIR if not os.path.exists(screen_dir): os.makedirs(screen_dir) screen_socket = socket.socket() if TCP_SERVER_MODE == "on": screen_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) if settings.ANDROID_DYNAMIC_ANALYZER == "MobSF_AVD": addr = ('127.0.0.1', settings.SCREEN_PORT) else: addr = (settings.SCREEN_IP, settings.SCREEN_PORT) screen_socket.bind(addr) screen_socket.listen(10) while TCP_SERVER_MODE == "on": screens, address = screen_socket.accept() print("Got Connection from: ", address[0]) if settings.ANDROID_DYNAMIC_ANALYZER == "MobSF_REAL_DEVICE": ip_address = settings.DEVICE_IP else: ip_address = settings.VM_IP if address[0] in [ip_address, '127.0.0.1']: ''' Very Basic Check to ensure that only MobSF VM/Device/Emulator is allowed to connect to MobSF ScreenCast Service. ''' with open(screen_dir + 'screen.png', 'wb') as flip: while True: data = screens.recv(1024) if not data: break flip.write(data) else: print( "\n[ATTACK] An unknown client :" + address[0] + " is trying " + "to make a connection with MobSF ScreenCast Service!") elif TCP_SERVER_MODE == "off": screen_socket.close() except: screen_socket.close() PrintException("[ERROR] ScreenCast Server")
def download(md5_hash, download_dir, apk_dir, package): """Generating Downloads""" logger.info("Generating Downloads") try: capfuzz_home = os.path.join(str(Path.home()), ".capfuzz") logcat = os.path.join(apk_dir, 'logcat.txt') xlogcat = os.path.join(apk_dir, 'x_logcat.txt') dumpsys = os.path.join(apk_dir, 'dump.txt') sshot = os.path.join(apk_dir, 'screenshots-apk/') web = os.path.join(capfuzz_home, 'flows', package + ".flows.txt") star = os.path.join(apk_dir, package + '.tar') dlogcat = os.path.join(download_dir, md5_hash + '-logcat.txt') dxlogcat = os.path.join(download_dir, md5_hash + '-x_logcat.txt') ddumpsys = os.path.join(download_dir, md5_hash + '-dump.txt') dsshot = os.path.join(download_dir, md5_hash + '-screenshots-apk/') dweb = os.path.join(download_dir, md5_hash + '-WebTraffic.txt') dstar = os.path.join(download_dir, md5_hash + '-AppData.tar') # Delete existing data dellist = [dlogcat, dxlogcat, ddumpsys, dsshot, dweb, dstar] for item in dellist: if os.path.isdir(item): shutil.rmtree(item) elif os.path.isfile(item): os.remove(item) # Copy new data shutil.copyfile(logcat, dlogcat) shutil.copyfile(xlogcat, dxlogcat) shutil.copyfile(dumpsys, ddumpsys) try: shutil.copytree(sshot, dsshot) except: pass try: shutil.copyfile(web, dweb) except: pass try: shutil.copyfile(star, dstar) except: pass except: PrintException("[ERROR] Generating Downloads")
def ios_list_files(src, md5_hash, binary_form, mode): """List iOS files""" try: print("[INFO] Get Files, BIN Plist -> XML, and Normalize") # Multi function, Get Files, BIN Plist -> XML, normalize + to x filez = [] certz = [] sfiles = [] database = [] plist = [] for dirname, _, files in os.walk(src): for jfile in files: if not jfile.endswith(".DS_Store"): file_path = os.path.join(src, dirname, jfile) if "+" in jfile: plus2x = os.path.join( src, dirname, jfile.replace("+", "x")) shutil.move(file_path, plus2x) file_path = plus2x fileparam = file_path.replace(src, '') filez.append(fileparam) ext = jfile.split('.')[-1] if re.search("cer|pem|cert|crt|pub|key|pfx|p12", ext): certz.append(escape(file_path.replace(src, ''))) if re.search("db|sqlitedb|sqlite", ext): database.append("<a href='../ViewFile/?file=" + \ escape(fileparam) + "&type=" + mode + "&md5=" + \ md5_hash + "''> " + \ escape(fileparam) + " </a>") if jfile.endswith(".plist"): if binary_form: convert_bin_xml(file_path) plist.append("<a href='../ViewFile/?file=" + \ escape(fileparam) + "&type=" + mode + "&md5=" + \ md5_hash + "''> " + \ escape(fileparam) + " </a>") if len(database) > 0: sfiles.append({ "issue": "SQLite Files", "files": database }) if len(plist) > 0: sfiles.append({ "issue": "Plist Files", "files": plist }) if len(certz) > 0: sfiles.append({ "issue": "Certificate/Key Files Hardcoded inside the App.", "files": certz }) return filez, sfiles except: PrintException("[ERROR] iOS List Files")
def _parse_xml(app_dir): """Parse the AppxManifest file to get basic informations.""" print "[INFO] Starting Binary Analysis - XML" xml_file = os.path.join(app_dir, "AppxManifest.xml") xml_dic = { 'version': '', 'arch': '', 'app_name': '', 'pub_name': '', 'compiler_version': '', 'visual_studio_version': '', 'visual_studio_edition': '', 'target_os': '', 'appx_dll_version': '', 'proj_guid': '', 'opti_tool': '', 'target_run': '' } try: print "[INFO] Reading AppxManifest" config = etree.XMLParser( # pylint: disable-msg=E1101 remove_blank_text=True, resolve_entities=False) xml = etree.XML(open(xml_file).read(), config) # pylint: disable-msg=E1101 for child in xml.getchildren(): # } to prevent conflict with PhoneIdentity.. if isinstance(child.tag, str) and child.tag.endswith("}Identity"): xml_dic['version'] = child.get("Version") xml_dic['arch'] = child.get("ProcessorArchitecture") elif isinstance(child.tag, str) and child.tag.endswith("Properties"): for sub_child in child.getchildren(): if sub_child.tag.endswith("}DisplayName"): # TODO(Needed? Compare to existing app_name) xml_dic['app_name'] = sub_child.text elif sub_child.tag.endswith("}PublisherDisplayName"): xml_dic['pub_name'] = sub_child.text elif isinstance(child.tag, str) and child.tag.endswith("}Metadata"): xml_dic = __parse_xml_metadata(xml_dic, child) except: PrintException("[ERROR] - Reading from AppxManifest.xml") return xml_dic
def GetEnv(request): print "\n[INFO] Setting up Dynamic Analysis Environment" try: if request.method == 'POST': data = {} MD5 = request.POST['md5'] PKG = request.POST['pkg'] LNCH = request.POST['lng'] if re.findall(";|\$\(|\|\||&&", PKG) or re.findall( ";|\$\(|\|\||&&", LNCH): print "[ATTACK] Possible RCE" return HttpResponseRedirect('/error/') m = re.match('^[0-9a-f]{32}$', MD5) if m: DIR = settings.BASE_DIR APP_DIR = os.path.join(settings.UPLD_DIR, MD5 + '/') #APP DIRECTORY APP_FILE = MD5 + '.apk' #NEW FILENAME APP_PATH = APP_DIR + APP_FILE #APP PATH TOOLS_DIR = os.path.join(DIR, 'DynamicAnalyzer/tools/') #TOOLS DIR DWD_DIR = settings.DWD_DIR ADB_CON_ID = getIdentifier() PROXY_IP = settings.PROXY_IP #Proxy IP PORT = str(settings.PORT) #Proxy Port WebProxy(APP_DIR, PROXY_IP, PORT) ConnectInstallRun( TOOLS_DIR, ADB_CON_ID, APP_PATH, PKG, LNCH, True) #Change True to support non-activity components SCREEN_WIDTH, SCREEN_HEIGHT = GetRes() data = { 'ready': 'yes', 'screen_witdth': SCREEN_WIDTH, 'screen_height': SCREEN_HEIGHT, } return HttpResponse(json.dumps(data), content_type='application/json') else: return HttpResponseRedirect('/error/') else: return HttpResponseRedirect('/error/') except: PrintException("[ERROR] Setting up Dynamic Analysis Environment") return HttpResponseRedirect('/error/')
def res_analysis(app_dir, typ): """Perform the elf analysis.""" try: print("[INFO] Static Android Resourse Analysis Started") elf_desc = { 'html_infected': ('Found html files infected by malware.', 'high', 'The built environment was probably infected by malware, The html file ' 'used in this APK is infected.'), } html_an_dic = {} for k in list(elf_desc.keys()): html_an_dic[k] = [] resraw = os.path.join(app_dir, "res", "raw") assets = os.path.join(app_dir, "assets") for resdir in (resraw, assets): if os.path.exists(resdir) and os.path.isdir(resdir): for pdir, dirl, filel in os.walk(resdir): for filename in filel: if filename.endswith(".htm") or filename.endswith( ".html"): try: filepath = os.path.join(pdir, filename) buf = "" with io.open(filepath, mode='rb') as filp: buf = filp.read() if "svchost.exe" in buf: html_an_dic['html_infected'].append( filepath.replace(app_dir, "")) except Exception as e: pass res = [] for k, filelist in list(html_an_dic.items()): if len(filelist): descs = elf_desc.get(k) res.append({ 'title': descs[0], 'stat': descs[1], 'desc': descs[2], 'file': " ".join(filelist), }) return res except: PrintException("[ERROR] Performing Resourse Analysis")
def DynamicAnalyzer(request): print "\n[INFO] Dynamic Analysis Started" try: if request.method == 'POST': MD5 = request.POST['md5'] PKG = request.POST['pkg'] LNCH = request.POST['lng'] if re.findall(";|\$\(|\|\||&&", PKG) or re.findall( ";|\$\(|\|\||&&", LNCH): print "[ATTACK] Possible RCE" return HttpResponseRedirect('/error/') m = re.match('^[0-9a-f]{32}$', MD5) if m: # Delete ScreenCast Cache SCREEN_FILE = os.path.join(settings.SCREEN_DIR, 'screen.png') if os.path.exists(SCREEN_FILE): os.remove(SCREEN_FILE) # Delete Contents of Screenshot Dir SCRDIR = os.path.join(settings.UPLD_DIR, MD5 + '/screenshots-apk/') if os.path.isdir(SCRDIR): shutil.rmtree(SCRDIR) #Start DM Proxy("", "", "", "") if settings.REAL_DEVICE: print "\n[INFO] MobSF will perform Dynamic Analysis on real Android Device" else: #Refersh VM RefreshVM(settings.UUID, settings.SUUID, settings.VBOX) context = { 'md5': MD5, 'pkg': PKG, 'lng': LNCH, 'title': 'Start Testing', } template = "start_test.html" return render(request, template, context) else: return HttpResponseRedirect('/error/') else: return HttpResponseRedirect('/error/') except: PrintException("[ERROR] DynamicAnalyzer") return HttpResponseRedirect('/error/')
def HashGen(APP_PATH): """Generate and return sha1 and sha256 as a tupel.""" try: print "[INFO] Generating Hashes" sha1 = hashlib.sha1() sha256 = hashlib.sha256() BLOCKSIZE = 65536 with io.open(APP_PATH, mode='rb') as afile: buf = afile.read(BLOCKSIZE) while buf: sha1.update(buf) sha256.update(buf) buf = afile.read(BLOCKSIZE) sha1val = sha1.hexdigest() sha256val = sha256.hexdigest() return sha1val, sha256val except: PrintException("[ERROR] Generating Hashes")
def dex_2_smali(app_dir, tools_dir): """Run dex2smali""" try: print "[INFO] DEX -> SMALI" dex_path = app_dir + 'classes.dex' if len(settings.BACKSMALI_BINARY) > 0 and isFileExists( settings.BACKSMALI_BINARY): bs_path = settings.BACKSMALI_BINARY else: bs_path = os.path.join(tools_dir, 'baksmali.jar') output = os.path.join(app_dir, 'smali_source/') args = [ settings.JAVA_PATH + 'java', '-jar', bs_path, dex_path, '-o', output ] subprocess.call(args) except: PrintException("[ERROR] Converting DEX to SMALI")
def hash_gen(app_path): """Generate and return sha1 and sha256 as a tupel.""" try: print "[INFO] Generating Hashes" sha1 = hashlib.sha1() sha256 = hashlib.sha256() block_size = 65536 with io.open(app_path, mode='rb') as afile: buf = afile.read(block_size) while buf: sha1.update(buf) sha256.update(buf) buf = afile.read(block_size) sha1val = sha1.hexdigest() sha256val = sha256.hexdigest() return sha1val, sha256val except: PrintException("[ERROR] Generating Hashes")
def InstallRun(TOOLSDIR, APKPATH, PACKAGE, LAUNCH, isACT): print "\n[INFO] Starting App for Dynamic Analysis" try: adb = getADB(TOOLSDIR) print "\n[INFO] Installing APK" subprocess.call([adb, "-s", getIdentifier(), "install", "-r", APKPATH]) if isACT: runApp = PACKAGE + "/" + LAUNCH print "\n[INFO] Launching APK Main Activity" subprocess.call([adb, "-s", getIdentifier(), "shell", "am", "start", "-n", runApp]) else: print "\n[INFO] App Doesn't have a Main Activity" # Handle Service or Give Choice to Select in Future. pass print "[INFO] Testing Environment is Ready!" except: PrintException("[ERROR] Starting App for Dynamic Analysis")