def cli(ctx, sdk_path, build_path, debug, source, report_type, exploit_apk, report_path, report_name): if not source: click.secho("Please pass a source for scanning through either --java or --apk") click.secho(ctx.get_help()) return if exploit_apk: if not sdk_path: # Try to set the SDK from environment variables if they exist # Follows the guidelines from https://developer.android.com/studio/command-line/variables if environ_path_variable_exists(ANDROID_SDK_HOME): sdk_path = os.environ[ANDROID_SDK_HOME] elif environ_path_variable_exists(ANDROID_HOME): sdk_path = os.environ[ANDROID_HOME] elif environ_path_variable_exists(ANDROID_SDK_ROOT): sdk_path = os.environ[ANDROID_SDK_ROOT] else: click.secho("Please provide path to android SDK if building exploit APK.") return # Debug controls the output to stderr, debug logs are ALWAYS stored in `qark_debug.log` if debug: level = "DEBUG" else: level = "INFO" initialize_logging(level) click.secho("Decompiling...") decompiler = Decompiler(path_to_source=source, build_directory=build_path) decompiler.run() click.secho("Running scans...") path_to_source = decompiler.path_to_source if decompiler.source_code else decompiler.build_directory scanner = Scanner(manifest_path=decompiler.manifest_path, path_to_source=path_to_source) scanner.run() click.secho("Finish scans...") click.secho("Writing report...") if report_path is not None: if report_name is not None: report = Report(issues=set(scanner.issues), report_path=report_path, report_name=report_name) else: report = Report(issues=set(scanner.issues), report_path=report_path) else: report = Report(issues=set(scanner.issues)) report_path = report.generate(file_type=report_type) click.secho("Finish writing report to {report_path} ...".format(report_path=report_path)) if exploit_apk: click.secho("Building exploit APK...") exploit_builder = APKBuilder(exploit_apk_path=build_path, issues=scanner.issues, apk_name=decompiler.apk_name, manifest_path=decompiler.manifest_path, sdk_path=sdk_path) exploit_builder.build() click.secho("Finish building exploit APK...")
def scanner(decompiler): return Scanner(decompiler.manifest_path, decompiler.build_directory)
def static_analyzer(request, api=False): """Do static analysis on an request and save to db.""" try: if api: typ = request.POST['scan_type'] checksum = request.POST['hash'] filename = request.POST['file_name'] rescan = str(request.POST.get('re_scan', 0)) else: typ = request.GET['type'] checksum = request.GET['checksum'] filename = request.GET['name'] rescan = str(request.GET.get('rescan', 0)) # Input validation app_dic = {} match = re.match('^[0-9a-f]{32}$', checksum) if ((match) and (filename.lower().endswith('.apk') or filename.lower().endswith('.zip')) and (typ in ['zip', 'apk'])): app_dic['dir'] = settings.BASE_DIR # BASE DIR app_dic['app_name'] = filename # APP ORGINAL NAME app_dic['md5'] = checksum # MD5 app_dic['app_dir'] = os.path.join( settings.UPLD_DIR, app_dic['md5'] + '/') # APP DIRECTORY app_dic['tools_dir'] = os.path.join( app_dic['dir'], 'StaticAnalyzer/tools/') # TOOLS DIR # DWD_DIR = settings.DWD_DIR # not needed? Var is never used. print("[INFO] Starting Analysis on : " + app_dic['app_name']) if typ == 'apk': # Check if in DB # pylint: disable=E1101 db_entry = StaticAnalyzerAndroid.objects.filter( MD5=app_dic['md5']) if db_entry.exists() and rescan == '0': context = get_context_from_db_entry(db_entry) else: app_dic[ 'app_file'] = app_dic['md5'] + '.apk' # NEW FILENAME app_dic['app_path'] = app_dic['app_dir'] + \ app_dic['app_file'] # APP PATH # ANALYSIS BEGINS app_dic['size'] = str(file_size( app_dic['app_path'])) + 'MB' # FILE SIZE app_dic['sha1'], app_dic['sha256'] = hash_gen( app_dic['app_path']) app_dic['files'] = unzip(app_dic['app_path'], app_dic['app_dir']) app_dic['certz'] = get_hardcoded_cert_keystore( app_dic['files']) print("[INFO] APK Extracted") # Manifest XML app_dic['parsed_xml'] = get_manifest( app_dic['app_path'], app_dic['app_dir'], app_dic['tools_dir'], '', True) # Get icon res_path = os.path.join(app_dic['app_dir'], 'res') app_dic['icon_hidden'] = True # Even if the icon is hidden, try to guess it by the # default paths app_dic['icon_found'] = False app_dic['icon_path'] = '' # TODO: Check for possible different names for resource # folder? if os.path.exists(res_path): icon_dic = get_icon(app_dic['app_path'], res_path) if icon_dic: app_dic['icon_hidden'] = icon_dic['hidden'] app_dic['icon_found'] = bool(icon_dic['path']) app_dic['icon_path'] = icon_dic['path'] # Set Manifest link app_dic['mani'] = '../ManifestView/?md5=' + \ app_dic['md5'] + '&type=apk&bin=1' man_data_dic = manifest_data(app_dic['parsed_xml']) man_an_dic = manifest_analysis(app_dic['parsed_xml'], man_data_dic) bin_an_buff = [] bin_an_buff += elf_analysis(app_dic['app_dir']) bin_an_buff += res_analysis(app_dic['app_dir']) cert_dic = cert_info(app_dic['app_dir'], app_dic['tools_dir']) apkid_results = apkid_analysis(app_dic['app_dir'], app_dic['app_path']) dex_2_jar(app_dic['app_path'], app_dic['app_dir'], app_dic['tools_dir']) dex_2_smali(app_dic['app_dir'], app_dic['tools_dir']) jar_2_java(app_dic['app_dir'], app_dic['tools_dir']) code_an_dic = code_analysis(app_dic['app_dir'], man_an_dic['permissons'], "apk") print("\n[INFO] Generating Java and Smali Downloads") gen_downloads(app_dic['app_dir'], app_dic['md5'], app_dic['icon_path']) # Get the strings app_dic['strings'] = strings_jar(app_dic['app_file'], app_dic['app_dir']) app_dic['zipped'] = '&type=apk' # QARK SCANNER print("\n[INFO] Running Qark Scanner") manifest = get_manifest_file(app_dic['app_path'], app_dic['app_dir'], app_dic['tools_dir']) scanner = Scanner(manifest_path=manifest, path_to_source=app_dic['app_dir']) scanner.run() qark_result = scanner.regroup_issues() print("\n[INFO] Connecting to Database") try: # SAVE TO DB if rescan == '1': print("\n[INFO] Updating Database...") update_db_entry( app_dic, man_data_dic, man_an_dic, code_an_dic, cert_dic, bin_an_buff, apkid_results, qark_result, ) elif rescan == '0': print("\n[INFO] Saving to Database") create_db_entry( app_dic, man_data_dic, man_an_dic, code_an_dic, cert_dic, bin_an_buff, apkid_results, qark_result, ) except: PrintException("[ERROR] Saving to Database Failed") context = get_context_from_analysis( app_dic, man_data_dic, man_an_dic, code_an_dic, cert_dic, bin_an_buff, apkid_results, qark_result, ) context["average_cvss"], context["security_score"] = score( context["findings"]) context['dynamic_analysis_done'] = os.path.exists( os.path.join(app_dic['app_dir'], 'logcat.txt')) context['VT_RESULT'] = None if settings.VT_ENABLED: vt = VirusTotal.VirusTotal() context['VT_RESULT'] = vt.get_result( os.path.join(app_dic['app_dir'], app_dic['md5']) + '.apk', app_dic['md5']) template = "static_analysis/static_analysis.html" if api: return context else: return render(request, template, context) elif typ == 'zip': # Check if in DB # pylint: disable=E1101 cert_dic = {} cert_dic['cert_info'] = '' cert_dic['issued'] = '' cert_dic['sha256Digest'] = False bin_an_buff = [] app_dic['strings'] = '' app_dic['zipped'] = '' # Above fields are only available for APK and not ZIP db_entry = StaticAnalyzerAndroid.objects.filter( MD5=app_dic['md5']) if db_entry.exists() and rescan == '0': context = get_context_from_db_entry(db_entry) else: app_dic[ 'app_file'] = app_dic['md5'] + '.zip' # NEW FILENAME app_dic['app_path'] = app_dic['app_dir'] + \ app_dic['app_file'] # APP PATH print("[INFO] Extracting ZIP") app_dic['files'] = unzip(app_dic['app_path'], app_dic['app_dir']) # Check if Valid Directory Structure and get ZIP Type pro_type, valid = valid_android_zip(app_dic['app_dir']) if valid and pro_type == 'ios': print("[INFO] Redirecting to iOS Source Code Analyzer") if api: return {"type": "ios"} else: return HttpResponseRedirect( '/StaticAnalyzer_iOS/?name=' + app_dic['app_name'] + '&type=ios&checksum=' + app_dic['md5']) app_dic['certz'] = get_hardcoded_cert_keystore( app_dic['files']) app_dic['zipped'] = pro_type print("[INFO] ZIP Type - " + pro_type) if valid and (pro_type in ['eclipse', 'studio']): # ANALYSIS BEGINS app_dic['size'] = str(file_size( app_dic['app_path'])) + 'MB' # FILE SIZE app_dic['sha1'], app_dic['sha256'] = hash_gen( app_dic['app_path']) # Manifest XML app_dic['persed_xml'] = get_manifest( "", app_dic['app_dir'], app_dic['tools_dir'], pro_type, False) # Set manifest view link app_dic['mani'] = ('../ManifestView/?md5=' + app_dic['md5'] + '&type=' + pro_type + '&bin=0') man_data_dic = manifest_data(app_dic['persed_xml']) man_an_dic = manifest_analysis(app_dic['persed_xml'], man_data_dic) # Get icon eclipse_res_path = os.path.join( app_dic['app_dir'], 'res') studio_res_path = os.path.join(app_dic['app_dir'], 'app', 'src', 'main', 'res') if os.path.exists(eclipse_res_path): res_path = eclipse_res_path elif os.path.exists(studio_res_path): res_path = studio_res_path else: res_path = '' app_dic['icon_hidden'] = man_an_dic['icon_hidden'] app_dic['icon_found'] = False app_dic['icon_path'] = '' if res_path: app_dic['icon_path'] = find_icon_path_zip( res_path, man_data_dic['icons']) if app_dic['icon_path']: app_dic['icon_found'] = True if app_dic['icon_path']: if os.path.exists(app_dic['icon_path']): shutil.copy2( app_dic['icon_path'], os.path.join(settings.DWD_DIR, app_dic['md5'] + '-icon.png')) code_an_dic = code_analysis(app_dic['app_dir'], man_an_dic['permissons'], pro_type) print("\n[INFO] Connecting to Database") try: # SAVE TO DB if rescan == '1': print("\n[INFO] Updating Database...") update_db_entry( app_dic, man_data_dic, man_an_dic, code_an_dic, cert_dic, bin_an_buff, {}, {}, ) elif rescan == '0': print("\n[INFO] Saving to Database") create_db_entry( app_dic, man_data_dic, man_an_dic, code_an_dic, cert_dic, bin_an_buff, {}, {}, ) except: PrintException("[ERROR] Saving to Database Failed") context = get_context_from_analysis( app_dic, man_data_dic, man_an_dic, code_an_dic, cert_dic, bin_an_buff, {}, {}, ) else: msg = "This ZIP Format is not supported" if api: return print_n_send_error_response( request, msg, True) else: print_n_send_error_response(request, msg, False) return HttpResponseRedirect('/zip_format/') context["average_cvss"], context["security_score"] = score( context["findings"]) template = "static_analysis/static_analysis_android_zip.html" if api: return context else: return render(request, template, context) else: print( "\n[ERROR] Only APK,IPA and Zipped Android/iOS Source code supported now!" ) else: msg = "Hash match failed or Invalid file extension or file type" if api: return print_n_send_error_response(request, msg, True) else: return print_n_send_error_response(request, msg, False) except Exception as excep: msg = str(excep) exp = excep.__doc__ if api: return print_n_send_error_response(request, msg, True, exp) else: return print_n_send_error_response(request, msg, False, exp)