def static_analyzer(request): """Do static analysis on an request and save to db.""" try: # Input validation app_dic = {} typ = request.GET['type'] # output = request.GET['format'] # Later for json output match = re.match('^[0-9a-f]{32}$', request.GET['checksum']) if ((match) and (request.GET['name'].lower().endswith('.apk') or request.GET['name'].lower().endswith('.zip')) and (typ in ['zip', 'apk'])): app_dic['dir'] = settings.BASE_DIR # BASE DIR app_dic['app_name'] = request.GET['name'] # APP ORGINAL NAME app_dic['md5'] = request.GET['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'] rescan = str(request.GET.get('rescan', 0)) 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(FileSize( app_dic['app_path'])) + 'MB' # FILE SIZE app_dic['sha1'], app_dic['sha256'] = HashGen( 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_dir'], app_dic['tools_dir'], '', True) # 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) cert_dic = cert_info(app_dic['app_dir'], app_dic['tools_dir']) 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'], app_dic['md5'], man_an_dic['permissons'], "apk") print "\n[INFO] Generating Java and Smali Downloads" gen_downloads(app_dic['app_dir'], app_dic['md5']) # Get the strings app_dic['strings'] = strings(app_dic['app_file'], app_dic['app_dir'], app_dic['tools_dir']) app_dic['zipped'] = '&type=apk' 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) 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) except: PrintException("[ERROR] Saving to Database Failed") context = get_context_from_an(app_dic, man_data_dic, man_an_dic, code_an_dic, cert_dic) template = "static_analysis/static_analysis.html" return render(request, template, context) elif typ == 'zip': # 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_zip(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" 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']) print "[INFO] ZIP Type - " + pro_type if valid and (pro_type in ['eclipse', 'studio']): # ANALYSIS BEGINS app_dic['size'] = str(FileSize( app_dic['app_path'])) + 'MB' # FILE SIZE app_dic['sha1'], app_dic['sha256'] = HashGen( 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) code_an_dic = code_analysis(app_dic['app_dir'], app_dic['md5'], 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_zip(app_dic, man_data_dic, man_an_dic, code_an_dic) elif rescan == '0': print "\n[INFO] Saving to Database" create_db_entry_zip(app_dic, man_data_dic, man_an_dic, code_an_dic) except: PrintException("[ERROR] Saving to Database Failed") context = get_context_from_an_zip( app_dic, man_data_dic, man_an_dic, code_an_dic) else: return HttpResponseRedirect('/zip_format/') template = "static_analysis/static_analysis_android_zip.html" return render(request, template, context) else: print "\n[ERROR] Only APK,IPA and Zipped Android/iOS Source code supported now!" else: return HttpResponseRedirect('/error/') except Exception as excep: PrintException("[ERROR] Static Analyzer") context = { 'title': 'Error', 'exp': excep.message, 'doc': excep.__doc__ } template = "general/error.html" return render(request, template, context)
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 generic_compare(request, first_hash: str, second_hash: str, api: bool = False): # This context consists of specific lists and analysis that is done on the classic ones # it will be filled during the different diff analysis context = { 'title': 'Compare report', 'first_app': dict(), 'second_app': dict(), 'urls': dict(), 'api': dict(), 'permissions': dict(), 'apkid': dict() } static_fields = [ 'md5', 'name', 'size', 'icon_found', 'icon_hidden', 'act_count', 'e_act', 'serv_count', 'e_ser', 'bro_count', 'e_bro', 'prov_count', 'e_cnt', 'apkid' ] # For now - support only android db_entry = StaticAnalyzerAndroid.objects.filter(MD5=first_hash) db_entry2 = StaticAnalyzerAndroid.objects.filter(MD5=second_hash) if not (db_entry.exists() and db_entry2.exists()): return print_n_send_error_response( request, "One of the Hashes wasn't found in the Android-results DB, make sure " "both of the apps finished analysis & they are both Android", False) # First fetch the already done analysis on each of the apps # We don't want to return this whole context back to the user because its a lot of data we don't use # it should help the performance I guess first_app = deepcopy(get_context_from_db_entry(db_entry)) second_app = deepcopy(get_context_from_db_entry(db_entry2)) # Second, fill the common static parts that are missing in the classic analysis for curr_app, db_context in [('first_app', first_app), ('second_app', second_app)]: # format informative title context[curr_app]['name_ver'] = "{0} - {1}".format( db_context['packagename'], db_context['androvername']) # Fill all the static information for static_attr in static_fields: context[curr_app][static_attr] = db_context[static_attr] # Get only the subject of the cert subject_regex = re.compile(r'.*Subject:([^<]+)</br>.*', re.DOTALL) match = subject_regex.match(db_context['certinfo']) if match: context[curr_app]['cert_subject'] = match.group(1) else: context[curr_app]['cert_subject'] = "No subject" # Some preparations so we have some sort of same structures # (urls are lists inside the list which mess things up...) tmp_list = list() for url_obj in db_context['urls']: for url in url_obj['urls']: # urls can mess up the table because they can be really long, so let's cut them tmp_url = url[:70] while len(url) > 70: url = url[70:] tmp_url += '<br />' tmp_url += url[:70] tmp_list.append(tmp_url) db_context['urls'] = list(set(deepcopy(tmp_list))) tmp_list.clear() # apkid check - we do it here just because its really ugly inside the template # it has a dedicated function because the result is more complicated then the others... diff_apkid(context) # Third, calculate some diffs for section, is_tuples in [('permissions', True), ('api', True), ('urls', False)]: if is_tuples: context[section]['common'] = [ (x, y) for (x, y) in first_app[section].items() if x in second_app[section].keys() ] # Only first context[section]['only_first'] = [ (x, y) for (x, y) in first_app[section].items() if x not in second_app[section].keys() ] # Only Second context[section]['only_second'] = [ (x, y) for (x, y) in second_app[section].items() if x not in first_app[section].keys() ] else: context[section]['common'] = [ x for x in first_app[section] if x in second_app[section] ] context[section]['only_first'] = [ x for x in first_app[section] if x not in second_app[section] ] context[section]['only_second'] = [ x for x in second_app[section] if x not in first_app[section] ] template = "static_analysis/compare.html" if api: return context else: return render(request, template, context)
def generic_compare(request, first_hash: str, second_hash: str, api: bool = False): # This context consists of specific lists and analysis # that is done on the classic ones # it will be filled during the different diff analysis context = { 'title': 'Compare report', 'version': settings.MOBSF_VER, 'first_app': {}, 'second_app': {}, 'urls': {}, 'android_api': {}, 'permissions': {}, 'apkid': {}, } static_fields = [ 'md5', 'file_name', 'size', 'icon_found', 'icon_hidden', 'activities', 'services', 'providers', 'receivers', 'exported_count', 'apkid' ] # For now - support only android db_entry = StaticAnalyzerAndroid.objects.filter(MD5=first_hash) db_entry2 = StaticAnalyzerAndroid.objects.filter(MD5=second_hash) if not (db_entry.exists() and db_entry2.exists()): return print_n_send_error_response( request, 'Currently you can only diff/compare android apps. ' 'One of the app has not completed static analysis or' ' they are not both android APK/ZIP.', api, ) # First fetch the already done analysis on each of the apps # We don't want to return this whole context back to the user # because its a lot of data we don't use # it should help the performance I guess first_app = deepcopy(get_context_from_db_entry(db_entry)) second_app = deepcopy(get_context_from_db_entry(db_entry2)) # Second, fill the common static parts that # are missing in the classic analysis for curr_app, db_context in [('first_app', first_app), ('second_app', second_app)]: # format informative title context[curr_app]['name_ver'] = '{0} - {1}'.format( db_context['package_name'], db_context['version_name']) # Fill all the static information for static_attr in static_fields: context[curr_app][static_attr] = db_context[static_attr] # Get only the subject of the cert subject_regex = re.compile(r'Subject: .*') match = subject_regex.search( db_context['certificate_analysis']['certificate_info']) if match: context[curr_app]['cert_subject'] = match.group() else: context[curr_app]['cert_subject'] = 'No subject' # Some preparations so we have some sort of same structures # (urls are lists inside the list which mess things up...) tmp_list = [] for url_obj in db_context['urls']: for url in url_obj['urls']: # urls can mess up the table because they can be really long, # so let's cut them # escape url url = escape(url) tmp_url = url[:70] while len(url) > 70: url = url[70:] tmp_url += '<br />' tmp_url += url[:70] tmp_list.append(tmp_url) db_context['urls'] = list(set(deepcopy(tmp_list))) tmp_list.clear() # apkid check - we do it here just because # its really ugly inside the template # it has a dedicated function because the result # is more complicated then the others... diff_apkid(context) # Third, calculate some diffs for section, is_tuples in [ ('permissions', True), ('android_api', True), ('urls', False), ]: if is_tuples: context[section]['common'] = [ (x, y) for (x, y) in first_app[section].items() if x in second_app[section].keys() ] # Only first context[section]['only_first'] = [ (x, y) for (x, y) in first_app[section].items() if x not in second_app[section].keys() ] # Only Second context[section]['only_second'] = [ (x, y) for (x, y) in second_app[section].items() if x not in first_app[section].keys() ] else: context[section]['common'] = [ x for x in first_app[section] if x in second_app[section] ] context[section]['only_first'] = [ x for x in first_app[section] if x not in second_app[section] ] context[section]['only_second'] = [ x for x in second_app[section] if x not in first_app[section] ] template = 'static_analysis/compare.html' if api: return context else: return render(request, template, context)
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 PDF(request): try: MD5 = request.GET['md5'] TYP = request.GET['type'] m = re.match('^[0-9a-f]{32}$', MD5) if m: if TYP in ['APK', 'ANDZIP']: DB = StaticAnalyzerAndroid.objects.filter(MD5=MD5) if DB.exists(): print "\n[INFO] Fetching data from DB for PDF Report Generation (Android)" context = get_context_from_db_entry(DB) if TYP == 'APK': template = get_template("pdf/static_analysis_pdf.html") else: template = get_template( "pdf/static_analysis_zip_pdf.html") else: return HttpResponse( json.dumps({"report": "Report not Found"}), content_type="application/json; charset=utf-8") elif re.findall('IPA|IOSZIP', TYP): if TYP == 'IPA': DB = StaticAnalyzerIPA.objects.filter(MD5=MD5) if DB.exists(): print "\n[INFO] Fetching data from DB for PDF Report Generation (IOS IPA)" context = { 'title': DB[0].TITLE, 'name': DB[0].APPNAMEX, 'size': DB[0].SIZE, 'md5': DB[0].MD5, 'sha1': DB[0].SHA1, 'sha256': DB[0].SHA256, 'plist': DB[0].INFOPLIST, 'bin_name': DB[0].BINNAME, 'id': DB[0].IDF, 'ver': DB[0].VERSION, 'sdk': DB[0].SDK, 'pltfm': DB[0].PLTFM, 'min': DB[0].MINX, 'bin_anal': DB[0].BIN_ANAL, 'libs': DB[0].LIBS, 'files': python_list(DB[0].FILES), 'file_analysis': DB[0].SFILESX, 'strings': python_list(DB[0].STRINGS), 'permissions': python_list(DB[0].PERMISSIONS) } template = get_template( "pdf/ios_binary_analysis_pdf.html") else: return HttpResponse( json.dumps({"report": "Report not Found"}), content_type="application/json; charset=utf-8") elif TYP == 'IOSZIP': DB = StaticAnalyzerIOSZIP.objects.filter(MD5=MD5) if DB.exists(): print "\n[INFO] Fetching data from DB for PDF Report Generation (IOS ZIP)" context = { 'title': DB[0].TITLE, 'name': DB[0].APPNAMEX, 'size': DB[0].SIZE, 'md5': DB[0].MD5, 'sha1': DB[0].SHA1, 'sha256': DB[0].SHA256, 'plist': DB[0].INFOPLIST, 'bin_name': DB[0].BINNAME, 'id': DB[0].IDF, 'ver': DB[0].VERSION, 'sdk': DB[0].SDK, 'pltfm': DB[0].PLTFM, 'min': DB[0].MINX, 'bin_anal': DB[0].BIN_ANAL, 'libs': DB[0].LIBS, 'files': python_list(DB[0].FILES), 'file_analysis': DB[0].SFILESX, 'api': DB[0].HTML, 'insecure': DB[0].CODEANAL, 'urls': DB[0].URLnFile, 'domains': python_dict(DB[0].DOMAINS), 'emails': DB[0].EmailnFile, 'permissions': python_list(DB[0].PERMISSIONS) } template = get_template( "pdf/ios_source_analysis_pdf.html") else: return HttpResponse( json.dumps({"report": "Report not Found"}), content_type="application/json; charset=utf-8") elif re.findall('APPX', TYP): if TYP == 'APPX': db_entry = StaticAnalyzerWindows.objects.filter( # pylint: disable-msg=E1101 MD5=MD5) if db_entry.exists(): print "\n[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: return HttpResponse( json.dumps({"type": "Type is not Allowed"}), content_type="application/json; charset=utf-8") html = template.render(context) result = StringIO() pdf = pisa.pisaDocument(StringIO("{0}".format( html.encode('utf-8'))), result, encoding='utf-8') if not pdf.err: return HttpResponse(result.getvalue(), content_type='application/pdf') else: return HttpResponseRedirect('/error/') else: return HttpResponse(json.dumps({"md5": "Invalid MD5"}), content_type="application/json; charset=utf-8") except: PrintException("[ERROR] PDF Report Generation Error") return HttpResponseRedirect('/error/')
def PDF(request): try: MD5 = request.GET['md5'] TYP = request.GET['type'] m = re.match('^[0-9a-f]{32}$', MD5) if m: if TYP in ['APK', 'ANDZIP']: DB = StaticAnalyzerAndroid.objects.filter(MD5=MD5) if DB.exists(): print "\n[INFO] Fetching data from DB for PDF Report Generation (Android)" context = get_context_from_db_entry(DB) if TYP == 'APK': template = get_template("pdf/static_analysis_pdf.html") else: template = get_template( "pdf/static_analysis_zip_pdf.html") else: return HttpResponse(json.dumps({"report": "Report not Found"}), content_type="application/json; charset=utf-8") elif re.findall('IPA|IOSZIP', TYP): if TYP == 'IPA': DB = StaticAnalyzerIPA.objects.filter(MD5=MD5) if DB.exists(): print "\n[INFO] Fetching data from DB for PDF Report Generation (IOS IPA)" context = get_context_from_db_entry_ipa(DB) template = get_template( "pdf/ios_binary_analysis_pdf.html") else: return HttpResponse(json.dumps({"report": "Report not Found"}), content_type="application/json; charset=utf-8") elif TYP == 'IOSZIP': DB = StaticAnalyzerIOSZIP.objects.filter(MD5=MD5) if DB.exists(): print "\n[INFO] Fetching data from DB for PDF Report Generation (IOS ZIP)" context = get_context_from_db_entry_ios(DB) template = get_template( "pdf/ios_source_analysis_pdf.html") else: return HttpResponse(json.dumps({"report": "Report not Found"}), content_type="application/json; charset=utf-8") elif re.findall('APPX', TYP): if TYP == 'APPX': db_entry = StaticAnalyzerWindows.objects.filter( # pylint: disable-msg=E1101 MD5=MD5 ) if db_entry.exists(): print "\n[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: return HttpResponse(json.dumps({"type": "Type is not Allowed"}), content_type="application/json; charset=utf-8") html = template.render(context) try: 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 } pdf = pdfkit.from_string(html, False, options=options) return HttpResponse(pdf, content_type='application/pdf') except Exception as exp: return HttpResponse(json.dumps({"pdf_error": "Cannot Generate PDF", "err_details": str(exp)}), content_type="application/json; charset=utf-8") else: return HttpResponse(json.dumps({"md5": "Invalid MD5"}), content_type="application/json; charset=utf-8") except: PrintException("[ERROR] PDF Report Generation Error") return HttpResponseRedirect('/error/')
def static_analyzer(request): """Do static analysis on an request and save to db.""" try: # Input validation app_dic = {} typ = request.GET['type'] # output = request.GET['format'] # Later for json output match = re.match('^[0-9a-f]{32}$', request.GET['checksum']) if ( ( match ) and ( request.GET['name'].lower().endswith('.apk') or request.GET['name'].lower().endswith('.zip') ) and ( typ in ['zip', 'apk'] ) ): app_dic['dir'] = settings.BASE_DIR # BASE DIR app_dic['app_name'] = request.GET['name'] # APP ORGINAL NAME app_dic['md5'] = request.GET['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'] rescan = str(request.GET.get('rescan', 0)) 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( FileSize(app_dic['app_path'])) + 'MB' # FILE SIZE app_dic['sha1'], app_dic[ 'sha256'] = HashGen(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_dir'], app_dic['tools_dir'], '', True ) # 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'], "apk" ) bin_an_buff += res_analysis( app_dic['app_dir'], "apk" ) cert_dic = cert_info( app_dic['app_dir'], app_dic['tools_dir']) 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'], app_dic['md5'], man_an_dic['permissons'], "apk" ) print "\n[INFO] Generating Java and Smali Downloads" gen_downloads(app_dic['app_dir'], app_dic['md5']) # Get the strings app_dic['strings'] = strings( app_dic['app_file'], app_dic['app_dir'], app_dic['tools_dir'] ) app_dic['zipped'] = '&type=apk' 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 ) template = "static_analysis/static_analysis.html" return render(request, template, context) elif typ == 'zip': # Check if in DB # pylint: disable=E1101 cert_dic = {} cert_dic['cert_info'] = '' cert_dic['issued'] = '' 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" 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']) print "[INFO] ZIP Type - " + pro_type if valid and (pro_type in ['eclipse', 'studio']): # ANALYSIS BEGINS app_dic['size'] = str( FileSize(app_dic['app_path'])) + 'MB' # FILE SIZE app_dic['sha1'], app_dic[ 'sha256'] = HashGen(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 ) code_an_dic = code_analysis( app_dic['app_dir'], app_dic['md5'], 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: return HttpResponseRedirect('/zip_format/') template = "static_analysis/static_analysis_android_zip.html" return render(request, template, context) else: print "\n[ERROR] Only APK,IPA and Zipped Android/iOS Source code supported now!" else: return HttpResponseRedirect('/error/') except Exception as excep: PrintException("[ERROR] Static Analyzer") context = { 'title': 'Error', 'exp': excep.message, 'doc': excep.__doc__ } template = "general/error.html" return render(request, template, context)
def PDF(request): try: MD5 = request.GET['md5'] TYP = request.GET['type'] m = re.match('^[0-9a-f]{32}$', MD5) if m: if TYP in ['APK', 'ANDZIP']: DB = StaticAnalyzerAndroid.objects.filter(MD5=MD5) if DB.exists(): print "\n[INFO] Fetching data from DB for PDF Report Generation (Android)" context = get_context_from_db_entry(DB) if TYP == 'APK': template = get_template("pdf/static_analysis_pdf.html") else: template = get_template( "pdf/static_analysis_zip_pdf.html") else: return HttpResponse(json.dumps({"report": "Report not Found"}), content_type="application/json; charset=utf-8") elif re.findall('IPA|IOSZIP', TYP): if TYP == 'IPA': DB = StaticAnalyzerIPA.objects.filter(MD5=MD5) if DB.exists(): print "\n[INFO] Fetching data from DB for PDF Report Generation (IOS IPA)" context = { 'title': DB[0].TITLE, 'name': DB[0].APPNAMEX, 'size': DB[0].SIZE, 'md5': DB[0].MD5, 'sha1': DB[0].SHA1, 'sha256': DB[0].SHA256, 'plist': DB[0].INFOPLIST, 'bin_name': DB[0].BINNAME, 'id': DB[0].IDF, 'ver': DB[0].VERSION, 'sdk': DB[0].SDK, 'pltfm': DB[0].PLTFM, 'min': DB[0].MINX, 'bin_anal': DB[0].BIN_ANAL, 'libs': DB[0].LIBS, 'files': python_list(DB[0].FILES), 'file_analysis': DB[0].SFILESX, 'strings': python_list(DB[0].STRINGS), 'permissions': python_list(DB[0].PERMISSIONS) } template = get_template( "pdf/ios_binary_analysis_pdf.html") else: return HttpResponse(json.dumps({"report": "Report not Found"}), content_type="application/json; charset=utf-8") elif TYP == 'IOSZIP': DB = StaticAnalyzerIOSZIP.objects.filter(MD5=MD5) if DB.exists(): print "\n[INFO] Fetching data from DB for PDF Report Generation (IOS ZIP)" context = { 'title': DB[0].TITLE, 'name': DB[0].APPNAMEX, 'size': DB[0].SIZE, 'md5': DB[0].MD5, 'sha1': DB[0].SHA1, 'sha256': DB[0].SHA256, 'plist': DB[0].INFOPLIST, 'bin_name': DB[0].BINNAME, 'id': DB[0].IDF, 'ver': DB[0].VERSION, 'sdk': DB[0].SDK, 'pltfm': DB[0].PLTFM, 'min': DB[0].MINX, 'bin_anal': DB[0].BIN_ANAL, 'libs': DB[0].LIBS, 'files': python_list(DB[0].FILES), 'file_analysis': DB[0].SFILESX, 'api': DB[0].HTML, 'insecure': DB[0].CODEANAL, 'urls': DB[0].URLnFile, 'domains': python_dict(DB[0].DOMAINS), 'emails': DB[0].EmailnFile, 'permissions': python_list(DB[0].PERMISSIONS) } template = get_template( "pdf/ios_source_analysis_pdf.html") else: return HttpResponse(json.dumps({"report": "Report not Found"}), content_type="application/json; charset=utf-8") elif re.findall('APPX', TYP): if TYP == 'APPX': db_entry = StaticAnalyzerWindows.objects.filter( # pylint: disable-msg=E1101 MD5=MD5 ) if db_entry.exists(): print "\n[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: return HttpResponse(json.dumps({"type": "Type is not Allowed"}), content_type="application/json; charset=utf-8") html = template.render(context) result = StringIO() pdf = pisa.pisaDocument(StringIO("{0}".format( html.encode('utf-8'))), result, encoding='utf-8') if not pdf.err: return HttpResponse(result.getvalue(), content_type='application/pdf') else: return HttpResponseRedirect('/error/') else: return HttpResponse(json.dumps({"md5": "Invalid MD5"}), content_type="application/json; charset=utf-8") except: PrintException("[ERROR] PDF Report Generation Error") return HttpResponseRedirect('/error/')
def pdf(request, api=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(): print "\n[INFO] Fetching data from DB for PDF Report Generation (Android)" context = get_context_from_db_entry(static_db) if scan_type.lower() == 'apk': template = get_template("pdf/static_analysis_pdf.html") else: template = get_template( "pdf/static_analysis_zip_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_code=500) elif re.findall('ipa|ioszip', scan_type.lower()): if scan_type.lower() == 'ipa': static_db = StaticAnalyzerIPA.objects.filter(MD5=checksum) if static_db.exists(): print "\n[INFO] Fetching data from DB for PDF Report Generation (IOS IPA)" context = get_context_from_db_entry_ipa(static_db) 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_code=500) elif scan_type.lower() == 'ioszip': static_db = StaticAnalyzerIOSZIP.objects.filter(MD5=checksum) if static_db.exists(): print "\n[INFO] Fetching data from DB for PDF Report Generation (IOS ZIP)" context = get_context_from_db_entry_ios(static_db) 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_code=500) elif re.findall('appx', scan_type.lower()): if scan_type.lower() == 'appx': db_entry = StaticAnalyzerWindows.objects.filter(# pylint: disable-msg=E1101 MD5=checksum ) if db_entry.exists(): print "\n[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_code=500) html = template.render(context) try: 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 } pdf_dat = pdfkit.from_string(html, False, options=options) if api: return {"pdf_dat": pdf_dat} else: return HttpResponse(pdf_dat, content_type='application/pdf') except Exception as exp: if api: return {"error": "Cannot Generate PDF", "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_code=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_code=500) except Exception as exp: 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 generic_compare(request, first_hash: str, second_hash: str, api: bool = False): # This context consists of specific lists and analysis that is done on the classic ones # it will be filled during the different diff analysis context = { 'title': 'Compare report', 'first_app': dict(), 'second_app': dict(), 'urls': dict(), 'api': dict(), 'permissions': dict() } static_fields = ['md5', 'name', 'size', 'icon_found', 'icon_hidden', 'act_count', 'e_act', 'serv_count', 'e_ser', 'bro_count', 'e_bro', 'prov_count', 'e_cnt', 'apkid'] # For now - support only android db_entry = StaticAnalyzerAndroid.objects.filter(MD5=first_hash) db_entry2 = StaticAnalyzerAndroid.objects.filter(MD5=second_hash) if not (db_entry.exists() and db_entry2.exists()): return print_n_send_error_response(request, "One of the Hashes wasn't found in the Android-results DB, make sure " "both of the apps finished analysis & they are both Android", False) # First fetch the already done analysis on each of the apps # We don't want to return this whole context back to the user because its a lot of data we don't use # it should help the performance I guess first_app = deepcopy(get_context_from_db_entry(db_entry)) second_app = deepcopy(get_context_from_db_entry(db_entry2)) # Second, fill the mutual static parts that are missing in the classic analysis for curr_app, db_context in [('first_app', first_app), ('second_app', second_app)]: # format informative title context[curr_app]['name_ver'] = "{0} - {1}".format(db_context['packagename'], db_context['androvername']) # Fill all the static information for static_attr in static_fields: context[curr_app][static_attr] = db_context[static_attr] # Get only the subject of the cert subject_regex = re.compile(r'.*Subject:([^<]+)</br>.*', re.DOTALL) match = subject_regex.match(db_context['certinfo']) if match: context[curr_app]['cert_subject'] = match.group(1) else: context[curr_app]['cert_subject'] = "No subject" # Some preparations so we have some sort of same structures # (urls are lists inside the list which mess things up...) tmp_list = list() for url_obj in db_context['urls']: for url in url_obj['urls']: # urls can mess up the table because they can be really long, so let's cut them tmp_url = url[:70] while len(url) > 70: url = url[70:] tmp_url += '<br />' tmp_url += url[:70] tmp_list.append(tmp_url) db_context['urls'] = list(set(deepcopy(tmp_list))) tmp_list.clear() # apkid check - we do it here just because its really ugly inside the template # I split it into these lines just it to be really clear what I'm checking first_error = context['first_app']['apkid'].get('error', False) second_error = context['second_app']['apkid'].get('error', False) first_has_version = context['first_app']['apkid'].get('apkid_version', False) second_has_version = context['second_app']['apkid'].get('apkid_version', False) context['apkid_error'] = (first_error or not first_has_version) or (second_error or not second_has_version) # Third, calculate some diffs for section, is_tuples in [ ('permissions', True), ('api', True), ('urls', False) ]: if is_tuples: context[section]['mutual'] = [(x, y) for (x, y) in first_app[section].items() if x in second_app[section].keys()] # Only first context[section]['only_first'] = [(x, y) for (x, y) in first_app[section].items() if x not in second_app[section].keys()] # Only Second context[section]['only_second'] = [(x, y) for (x, y) in second_app[section].items() if x not in first_app[section].keys()] else: context[section]['mutual'] = [x for x in first_app[section] if x in second_app[section]] context[section]['only_first'] = [x for x in first_app[section] if x not in second_app[section]] context[section]['only_second'] = [x for x in second_app[section] if x not in first_app[section]] template = "static_analysis/compare.html" if api: return context else: return render(request, template, context)
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']) 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']) 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, ) 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, ) 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, ) 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 pdf(request, api=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(): print "\n[INFO] Fetching data from DB for PDF Report Generation (Android)" context = get_context_from_db_entry(static_db) if scan_type.lower() == 'apk': template = get_template("pdf/static_analysis_pdf.html") else: template = get_template( "pdf/static_analysis_zip_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 re.findall('ipa|ioszip', scan_type.lower()): if scan_type.lower() == 'ipa': static_db = StaticAnalyzerIPA.objects.filter(MD5=checksum) if static_db.exists(): print "\n[INFO] Fetching data from DB for PDF Report Generation (IOS IPA)" context = get_context_from_db_entry_ipa(static_db) 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(): print "\n[INFO] Fetching data from DB for PDF Report Generation (IOS ZIP)" context = get_context_from_db_entry_ios(static_db) 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 re.findall('appx', scan_type.lower()): if scan_type.lower() == 'appx': db_entry = StaticAnalyzerWindows.objects.filter( # pylint: disable-msg=E1101 MD5=checksum) if db_entry.exists(): print "\n[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() context['VT_RESULT'] = vt.get_result( os.path.join(app_dir, checksum) + '.' + scan_type.lower(), checksum) html = template.render(context) try: 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 } BASE_DIR = os.path.dirname( os.path.dirname(os.path.dirname( os.path.abspath(__file__)))) path_wk = os.path.join(BASE_DIR, 'windows/wkhtmltopdf/wkhtmltopdf.exe') # path_wk = r'C:\Program Files\wkhtmltopdf\bin\wkhtmltopdf.exe' # 安装位置 config = pdfkit.configuration(wkhtmltopdf=path_wk) pdf_dat = pdfkit.from_string(html, False, options=options, configuration=config) if api: return {"pdf_dat": pdf_dat} else: return HttpResponse(pdf_dat, content_type='application/pdf') except Exception as exp: if api: return { "error": "Cannot Generate PDF", "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: 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 XML(request): try: MD5 = request.GET['md5'] TYP = request.GET['type'] m = re.match('^[0-9a-f]{32}$', MD5) if m: if TYP in ['APK', 'ANDZIP']: DB = StaticAnalyzerAndroid.objects.filter(MD5=MD5) if DB.exists(): print "\n[INFO] Fetching data from DB for PDF Report Generation (Android)" context = get_context_from_db_entry(DB) if TYP == 'APK': template = get_template("pdf/static_analysis_pdf.html") else: template = get_template( "pdf/static_analysis_zip_pdf.html") else: return HttpResponse( json.dumps({"report": "Report not Found"}), content_type="application/json; charset=utf-8") elif re.findall('IPA|IOSZIP', TYP): if TYP == 'IPA': DB = StaticAnalyzerIPA.objects.filter(MD5=MD5) if DB.exists(): print "\n[INFO] Fetching data from DB for PDF Report Generation (IOS IPA)" context = { 'title': DB[0].TITLE, 'name': DB[0].APPNAMEX, 'size': DB[0].SIZE, 'md5': DB[0].MD5, 'sha1': DB[0].SHA1, 'sha256': DB[0].SHA256, 'plist': DB[0].INFOPLIST, 'bin_name': DB[0].BINNAME, 'id': DB[0].IDF, 'ver': DB[0].VERSION, 'sdk': DB[0].SDK, 'pltfm': DB[0].PLTFM, 'min': DB[0].MINX, 'bin_anal': DB[0].BIN_ANAL, 'libs': DB[0].LIBS, 'files': python_list(DB[0].FILES), 'file_analysis': DB[0].SFILESX, 'strings': python_list(DB[0].STRINGS), 'permissions': python_list(DB[0].PERMISSIONS) } template = get_template( "pdf/ios_binary_analysis_pdf.html") else: return HttpResponse( json.dumps({"report": "Report not Found"}), content_type="application/json; charset=utf-8") elif TYP == 'IOSZIP': DB = StaticAnalyzerIOSZIP.objects.filter(MD5=MD5) if DB.exists(): print "\n[INFO] Fetching data from DB for PDF Report Generation (IOS ZIP)" context = { 'title': DB[0].TITLE, 'name': DB[0].APPNAMEX, 'size': DB[0].SIZE, 'md5': DB[0].MD5, 'sha1': DB[0].SHA1, 'sha256': DB[0].SHA256, 'plist': DB[0].INFOPLIST, 'bin_name': DB[0].BINNAME, 'id': DB[0].IDF, 'ver': DB[0].VERSION, 'sdk': DB[0].SDK, 'pltfm': DB[0].PLTFM, 'min': DB[0].MINX, 'bin_anal': DB[0].BIN_ANAL, 'libs': DB[0].LIBS, 'files': python_list(DB[0].FILES), 'file_analysis': DB[0].SFILESX, 'api': DB[0].HTML, 'insecure': DB[0].CODEANAL, 'urls': DB[0].URLnFile, 'domains': python_dict(DB[0].DOMAINS), 'emails': DB[0].EmailnFile, 'permissions': python_list(DB[0].PERMISSIONS) } template = get_template( "pdf/ios_source_analysis_pdf.html") else: return HttpResponse( json.dumps({"report": "Report not Found"}), content_type="application/json; charset=utf-8") elif re.findall('APPX', TYP): if TYP == 'APPX': db_entry = StaticAnalyzerWindows.objects.filter( # pylint: disable-msg=E1101 MD5=MD5) if db_entry.exists(): print "\n[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: return HttpResponse( json.dumps({"type": "Type is not Allowed"}), content_type="application/json; charset=utf-8") html = template.render(context) memorandum = etree.Element("memorandum") etree.SubElement( memorandum, "titul" ).text = context.get("title") + " - " + context.get("name") precuinat = etree.SubElement(memorandum, "precuinat") precuinat.set("category", "fileInformation") etree.SubElement(precuinat, "title").text = "File Information" etree.SubElement(precuinat, "nom").text = context.get("name") etree.SubElement(precuinat, "tam").text = context.get("size") etree.SubElement(precuinat, "md5").text = context.get("md5") etree.SubElement(precuinat, "sha1").text = context.get("sha1") etree.SubElement(precuinat, "sha256").text = context.get("sha256") precuinat = etree.SubElement(memorandum, "precuinat") precuinat.set("category", "appInformation") etree.SubElement(precuinat, "title").text = "App Information" etree.SubElement(precuinat, "packagename").text = context.get("packagename") etree.SubElement(precuinat, "mainactivity").text = context.get("mainactivity") etree.SubElement(precuinat, "targetsdk").text = context.get("targetsdk") etree.SubElement(precuinat, "minsdk").text = context.get("minsdk") etree.SubElement(precuinat, "maxsdk").text = context.get("maxsdk") etree.SubElement(precuinat, "androvername").text = context.get("androvername") etree.SubElement(precuinat, "androver").text = context.get("androver") precuinat = etree.SubElement(memorandum, "precuinat") precuinat.set("category", "codeNature") etree.SubElement(precuinat, "title").text = "Code Nature" etree.SubElement(precuinat, "native").text = context.get("native") etree.SubElement(precuinat, "dynamic").text = context.get("dynamic") etree.SubElement(precuinat, "reflection").text = context.get("reflection") etree.SubElement(precuinat, "crypto").text = context.get("crypto") etree.SubElement(precuinat, "obfus").text = context.get("obfus") precuinat = etree.SubElement(memorandum, "precuinat") precuinat.set("category", "certificate") etree.SubElement(precuinat, "title").text = "Certificate" etree.SubElement(precuinat, "certinfo").text = context.get("certinfo") etree.SubElement( precuinat, "issued").text = "Certificate Status: " + context.get("issued") precuinat = etree.SubElement(memorandum, "precuinat") precuinat.set("category", "permissions") etree.SubElement(precuinat, "title").text = "Permissions" dic = context.get("permissions") for perm, desc in dic.items(): etree.SubElement( precuinat, "perm").text = "PERMISSION: " + perm + " " + desc[0] etree.SubElement(precuinat, "info").text = "INFO: " + desc[1] etree.SubElement( precuinat, "description").text = "DESCRIPTION: " + desc[2] precuinat = etree.SubElement(memorandum, "precuinat") precuinat.set("category", "SOLibraryBinaryAnalis") etree.SubElement(precuinat, "title").text = "ANDROID LIBRARY BINARY ANALYSIS" dic = context.get("binary_analysis") dic2 = dic[0] for i, j in dic2.items(): etree.SubElement(precuinat, "key").text = i etree.SubElement(precuinat, "value").text = j precuinat = etree.SubElement(memorandum, "precuinat") precuinat.set("category", "brossableActivities") etree.SubElement(precuinat, "title").text = "Brossable Activities" dic = context.get("browsable_activities") for i, j in dic.items(): etree.SubElement(precuinat, "activity").text = "ACTIVITY " + i etree.SubElement(precuinat, "intent").text = "INTENT " + j precuinat = etree.SubElement(memorandum, "precuinat") precuinat.set("category", "manifestAnalysis") etree.SubElement(precuinat, "title").text = "Manifest Analysis" dic = context.get("manifest") for p in dic: for i, j in p.items(): etree.SubElement(precuinat, "key").text = i etree.SubElement(precuinat, "value").text = j precuinat = etree.SubElement(memorandum, "precuinat") precuinat.set("category", "codeAnalysis") etree.SubElement(precuinat, "title").text = "Code Analysis" etree.SubElement(precuinat, "contenido").text = context.get("dang") precuinat = etree.SubElement(memorandum, "precuinat") precuinat.set("category", "AndroidAPI") etree.SubElement(precuinat, "title").text = "Android API" etree.SubElement(precuinat, "contenido").text = context.get("api") precuinat = etree.SubElement(memorandum, "precuinat") precuinat.set("category", "urls") etree.SubElement(precuinat, "title").text = "URLS" etree.SubElement(precuinat, "contenido").text = context.get("urls") precuinat = etree.SubElement(memorandum, "precuinat") precuinat.set("category", "malwareChecks") etree.SubElement(precuinat, "title").text = "Malware Checks" dic = context.get("domain") precuinat = etree.SubElement(memorandum, "precuinat") precuinat.set("category", "emails") etree.SubElement(precuinat, "title").text = "Emails" etree.SubElement(precuinat, "contenido").text = context.get("emails") precuinat = etree.SubElement(memorandum, "precuinat") precuinat.set("category", "fileAnalysis") etree.SubElement(precuinat, "title").text = "File Analysis" etree.SubElement(precuinat, "contenido").text = context.get("certz") precuinat = etree.SubElement(memorandum, "precuinat") precuinat.set("category", "strings") etree.SubElement(precuinat, "title").text = "Strings" list = context.get("strings") for var in list: etree.SubElement(precuinat, "strings").text = var precuinat = etree.SubElement(memorandum, "precuinat") precuinat.set("category", "activities") etree.SubElement(precuinat, "title").text = "Activities" list = context.get("activities") for act in list: etree.SubElement(precuinat, "activity").text = act precuinat = etree.SubElement(memorandum, "precuinat") precuinat.set("category", "providers") etree.SubElement(precuinat, "title").text = "Providers" list = context.get("providers") for prov in list: etree.SubElement(precuinat, "provider").text = prov precuinat = etree.SubElement(memorandum, "precuinat") precuinat.set("category", "receivers") etree.SubElement(precuinat, "title").text = "Receivers" list = context.get("receivers") for rec in list: etree.SubElement(precuinat, "receiver").text = rec precuinat = etree.SubElement(memorandum, "precuinat") precuinat.set("category", "services") etree.SubElement(precuinat, "title").text = "Services" list = context.get("services") for ser in list: etree.SubElement(precuinat, "service").text = ser precuinat = etree.SubElement(memorandum, "precuinat") precuinat.set("category", "libraries") etree.SubElement(precuinat, "title").text = "Libraries" list = context.get("libraries") for lib in list: etree.SubElement(precuinat, "library").text = lib precuinat = etree.SubElement(memorandum, "precuinat") precuinat.set("category", "files") etree.SubElement(precuinat, "title").text = "Files" list = context.get("files") for f in list: etree.SubElement(precuinat, "file").text = f g = open('./xml/t.xml', 'w') g.write('<?xml version="1.0"?>') # print(etree.tostring(memorandum, xml_declaration=True, encoding = 'iso-8859-1')) g.write(etree.tostring(memorandum)) g.close() g = open('./xml/t.xml', 'r') response = HttpResponse(g, content_type='application/force-download') response['Content-Disposition'] = 'attachment; filename=t.xml' g.close() return response else: return HttpResponse(json.dumps({"md5": "Invalid MD5"}), content_type="application/json; charset=utf-8") except: PrintException("[ERROR] XML Report Generation Error") return HttpResponseRedirect('/error/')
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(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_dir'], app_dic['tools_dir'], '', True) # Get icon res_path = os.path.join(app_dic['app_dir'], 'res') app_dic['icon_hidden'] = True app_dic[ 'icon_found'] = False # Even if the icon is hidden, try to guess it by the default paths app_dic['icon_path'] = '' if os.path.exists( res_path ): # TODO: Check for possible different names for resource folder? icon_dic = get_icon(app_dic['app_path'], res_path, app_dic['tools_dir']) 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'], "apk") bin_an_buff += res_analysis(app_dic['app_dir'], "apk") cert_dic = cert_info(app_dic['app_dir'], app_dic['tools_dir']) apkid_results = apkid_analysis(app_dic['app_dir']) 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(app_dic['app_file'], app_dic['app_dir'], app_dic['tools_dir']) app_dic['zipped'] = '&type=apk' 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, ) 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, ) 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, ) context['dynamic_analysis_done'] = os.path.exists( os.path.join(app_dic['app_dir'], 'logcat.txt')) 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'] = '' 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/') 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)