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. logger.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']) if not app_dic['files']: # Can't Analyze APK, bail out. msg = "APK file is invalid or corrupt" if api: return print_n_send_error_response( request, msg, True) else: return print_n_send_error_response( request, msg, False) app_dic['certz'] = get_hardcoded_cert_keystore( app_dic['files']) logger.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']) app_dic['playstore'] = get_app_details( man_data_dic['packagename']) 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['app_file'], app_dic['tools_dir']) apkid_results = apkid_analysis(app_dic['app_dir'], app_dic['app_path'], app_dic['app_name']) tracker = Trackers.Trackers(app_dic['app_dir'], app_dic['tools_dir']) tracker_res = tracker.get_trackers() 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") # Get the strings string_res = strings_jar(app_dic['app_file'], app_dic['app_dir']) if string_res: app_dic['strings'] = string_res['strings'] code_an_dic["urls_list"].extend( string_res['urls_list']) code_an_dic["urls"].extend(string_res['url_nf']) code_an_dic["emails"].extend(string_res['emails_nf']) else: app_dic['strings'] = [] # Firebase DB Check code_an_dic['firebase'] = firebase_analysis( list(set(code_an_dic["urls_list"]))) # Domain Extraction and Malware Check logger.info( "Performing Malware Check on extracted Domains") code_an_dic["domains"] = malware_check( list(set(code_an_dic["urls_list"]))) logger.info("Generating Java and Smali Downloads") gen_downloads(app_dic['app_dir'], app_dic['md5'], app_dic['icon_path']) app_dic['zipped'] = '&type=apk' logger.info("Connecting to Database") try: # SAVE TO DB if rescan == '1': logger.info("Updating Database...") update_db_entry( app_dic, man_data_dic, man_an_dic, code_an_dic, cert_dic, bin_an_buff, apkid_results, tracker_res, ) update_scan_timestamp(app_dic['md5']) elif rescan == '0': logger.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, tracker_res, ) except: PrintException("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, tracker_res, ) 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/android_binary_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 logger.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': logger.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 logger.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']) app_dic['playstore'] = get_app_details( man_data_dic['packagename']) 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) # Firebase DB Check code_an_dic['firebase'] = firebase_analysis( list(set(code_an_dic["urls_list"]))) # Domain Extraction and Malware Check logger.info( "Performing Malware Check on extracted Domains") code_an_dic["domains"] = malware_check( list(set(code_an_dic["urls_list"]))) logger.info("Connecting to Database") try: # SAVE TO DB if rescan == '1': logger.info("Updating Database...") update_db_entry( app_dic, man_data_dic, man_an_dic, code_an_dic, cert_dic, bin_an_buff, {}, {}, ) update_scan_timestamp(app_dic['md5']) elif rescan == '0': logger.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("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/android_source_analysis.html" if api: return context else: return render(request, template, context) else: logger.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)
def static_analyzer_ios(request, api=False): """Module that performs iOS IPA/ZIP Static Analysis.""" try: logger.info('iOS Static Analysis Started') if api: file_type = request.POST['scan_type'] checksum = request.POST['hash'] rescan = str(request.POST.get('re_scan', 0)) filename = request.POST['file_name'] else: file_type = request.GET['type'] checksum = request.GET['checksum'] rescan = str(request.GET.get('rescan', 0)) filename = request.GET['name'] md5_match = re.match('^[0-9a-f]{32}$', checksum) if ((md5_match) and (filename.lower().endswith('.ipa') or filename.lower().endswith('.zip')) and (file_type in ['ipa', 'ios'])): app_dict = {} app_dict['directory'] = Path(settings.BASE_DIR) # BASE DIR app_dict['file_name'] = filename # APP ORGINAL NAME app_dict['md5_hash'] = checksum # MD5 app_dict['app_dir'] = Path(settings.UPLD_DIR) / checksum tools_dir = app_dict[ 'directory'] / 'StaticAnalyzer' / 'tools' / 'ios' tools_dir = tools_dir.as_posix() if file_type == 'ipa': app_dict[ 'app_file'] = app_dict['md5_hash'] + '.ipa' # NEW FILENAME app_dict[ 'app_path'] = app_dict['app_dir'] / app_dict['app_file'] app_dict['app_path'] = app_dict['app_path'].as_posix() # DB ipa_db = StaticAnalyzerIOS.objects.filter( MD5=app_dict['md5_hash']) if ipa_db.exists() and rescan == '0': context = get_context_from_db_entry(ipa_db) else: logger.info('iOS Binary (IPA) Analysis Started') app_dict['bin_dir'] = app_dict['app_dir'] / 'Payload' app_dict['bin_dir'] = app_dict['bin_dir'].as_posix() + '/' app_dict['app_dir'] = app_dict['app_dir'].as_posix() + '/' app_dict['size'] = str(file_size( app_dict['app_path'])) + 'MB' # FILE SIZE app_dict['sha1'], app_dict['sha256'] = hash_gen( app_dict['app_path']) # SHA1 & SHA256 HASHES logger.info('Extracting IPA') # EXTRACT IPA unzip(app_dict['app_path'], app_dict['app_dir']) # Get Files, normalize + to x, # and convert binary plist -> xml all_files = ios_list_files(app_dict['bin_dir'], app_dict['md5_hash'], True, 'ipa') infoplist_dict = plist_analysis(app_dict['bin_dir'], False) app_dict['appstore'] = app_search(infoplist_dict.get('id')) bin_analysis_dict = binary_analysis( app_dict['bin_dir'], tools_dir, app_dict['app_dir'], infoplist_dict.get('bin')) # Get Icon app_dict['icon_found'] = get_icon( app_dict['md5_hash'], app_dict['bin_dir'], infoplist_dict.get('bin')) # IPA URL and Email Extract recon = extract_urls_n_email(app_dict['bin_dir'], all_files['files_long'], bin_analysis_dict['strings']) code_dict = { 'api': {}, 'code_anal': {}, 'urlnfile': recon['urlnfile'], 'domains': recon['domains'], 'emailnfile': recon['emailnfile'], 'firebase': firebase_analysis(recon['urls_list']), } # Saving to DB logger.info('Connecting to DB') if rescan == '1': logger.info('Updating Database...') save_or_update('update', app_dict, infoplist_dict, code_dict, bin_analysis_dict, all_files) update_scan_timestamp(app_dict['md5_hash']) elif rescan == '0': logger.info('Saving to Database') save_or_update('save', app_dict, infoplist_dict, code_dict, bin_analysis_dict, all_files) context = get_context_from_analysis( app_dict, infoplist_dict, code_dict, bin_analysis_dict, all_files) context['virus_total'] = None if settings.VT_ENABLED: vt = VirusTotal.VirusTotal() context['virus_total'] = vt.get_result( app_dict['app_path'], app_dict['md5_hash']) context['average_cvss'], context['security_score'] = score( context['binary_analysis']) template = 'static_analysis/ios_binary_analysis.html' if api: return context else: return render(request, template, context) elif file_type == 'ios': ios_zip_db = StaticAnalyzerIOS.objects.filter( MD5=app_dict['md5_hash']) if ios_zip_db.exists() and rescan == '0': context = get_context_from_db_entry(ios_zip_db) else: logger.info('iOS Source Code Analysis Started') app_dict['app_file'] = app_dict[ 'md5_hash'] + '.zip' # NEW FILENAME app_dict['app_path'] = app_dict['app_dir'] / app_dict[ 'app_file'] app_dict['app_path'] = app_dict['app_path'].as_posix() app_dict['app_dir'] = app_dict['app_dir'].as_posix() + '/' # ANALYSIS BEGINS - Already Unzipped logger.info('ZIP Already Extracted') app_dict['size'] = str(file_size( app_dict['app_path'])) + 'MB' # FILE SIZE app_dict['sha1'], app_dict['sha256'] = hash_gen( app_dict['app_path']) # SHA1 & SHA256 HASHES all_files = ios_list_files(app_dict['app_dir'], app_dict['md5_hash'], False, 'ios') infoplist_dict = plist_analysis(app_dict['app_dir'], True) app_dict['appstore'] = app_search(infoplist_dict.get('id')) code_analysis_dic = ios_source_analysis( app_dict['app_dir']) # Get App Icon app_dict['icon_found'] = get_icon_source( app_dict['md5_hash'], app_dict['app_dir']) # Firebase DB Check code_analysis_dic['firebase'] = firebase_analysis( list(set(code_analysis_dic['urls_list']))) fake_bin_dict = { 'bin_type': code_analysis_dic['source_type'], 'macho': {}, 'bin_res': [], 'libs': [], 'strings': [], } # Saving to DB logger.info('Connecting to DB') if rescan == '1': logger.info('Updating Database...') save_or_update('update', app_dict, infoplist_dict, code_analysis_dic, fake_bin_dict, all_files) update_scan_timestamp(app_dict['md5_hash']) elif rescan == '0': logger.info('Saving to Database') save_or_update('save', app_dict, infoplist_dict, code_analysis_dic, fake_bin_dict, all_files) context = get_context_from_analysis( app_dict, infoplist_dict, code_analysis_dic, fake_bin_dict, all_files) context['average_cvss'], context['security_score'] = score( context['code_analysis']) template = 'static_analysis/ios_source_analysis.html' if api: return context else: return render(request, template, context) else: msg = 'File Type not supported!' if api: return print_n_send_error_response(request, msg, True) else: return print_n_send_error_response(request, msg, False) 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 exp: logger.exception('Error Perfroming Static Analysis') msg = str(exp) exp_doc = exp.__doc__ if api: return print_n_send_error_response(request, msg, True, exp_doc) else: return print_n_send_error_response(request, msg, False, exp_doc)
def static_analyzer_ios(request, api=False): """Module that performs iOS IPA/ZIP Static Analysis.""" try: logger.info('iOS Static Analysis Started') if api: file_type = request.POST['scan_type'] checksum = request.POST['hash'] rescan = str(request.POST.get('re_scan', 0)) filename = request.POST['file_name'] else: file_type = request.GET['type'] checksum = request.GET['checksum'] rescan = str(request.GET.get('rescan', 0)) filename = request.GET['name'] md5_match = re.match('^[0-9a-f]{32}$', checksum) if ((md5_match) and (filename.lower().endswith('.ipa') or filename.lower().endswith('.zip')) and (file_type in ['ipa', 'ios'])): app_dict = {} app_dict['directory'] = settings.BASE_DIR # BASE DIR app_dict['file_name'] = filename # APP ORGINAL NAME app_dict['md5_hash'] = checksum # MD5 app_dict['app_dir'] = os.path.join( settings.UPLD_DIR, app_dict['md5_hash'] + '/') # APP DIRECTORY tools_dir = os.path.join(app_dict['directory'], 'StaticAnalyzer/tools/mac/') if file_type == 'ipa': # DB ipa_db = StaticAnalyzerIPA.objects.filter( MD5=app_dict['md5_hash']) if ipa_db.exists() and rescan == '0': context = get_context_from_db_entry_ipa(ipa_db) else: logger.info('iOS Binary (IPA) Analysis Started') app_dict['app_file'] = app_dict[ 'md5_hash'] + '.ipa' # NEW FILENAME app_dict['app_path'] = (app_dict['app_dir'] + app_dict['app_file']) app_dict['bin_dir'] = os.path.join(app_dict['app_dir'], 'Payload/') app_dict['size'] = str(file_size( app_dict['app_path'])) + 'MB' # FILE SIZE app_dict['sha1'], app_dict['sha256'] = hash_gen( app_dict['app_path']) # SHA1 & SHA256 HASHES logger.info('Extracting IPA') # EXTRACT IPA unzip(app_dict['app_path'], app_dict['app_dir']) # Get Files, normalize + to x, # and convert binary plist -> xml files, sfiles = ios_list_files(app_dict['bin_dir'], app_dict['md5_hash'], True, 'ipa') infoplist_dict = plist_analysis(app_dict['bin_dir'], False) app_dict['appstore'] = app_search(infoplist_dict.get('id')) bin_analysis_dict = binary_analysis( app_dict['bin_dir'], tools_dir, app_dict['app_dir'], infoplist_dict.get('bin')) # Saving to DB logger.info('Connecting to DB') if rescan == '1': logger.info('Updating Database...') update_db_entry_ipa(app_dict, infoplist_dict, bin_analysis_dict, files, sfiles) update_scan_timestamp(app_dict['md5_hash']) elif rescan == '0': logger.info('Saving to Database') create_db_entry_ipa(app_dict, infoplist_dict, bin_analysis_dict, files, sfiles) context = get_context_from_analysis_ipa( app_dict, infoplist_dict, bin_analysis_dict, files, sfiles) context['VT_RESULT'] = None if settings.VT_ENABLED: vt = VirusTotal.VirusTotal() context['VT_RESULT'] = vt.get_result( os.path.join(app_dict['app_dir'], app_dict['md5_hash']) + '.ipa', app_dict['md5_hash']) context['average_cvss'], context['security_score'] = score( context['bin_anal']) template = 'static_analysis/ios_binary_analysis.html' if api: return context else: return render(request, template, context) elif file_type == 'ios': ios_zip_db = StaticAnalyzerIOSZIP.objects.filter( MD5=app_dict['md5_hash']) if ios_zip_db.exists() and rescan == '0': context = get_context_from_db_entry_ios(ios_zip_db) else: logger.info('iOS Source Code Analysis Started') app_dict['app_file'] = app_dict[ 'md5_hash'] + '.zip' # NEW FILENAME app_dict['app_path'] = (app_dict['app_dir'] + app_dict['app_file']) # ANALYSIS BEGINS - Already Unzipped logger.info('ZIP Already Extracted') app_dict['size'] = str(file_size( app_dict['app_path'])) + 'MB' # FILE SIZE app_dict['sha1'], app_dict['sha256'] = hash_gen( app_dict['app_path']) # SHA1 & SHA256 HASHES files, sfiles = ios_list_files(app_dict['app_dir'], app_dict['md5_hash'], False, 'ios') infoplist_dict = plist_analysis(app_dict['app_dir'], True) app_dict['appstore'] = app_search(infoplist_dict.get('id')) code_analysis_dic = ios_source_analysis( app_dict['app_dir']) # Firebase DB Check code_analysis_dic['firebase'] = firebase_analysis( list(set(code_analysis_dic['urls_list']))) # Saving to DB logger.info('Connecting to DB') if rescan == '1': logger.info('Updating Database...') update_db_entry_ios(app_dict, infoplist_dict, code_analysis_dic, files, sfiles) update_scan_timestamp(app_dict['md5_hash']) elif rescan == '0': logger.info('Saving to Database') create_db_entry_ios(app_dict, infoplist_dict, code_analysis_dic, files, sfiles) context = get_context_from_analysis_ios( app_dict, infoplist_dict, code_analysis_dic, files, sfiles) context['average_cvss'], context['security_score'] = score( context['insecure']) template = 'static_analysis/ios_source_analysis.html' if api: return context else: return render(request, template, context) else: msg = 'File Type not supported!' if api: return print_n_send_error_response(request, msg, True) else: return print_n_send_error_response(request, msg, False) 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 exp: logger.exception('Error Perfroming Static Analysis') msg = str(exp) exp_doc = exp.__doc__ if api: return print_n_send_error_response(request, msg, True, exp_doc) else: return print_n_send_error_response(request, msg, False, exp_doc)
def pdf(request, api=False, jsonres=False): try: if api: checksum = request.POST['hash'] scan_type = request.POST['scan_type'] else: checksum = request.GET['md5'] scan_type = request.GET['type'] hash_match = re.match('^[0-9a-f]{32}$', checksum) if hash_match: if scan_type.lower() in ['apk', 'andzip']: static_db = StaticAnalyzerAndroid.objects.filter(MD5=checksum) if static_db.exists(): logger.info('Fetching data from DB for ' 'PDF Report Generation (Android)') context = get_context_from_db_entry(static_db) context['average_cvss'], context['security_score'] = score( context['findings']) if scan_type.lower() == 'apk': template = get_template( 'pdf/android_binary_analysis.pdf.html') else: template = get_template( 'pdf/android_source_analysis_pdf.html') else: if api: return {'report': 'Report not Found'} else: return HttpResponse( json.dumps({'report': 'Report not Found'}), content_type='application/json; charset=utf-8', status=500) elif scan_type.lower() in ['ipa', 'ioszip']: if scan_type.lower() == 'ipa': static_db = StaticAnalyzerIPA.objects.filter(MD5=checksum) if static_db.exists(): logger.info('Fetching data from DB for ' 'PDF Report Generation (IOS IPA)') context = get_context_from_db_entry_ipa(static_db) context['average_cvss'], context[ 'security_score'] = score(context['bin_anal']) template = get_template( 'pdf/ios_binary_analysis_pdf.html') else: if api: return {'report': 'Report not Found'} else: return HttpResponse( json.dumps({'report': 'Report not Found'}), content_type='application/json; charset=utf-8', status=500) elif scan_type.lower() == 'ioszip': static_db = StaticAnalyzerIOSZIP.objects.filter( MD5=checksum) if static_db.exists(): logger.info('Fetching data from DB for ' 'PDF Report Generation (IOS ZIP)') context = get_context_from_db_entry_ios(static_db) context['average_cvss'], context[ 'security_score'] = score(context['insecure']) template = get_template( 'pdf/ios_source_analysis_pdf.html') else: if api: return {'report': 'Report not Found'} else: return HttpResponse( json.dumps({'report': 'Report not Found'}), content_type='application/json; charset=utf-8', status=500) elif 'appx' == scan_type.lower(): if scan_type.lower() == 'appx': db_entry = StaticAnalyzerWindows.objects.filter( MD5=checksum, ) if db_entry.exists(): logger.info('Fetching data from DB for ' 'PDF Report Generation (APPX)') context = { 'title': db_entry[0].TITLE, 'name': db_entry[0].APP_NAME, 'pub_name': db_entry[0].PUB_NAME, 'size': db_entry[0].SIZE, 'md5': db_entry[0].MD5, 'sha1': db_entry[0].SHA1, 'sha256': db_entry[0].SHA256, 'bin_name': db_entry[0].BINNAME, 'version': db_entry[0].VERSION, 'arch': db_entry[0].ARCH, 'compiler_version': db_entry[0].COMPILER_VERSION, 'visual_studio_version': db_entry[0].VISUAL_STUDIO_VERSION, 'visual_studio_edition': db_entry[0].VISUAL_STUDIO_EDITION, 'target_os': db_entry[0].TARGET_OS, 'appx_dll_version': db_entry[0].APPX_DLL_VERSION, 'proj_guid': db_entry[0].PROJ_GUID, 'opti_tool': db_entry[0].OPTI_TOOL, 'target_run': db_entry[0].TARGET_RUN, 'files': python_list(db_entry[0].FILES), 'strings': python_list(db_entry[0].STRINGS), 'bin_an_results': python_list(db_entry[0].BIN_AN_RESULTS), 'bin_an_warnings': python_list(db_entry[0].BIN_AN_WARNINGS), } template = get_template( 'pdf/windows_binary_analysis_pdf.html') else: if api: return {'scan_type': 'Type is not Allowed'} else: return HttpResponse( json.dumps({'type': 'Type is not Allowed'}), content_type='application/json; charset=utf-8', status=500) context['VT_RESULT'] = None if settings.VT_ENABLED: app_dir = os.path.join(settings.UPLD_DIR, checksum + '/') vt = VirusTotal.VirusTotal() if 'zip' in scan_type.lower(): context['VT_RESULT'] = None else: context['VT_RESULT'] = vt.get_result( os.path.join(app_dir, checksum) + '.' + scan_type.lower(), checksum) try: if api and jsonres: return {'report_dat': context} else: options = { 'page-size': 'A4', 'quiet': '', 'no-collate': '', 'margin-top': '0.50in', 'margin-right': '0.50in', 'margin-bottom': '0.50in', 'margin-left': '0.50in', 'encoding': 'UTF-8', 'custom-header': [ ('Accept-Encoding', 'gzip'), ], 'no-outline': None, } html = template.render(context) pdf_dat = pdfkit.from_string(html, False, options=options) if api: return {'pdf_dat': pdf_dat} return HttpResponse(pdf_dat, content_type='application/pdf') except Exception as exp: logger.exception('Error Generating PDF Report') if api: return { 'error': 'Cannot Generate PDF/JSON', 'err_details': str(exp) } else: return HttpResponse( json.dumps({ 'pdf_error': 'Cannot Generate PDF', 'err_details': str(exp) }), content_type='application/json; charset=utf-8', status=500) else: if api: return {'error': 'Invalid scan hash'} else: return HttpResponse( json.dumps({'md5': 'Invalid MD5'}), content_type='application/json; charset=utf-8', status=500) except Exception as exp: logger.exception('Error Generating PDF Report') msg = str(exp) exp = exp.__doc__ if api: return print_n_send_error_response(request, msg, True, exp) else: return print_n_send_error_response(request, msg, False, exp)
def pdf(request, api=False, jsonres=False): try: if api: checksum = request.POST['hash'] else: checksum = request.GET['md5'] hash_match = re.match('^[0-9a-f]{32}$', checksum) if not hash_match: if api: return {'error': 'Invalid scan hash'} else: return HttpResponse(json.dumps({'md5': 'Invalid scan hash'}), content_type=ctype, status=500) # Do Lookups android_static_db = StaticAnalyzerAndroid.objects.filter(MD5=checksum) ios_static_db = StaticAnalyzerIOS.objects.filter(MD5=checksum) win_static_db = StaticAnalyzerWindows.objects.filter(MD5=checksum) if android_static_db.exists(): context, template = handle_pdf_android(android_static_db) elif ios_static_db.exists(): context, template = handle_pdf_ios(ios_static_db) elif win_static_db.exists(): context, template = handle_pdf_win(win_static_db) else: if api: return {'report': 'Report not Found'} else: return HttpResponse(json.dumps({'report': 'Report not Found'}), content_type=ctype, status=500) # Do VT Scan only on binaries context['virus_total'] = None ext = os.path.splitext(context['file_name'].lower())[1] if settings.VT_ENABLED and ext != '.zip': app_bin = os.path.join(settings.UPLD_DIR, checksum + '/', checksum + ext) vt = VirusTotal.VirusTotal() context['virus_total'] = vt.get_result(app_bin, checksum) # Get Local Base URL proto = 'file://' host_os = 'nix' if platform.system() == 'Windows': proto = 'file:///' host_os = 'windows' context['base_url'] = proto + settings.BASE_DIR context['dwd_dir'] = proto + settings.DWD_DIR context['host_os'] = host_os try: if api and jsonres: return {'report_dat': context} else: options = { 'page-size': 'Letter', 'quiet': '', 'no-collate': '', 'margin-top': '0.50in', 'margin-right': '0.50in', 'margin-bottom': '0.50in', 'margin-left': '0.50in', 'encoding': 'UTF-8', 'custom-header': [ ('Accept-Encoding', 'gzip'), ], 'no-outline': None, } # Added proxy support to wkhtmltopdf proxies, _ = upstream_proxy('https') if proxies['https']: options['proxy'] = proxies['https'] html = template.render(context) pdf_dat = pdfkit.from_string(html, False, options=options) if api: return {'pdf_dat': pdf_dat} return HttpResponse(pdf_dat, content_type='application/pdf') except Exception as exp: logger.exception('Error Generating PDF Report') if api: return { 'error': 'Cannot Generate PDF/JSON', 'err_details': str(exp) } else: return HttpResponse(json.dumps({ 'pdf_error': 'Cannot Generate PDF', 'err_details': str(exp) }), content_type=ctype, status=500) except Exception as exp: logger.exception('Error Generating PDF Report') msg = str(exp) exp = exp.__doc__ if api: return print_n_send_error_response(request, msg, True, exp) else: return print_n_send_error_response(request, msg, False, exp)
def pdf(request, api=False, jsonres=False): try: if api: checksum = request.POST['hash'] scan_type = request.POST['scan_type'] else: checksum = request.GET['md5'] scan_type = request.GET['type'] hash_match = re.match('^[0-9a-f]{32}$', checksum) if hash_match: if scan_type.lower() in ['apk', 'andzip']: static_db = StaticAnalyzerAndroid.objects.filter(MD5=checksum) if static_db.exists(): logger.info('Fetching data from DB for ' 'PDF Report Generation (Android)') context = adb(static_db) context['average_cvss'], context['security_score'] = score( context['code_analysis']) if scan_type.lower() == 'apk': template = get_template( 'pdf/android_binary_analysis.pdf.html') else: template = get_template( 'pdf/android_source_analysis_pdf.html') else: if api: return {'report': 'Report not Found'} else: return HttpResponse( json.dumps({'report': 'Report not Found'}), content_type='application/json; charset=utf-8', status=500) elif scan_type.lower() in ['ipa', 'ioszip']: if scan_type.lower() == 'ipa': static_db = StaticAnalyzerIOS.objects.filter(MD5=checksum) if static_db.exists(): logger.info('Fetching data from DB for ' 'PDF Report Generation (IOS IPA)') context = idb(static_db) context['average_cvss'], context[ 'security_score'] = score( context['binary_analysis']) template = get_template( 'pdf/ios_binary_analysis_pdf.html') else: if api: return {'report': 'Report not Found'} else: return HttpResponse( json.dumps({'report': 'Report not Found'}), content_type='application/json; charset=utf-8', status=500) elif scan_type.lower() == 'ioszip': static_db = StaticAnalyzerIOS.objects.filter(MD5=checksum) if static_db.exists(): logger.info('Fetching data from DB for ' 'PDF Report Generation (IOS ZIP)') context = idb(static_db) context['average_cvss'], context[ 'security_score'] = score(context['code_analysis']) template = get_template( 'pdf/ios_source_analysis_pdf.html') else: if api: return {'report': 'Report not Found'} else: return HttpResponse( json.dumps({'report': 'Report not Found'}), content_type='application/json; charset=utf-8', status=500) elif 'appx' == scan_type.lower(): if scan_type.lower() == 'appx': db_entry = StaticAnalyzerWindows.objects.filter( MD5=checksum, ) if db_entry.exists(): logger.info('Fetching data from DB for ' 'PDF Report Generation (APPX)') context = wdb(db_entry) template = get_template( 'pdf/windows_binary_analysis_pdf.html') else: if api: return {'scan_type': 'Type is not Allowed'} else: return HttpResponse( json.dumps({'type': 'Type is not Allowed'}), content_type='application/json; charset=utf-8', status=500) context['virus_total'] = None if settings.VT_ENABLED: app_dir = os.path.join(settings.UPLD_DIR, checksum + '/') vt = VirusTotal.VirusTotal() if 'zip' in scan_type.lower(): context['virus_total'] = None else: context['virus_total'] = vt.get_result( os.path.join(app_dir, checksum) + '.' + scan_type.lower(), checksum) try: if api and jsonres: return {'report_dat': context} else: options = { 'page-size': 'A4', 'quiet': '', 'no-collate': '', 'margin-top': '0.50in', 'margin-right': '0.50in', 'margin-bottom': '0.50in', 'margin-left': '0.50in', 'encoding': 'UTF-8', 'custom-header': [ ('Accept-Encoding', 'gzip'), ], 'no-outline': None, } html = template.render(context) pdf_dat = pdfkit.from_string(html, False, options=options) if api: return {'pdf_dat': pdf_dat} return HttpResponse(pdf_dat, content_type='application/pdf') except Exception as exp: logger.exception('Error Generating PDF Report') if api: return { 'error': 'Cannot Generate PDF/JSON', 'err_details': str(exp) } else: return HttpResponse( json.dumps({ 'pdf_error': 'Cannot Generate PDF', 'err_details': str(exp) }), content_type='application/json; charset=utf-8', status=500) else: if api: return {'error': 'Invalid scan hash'} else: return HttpResponse( json.dumps({'md5': 'Invalid MD5'}), content_type='application/json; charset=utf-8', status=500) except Exception as exp: logger.exception('Error Generating PDF Report') msg = str(exp) exp = exp.__doc__ if api: return print_n_send_error_response(request, msg, True, exp) else: return print_n_send_error_response(request, msg, False, exp)
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'] = Path(settings.BASE_DIR) # BASE DIR app_dic['app_name'] = filename # APP ORGINAL NAME app_dic['md5'] = checksum # MD5 # APP DIRECTORY app_dic['app_dir'] = Path(settings.UPLD_DIR) / checksum app_dic['tools_dir'] = app_dic['dir'] / 'StaticAnalyzer' / 'tools' app_dic['tools_dir'] = app_dic['tools_dir'].as_posix() logger.info('Starting Analysis on : %s', app_dic['app_name']) if typ == 'apk': app_dic['app_file'] = app_dic['md5'] + '.apk' # NEW FILENAME app_dic['app_path'] = (app_dic['app_dir'] / app_dic['app_file']).as_posix() app_dic['app_dir'] = app_dic['app_dir'].as_posix() + '/' # 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: # 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']) if not app_dic['files']: # Can't Analyze APK, bail out. msg = 'APK file is invalid or corrupt' if api: return print_n_send_error_response( request, msg, True) else: return print_n_send_error_response( request, msg, False) app_dic['certz'] = get_hardcoded_cert_keystore( app_dic['files']) logger.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 app_name app_dic['real_name'] = get_app_name( 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']) app_dic['playstore'] = get_app_details( man_data_dic['packagename']) man_an_dic = manifest_analysis( app_dic['parsed_xml'], man_data_dic, '', app_dic['app_dir'], ) 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['app_file']) apkid_results = apkid_analysis(app_dic['app_dir'], app_dic['app_path'], app_dic['app_name']) tracker = Trackers.Trackers(app_dic['app_dir'], app_dic['tools_dir']) tracker_res = tracker.get_trackers() apk_2_java(app_dic['app_path'], app_dic['app_dir'], app_dic['tools_dir']) dex_2_smali(app_dic['app_dir'], app_dic['tools_dir']) code_an_dic = code_analysis(app_dic['app_dir'], 'apk') # Get the strings string_res = strings_jar(app_dic['app_file'], app_dic['app_dir']) if string_res: app_dic['strings'] = string_res['strings'] app_dic['secrets'] = string_res['secrets'] code_an_dic['urls_list'].extend( string_res['urls_list']) code_an_dic['urls'].extend(string_res['url_nf']) code_an_dic['emails'].extend(string_res['emails_nf']) else: app_dic['strings'] = [] app_dic['secrets'] = [] # Firebase DB Check code_an_dic['firebase'] = firebase_analysis( list(set(code_an_dic['urls_list']))) # Domain Extraction and Malware Check logger.info( 'Performing Malware Check on extracted Domains') code_an_dic['domains'] = malware_check( list(set(code_an_dic['urls_list']))) # Copy App icon copy_icon(app_dic['md5'], app_dic['icon_path']) app_dic['zipped'] = 'apk' logger.info('Connecting to Database') try: # SAVE TO DB if rescan == '1': logger.info('Updating Database...') save_or_update( 'update', app_dic, man_data_dic, man_an_dic, code_an_dic, cert_dic, bin_an_buff, apkid_results, tracker_res, ) update_scan_timestamp(app_dic['md5']) elif rescan == '0': logger.info('Saving to Database') save_or_update( 'save', app_dic, man_data_dic, man_an_dic, code_an_dic, cert_dic, bin_an_buff, apkid_results, tracker_res, ) except Exception: logger.exception('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, tracker_res, ) context['average_cvss'], context['security_score'] = score( context['code_analysis']) context['dynamic_analysis_done'] = is_file_exists( os.path.join(app_dic['app_dir'], 'logcat.txt')) context['virus_total'] = None if settings.VT_ENABLED: vt = VirusTotal.VirusTotal() context['virus_total'] = vt.get_result( app_dic['app_path'], app_dic['md5']) template = 'static_analysis/android_binary_analysis.html' if api: return context else: return render(request, template, context) elif typ == 'zip': ios_ret = HttpResponseRedirect('/StaticAnalyzer_iOS/?name=' + app_dic['app_name'] + '&type=ios&checksum=' + app_dic['md5']) # Check if in DB # pylint: disable=E1101 cert_dic = { 'certificate_info': '', 'certificate_status': '', 'description': '', } bin_an_buff = [] app_dic['strings'] = [] app_dic['secrets'] = [] app_dic['zipped'] = '' # Above fields are only available for APK and not ZIP app_dic['app_file'] = app_dic['md5'] + '.zip' # NEW FILENAME app_dic['app_path'] = (app_dic['app_dir'] / app_dic['app_file']).as_posix() app_dic['app_dir'] = app_dic['app_dir'].as_posix() + '/' db_entry = StaticAnalyzerAndroid.objects.filter( MD5=app_dic['md5']) ios_db_entry = StaticAnalyzerIOS.objects.filter( MD5=app_dic['md5']) if db_entry.exists() and rescan == '0': context = get_context_from_db_entry(db_entry) elif ios_db_entry.exists() and rescan == '0': if api: return {'type': 'ios'} else: return ios_ret else: logger.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': logger.info('Redirecting to iOS Source Code Analyzer') if api: return {'type': 'ios'} else: return ios_ret app_dic['certz'] = get_hardcoded_cert_keystore( app_dic['files']) app_dic['zipped'] = pro_type logger.info('ZIP Type - %s', 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, ) # get app_name app_dic['real_name'] = get_app_name( app_dic['app_path'], app_dic['app_dir'], app_dic['tools_dir'], 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']) app_dic['playstore'] = get_app_details( man_data_dic['packagename']) man_an_dic = manifest_analysis( app_dic['persed_xml'], man_data_dic, pro_type, app_dic['app_dir'], ) # 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'], pro_type) # Firebase DB Check code_an_dic['firebase'] = firebase_analysis( list(set(code_an_dic['urls_list']))) # Domain Extraction and Malware Check logger.info( 'Performing Malware Check on extracted Domains') code_an_dic['domains'] = malware_check( list(set(code_an_dic['urls_list']))) logger.info('Connecting to Database') try: # SAVE TO DB if rescan == '1': logger.info('Updating Database...') save_or_update( 'update', app_dic, man_data_dic, man_an_dic, code_an_dic, cert_dic, bin_an_buff, {}, {}, ) update_scan_timestamp(app_dic['md5']) elif rescan == '0': logger.info('Saving to Database') save_or_update( 'save', app_dic, man_data_dic, man_an_dic, code_an_dic, cert_dic, bin_an_buff, {}, {}, ) except Exception: logger.exception('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) ctx = { 'title': 'Invalid ZIP archive', 'version': settings.MOBSF_VER, } template = 'general/zip.html' return render(request, template, ctx) context['average_cvss'], context['security_score'] = score( context['code_analysis']) template = 'static_analysis/android_source_analysis.html' if api: return context else: return render(request, template, context) else: err = ('Only APK,IPA and Zipped ' 'Android/iOS Source code supported now!') logger.error(err) 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: logger.exception('Error Performing Static Analysis') 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)
def staticanalyzer_windows(request, api=False): """Analyse a windows app.""" try: # Input validation logger.info('Windows Static Analysis Started') app_dic = {} # Dict to store the binary attributes if api: typ = request.POST['scan_type'] rescan = str(request.POST.get('re_scan', 0)) checksum = request.POST['hash'] filename = request.POST['file_name'] else: typ = request.GET['type'] rescan = str(request.GET.get('rescan', 0)) checksum = request.GET['checksum'] filename = request.GET['name'] md5_regex = re.match('^[0-9a-f]{32}$', checksum) if (md5_regex) and (typ in ['appx']): app_dic['app_name'] = filename # APP ORGINAL NAME app_dic['md5'] = checksum app_dic['app_dir'] = os.path.join(settings.UPLD_DIR, app_dic['md5'] + '/') app_dic['tools_dir'] = os.path.join( settings.BASE_DIR, 'StaticAnalyzer/tools/windows/') if typ == 'appx': # DB db_entry = StaticAnalyzerWindows.objects.filter( MD5=app_dic['md5'], ) if db_entry.exists() and rescan == '0': logger.info('Analysis is already Done.' ' Fetching data from the DB...') context = get_context_from_db_entry(db_entry) else: logger.info('Windows Binary Analysis Started') app_dic['app_path'] = os.path.join( app_dic['app_dir'], app_dic['md5'] + '.appx') # ANALYSIS BEGINS app_dic['size'] = str(file_size( app_dic['app_path'])) + 'MB' # Generate hashes app_dic['sha1'], app_dic['sha256'] = hash_gen( app_dic['app_path']) # EXTRACT APPX logger.info('Extracting APPX') app_dic['files'] = unzip(app_dic['app_path'], app_dic['app_dir']) xml_dic = _parse_xml(app_dic['app_dir']) bin_an_dic = _binary_analysis(app_dic) # Saving to db logger.info('Connecting to DB') if rescan == '1': logger.info('Updating Database...') save_or_update('update', app_dic, xml_dic, bin_an_dic) update_scan_timestamp(app_dic['md5']) elif rescan == '0': logger.info('Saving to Database') save_or_update('save', app_dic, xml_dic, bin_an_dic) context = get_context_from_analysis( app_dic, xml_dic, bin_an_dic) context['virus_total'] = None if settings.VT_ENABLED: vt = VirusTotal.VirusTotal() context['virus_total'] = vt.get_result( os.path.join(app_dic['app_dir'], app_dic['md5']) + '.appx', app_dic['md5']) template = 'static_analysis/windows_binary_analysis.html' if api: return context else: return render(request, template, context) else: msg = 'File type not supported' if api: return print_n_send_error_response(request, msg, True) else: return print_n_send_error_response(request, msg, False) else: msg = 'Hash match failed or Invalid file extension' if api: return print_n_send_error_response(request, msg, True) else: return print_n_send_error_response(request, msg, False) except Exception as exception: logger.exception('Error Performing Static Analysis') msg = str(exception) exp_doc = exception.__doc__ if api: return print_n_send_error_response(request, msg, True, exp_doc) else: return print_n_send_error_response(request, msg, False, exp_doc)
def pdf(request, api=False, jsonres=False): try: if api: checksum = request.POST['hash'] else: checksum = request.GET['md5'] hash_match = re.match('^[0-9a-f]{32}$', checksum) if not hash_match: if api: return {'error': 'Invalid scan hash'} else: return HttpResponse(json.dumps({'md5': 'Invalid scan hash'}), content_type=ctype, status=500) # Do Lookups android_static_db = StaticAnalyzerAndroid.objects.filter(MD5=checksum) ios_static_db = StaticAnalyzerIOS.objects.filter(MD5=checksum) win_static_db = StaticAnalyzerWindows.objects.filter(MD5=checksum) if android_static_db.exists(): key = settings.MODEL_K % ('StaticAnalyzerAndroid', checksum) context, template = handle_pdf_android(android_static_db, key) elif ios_static_db.exists(): context, template = handle_pdf_ios(ios_static_db) elif win_static_db.exists(): context, template = handle_pdf_win(win_static_db) else: if api: return {'report': 'Report not Found'} else: return HttpResponse(json.dumps({'report': 'Report not Found'}), content_type=ctype, status=500) # Do VT Scan only on binaries context['virus_total'] = None ext = os.path.splitext(context['file_name'].lower())[1] if settings.VT_ENABLED and ext != '.zip': app_bin = os.path.join(settings.UPLD_DIR, checksum + '/', checksum + ext) vt = VirusTotal.VirusTotal() context['virus_total'] = vt.get_result(app_bin, checksum) # Get Local Base URL proto = 'file://' host_os = 'nix' if platform.system() == 'Windows': proto = 'file:///' host_os = 'windows' context['base_url'] = proto + settings.BASE_DIR context['dwd_dir'] = proto + settings.DWD_DIR context['host_os'] = host_os # 增加:返回时间 time = RecentScansDB.objects.get(MD5=checksum).TIMESTAMP context['time'] = time # 增加:证书subject和issuer提取 certificate_info = context['certificate_analysis']['certificate_info'] subject = re.search(r'Subject:.*', certificate_info).group().split(':')[1] issuer = re.search(r'Issuer:.*', certificate_info).group().split(':')[1] context['cer_subject'] = subject context['cer_issuer'] = issuer # 增加:permmision排序 perm_dict_items = context['permissions'].items() sorted_perm = sorted(perm_dict_items, key=lambda x: x[1]['status']) context['sorted_perm'] = sorted_perm #测试url context['test_url'] = [ { "urls": [ "http://192.168.1.201:12345/ad_monitor/uploadReceiver.php?os=android&platform=domob" ], "path": "cn/domob/android/ads/C0027o.java", "results": [{ "phones": ["18337258710", "15160578228"], "cards": [], "passports": ["E16728736"], "gps_lng_lat": [(78.356287, 120.834628)], "sources": "http://192.168.1.201:12345/ad_monitor/uploadReceiver.php?os=android&platform=domob" }] }, { "urls": ["http://www.google.com/loc/json"], "path": "cn/domob/android/ads/C0029q.java", "results": [{ "phones": [], "cards": [], "passports": [], "gps_lng_lat": [], "sources": "" }] }, { "urls": ["http://r.domob.cn/a/"], "path": "cn/domob/android/ads/C0032t.java", "results": [{ "phones": [], "cards": [], "passports": [], "gps_lng_lat": [], "sources": "" }] }, { "urls": ["http://e.domob.cn/event_report", "http://r.domob.cn/a/"], "path": "cn/domob/android/ads/C0017e.java", "results": [{ "phones": ["18337258710", "15160578228"], "cards": [], "passports": ["E16728736"], "gps_lng_lat": [(78.356287, 120.834628)], "sources": "http://e.domob.cn/event_report" }] }, { "urls": ["http://r.domob.cn/a/"], "path": "cn/domob/android/ads/C0022j.java", "results": [{ "phones": ["18337258710", "15160578228"], "cards": [], "passports": ["E16233236"], "gps_lng_lat": [(78.356287, 120.834628)], "sources": "http://r.domob.cn/a/" }] }, ] try: if api and jsonres: return {'report_dat': context} else: options = { 'page-size': 'A4', 'quiet': '', 'no-collate': '', 'margin-top': '15mm', 'margin-right': '10mm', 'margin-bottom': '15mm', 'margin-left': '10mm', 'encoding': 'UTF-8', 'header-line': '', # 页脚与正文之间的距离(默认为零) 'header-spacing': 2, 'footer-spacing': 2, # 设置页码 'footer-center': '第 [page] 页', # 'custom-header': [ # ('Accept-Encoding', 'gzip'), # ], # 'dump-outline':'toc.xml', # 'dump-default-toc-xsl': 'my.xsl', 'outline': '', # 大纲的深度 'outline-depth': '2', } xsl_path = os.path.join(settings.BASE_DIR, "templates/my.xsl"), toc = { # 'toc-header-text':'目录', 'toc-level-indentation': '100', 'disable-dotted-lines': '', 'xsl-style-sheet': xsl_path, } # cover = os.path.join(settings.BASE_DIR, 'templates/cover.html') html = template.render(context) # Added proxy support to wkhtmltopdf proxies, _ = upstream_proxy('https') if proxies['https']: options['proxy'] = proxies['https'] # pdf_dat = pdfkit.from_string(html,False,options,toc,cover,cover_first=True) pdf_dat = pdfkit.from_string(html, False, options, toc) if api: return {'pdf_dat': pdf_dat} return HttpResponse(pdf_dat, content_type='application/pdf') except Exception as exp: logger.exception('Error Generating PDF Report') if api: return { 'error': 'Cannot Generate PDF/JSON', 'err_details': str(exp) } else: return HttpResponse(json.dumps({ 'pdf_error': 'Cannot Generate PDF', 'err_details': str(exp) }), content_type=ctype, status=500) except Exception as exp: logger.exception('Error Generating PDF Report') msg = str(exp) exp = exp.__doc__ if api: return print_n_send_error_response(request, msg, True, exp) else: return print_n_send_error_response(request, msg, False, exp)
def pdf(request, api=False, jsonres=False): try: if api: checksum = request.POST['hash'] else: checksum = request.GET['md5'] hash_match = re.match('^[0-9a-f]{32}$', checksum) if hash_match: android_static_db = StaticAnalyzerAndroid.objects.filter( MD5=checksum) ios_static_db = StaticAnalyzerIOS.objects.filter(MD5=checksum) win_static_db = StaticAnalyzerWindows.objects.filter(MD5=checksum) if android_static_db.exists(): context, template = handle_pdf_android(android_static_db) elif ios_static_db.exists(): context, template = handle_pdf_ios(ios_static_db) elif win_static_db.exists(): context, template = handle_pdf_win(win_static_db) else: if api: return {'report': 'Report not Found'} else: return HttpResponse( json.dumps({'report': 'Report not Found'}), content_type='application/json; charset=utf-8', status=500) context['virus_total'] = None if settings.VT_ENABLED: file_extension = os.path.splitext( context['file_name'].lower())[1] app_dir = os.path.join(settings.UPLD_DIR, checksum + '/') vt = VirusTotal.VirusTotal() if file_extension.lower() == '.zip': context['virus_total'] = None else: context['virus_total'] = vt.get_result( os.path.join(app_dir, checksum) + file_extension.lower(), checksum) try: if api and jsonres: return {'report_dat': context} else: options = { 'page-size': 'A4', 'quiet': '', 'no-collate': '', 'margin-top': '0.50in', 'margin-right': '0.50in', 'margin-bottom': '0.50in', 'margin-left': '0.50in', 'encoding': 'UTF-8', 'custom-header': [ ('Accept-Encoding', 'gzip'), ], 'no-outline': None, } html = template.render(context) pdf_dat = pdfkit.from_string(html, False, options=options) if api: return {'pdf_dat': pdf_dat} return HttpResponse(pdf_dat, content_type='application/pdf') except Exception as exp: logger.exception('Error Generating PDF Report') if api: return { 'error': 'Cannot Generate PDF/JSON', 'err_details': str(exp) } else: return HttpResponse( json.dumps({ 'pdf_error': 'Cannot Generate PDF', 'err_details': str(exp) }), content_type='application/json; charset=utf-8', status=500) else: if api: return {'error': 'Invalid scan hash'} else: return HttpResponse( json.dumps({'md5': 'Invalid MD5'}), content_type='application/json; charset=utf-8', status=500) except Exception as exp: logger.exception('Error Generating PDF Report') msg = str(exp) exp = exp.__doc__ if api: return print_n_send_error_response(request, msg, True, exp) else: return print_n_send_error_response(request, msg, False, exp)