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)
Esempio n. 2
0
def static_analyzer_ios(request, api=False):
    """Module that performs iOS IPA/ZIP Static Analysis."""
    try:
        logger.info('iOS Static Analysis Started')
        if api:
            file_type = request.POST['scan_type']
            checksum = request.POST['hash']
            rescan = str(request.POST.get('re_scan', 0))
            filename = request.POST['file_name']
        else:
            file_type = request.GET['type']
            checksum = request.GET['checksum']
            rescan = str(request.GET.get('rescan', 0))
            filename = request.GET['name']

        md5_match = re.match('^[0-9a-f]{32}$', checksum)
        if ((md5_match) and (filename.lower().endswith('.ipa')
                             or filename.lower().endswith('.zip'))
                and (file_type in ['ipa', 'ios'])):
            app_dict = {}
            app_dict['directory'] = Path(settings.BASE_DIR)  # BASE DIR
            app_dict['file_name'] = filename  # APP ORGINAL NAME
            app_dict['md5_hash'] = checksum  # MD5
            app_dict['app_dir'] = Path(settings.UPLD_DIR) / checksum
            tools_dir = app_dict[
                'directory'] / 'StaticAnalyzer' / 'tools' / 'ios'
            tools_dir = tools_dir.as_posix()
            if file_type == 'ipa':
                app_dict[
                    'app_file'] = app_dict['md5_hash'] + '.ipa'  # NEW FILENAME
                app_dict[
                    'app_path'] = app_dict['app_dir'] / app_dict['app_file']
                app_dict['app_path'] = app_dict['app_path'].as_posix()
                # DB
                ipa_db = StaticAnalyzerIOS.objects.filter(
                    MD5=app_dict['md5_hash'])
                if ipa_db.exists() and rescan == '0':
                    context = get_context_from_db_entry(ipa_db)
                else:

                    logger.info('iOS Binary (IPA) Analysis Started')
                    app_dict['bin_dir'] = app_dict['app_dir'] / 'Payload'
                    app_dict['bin_dir'] = app_dict['bin_dir'].as_posix() + '/'
                    app_dict['app_dir'] = app_dict['app_dir'].as_posix() + '/'
                    app_dict['size'] = str(file_size(
                        app_dict['app_path'])) + 'MB'  # FILE SIZE
                    app_dict['sha1'], app_dict['sha256'] = hash_gen(
                        app_dict['app_path'])  # SHA1 & SHA256 HASHES
                    logger.info('Extracting IPA')
                    # EXTRACT IPA
                    unzip(app_dict['app_path'], app_dict['app_dir'])
                    # Get Files, normalize + to x,
                    # and convert binary plist -> xml
                    all_files = ios_list_files(app_dict['bin_dir'],
                                               app_dict['md5_hash'], True,
                                               'ipa')
                    infoplist_dict = plist_analysis(app_dict['bin_dir'], False)
                    app_dict['appstore'] = app_search(infoplist_dict.get('id'))
                    bin_analysis_dict = binary_analysis(
                        app_dict['bin_dir'], tools_dir, app_dict['app_dir'],
                        infoplist_dict.get('bin'))
                    # Get Icon
                    app_dict['icon_found'] = get_icon(
                        app_dict['md5_hash'], app_dict['bin_dir'],
                        infoplist_dict.get('bin'))
                    # IPA URL and Email Extract
                    recon = extract_urls_n_email(app_dict['bin_dir'],
                                                 all_files['files_long'],
                                                 bin_analysis_dict['strings'])
                    code_dict = {
                        'api': {},
                        'code_anal': {},
                        'urlnfile': recon['urlnfile'],
                        'domains': recon['domains'],
                        'emailnfile': recon['emailnfile'],
                        'firebase': firebase_analysis(recon['urls_list']),
                    }
                    # Saving to DB
                    logger.info('Connecting to DB')
                    if rescan == '1':
                        logger.info('Updating Database...')
                        save_or_update('update', app_dict, infoplist_dict,
                                       code_dict, bin_analysis_dict, all_files)
                        update_scan_timestamp(app_dict['md5_hash'])
                    elif rescan == '0':
                        logger.info('Saving to Database')
                        save_or_update('save', app_dict, infoplist_dict,
                                       code_dict, bin_analysis_dict, all_files)
                    context = get_context_from_analysis(
                        app_dict, infoplist_dict, code_dict, bin_analysis_dict,
                        all_files)
                context['virus_total'] = None
                if settings.VT_ENABLED:
                    vt = VirusTotal.VirusTotal()
                    context['virus_total'] = vt.get_result(
                        app_dict['app_path'], app_dict['md5_hash'])
                context['average_cvss'], context['security_score'] = score(
                    context['binary_analysis'])
                template = 'static_analysis/ios_binary_analysis.html'
                if api:
                    return context
                else:
                    return render(request, template, context)
            elif file_type == 'ios':
                ios_zip_db = StaticAnalyzerIOS.objects.filter(
                    MD5=app_dict['md5_hash'])
                if ios_zip_db.exists() and rescan == '0':
                    context = get_context_from_db_entry(ios_zip_db)
                else:
                    logger.info('iOS Source Code Analysis Started')
                    app_dict['app_file'] = app_dict[
                        'md5_hash'] + '.zip'  # NEW FILENAME
                    app_dict['app_path'] = app_dict['app_dir'] / app_dict[
                        'app_file']
                    app_dict['app_path'] = app_dict['app_path'].as_posix()
                    app_dict['app_dir'] = app_dict['app_dir'].as_posix() + '/'
                    # ANALYSIS BEGINS - Already Unzipped
                    logger.info('ZIP Already Extracted')
                    app_dict['size'] = str(file_size(
                        app_dict['app_path'])) + 'MB'  # FILE SIZE
                    app_dict['sha1'], app_dict['sha256'] = hash_gen(
                        app_dict['app_path'])  # SHA1 & SHA256 HASHES
                    all_files = ios_list_files(app_dict['app_dir'],
                                               app_dict['md5_hash'], False,
                                               'ios')
                    infoplist_dict = plist_analysis(app_dict['app_dir'], True)
                    app_dict['appstore'] = app_search(infoplist_dict.get('id'))
                    code_analysis_dic = ios_source_analysis(
                        app_dict['app_dir'])
                    # Get App Icon
                    app_dict['icon_found'] = get_icon_source(
                        app_dict['md5_hash'], app_dict['app_dir'])
                    # Firebase DB Check
                    code_analysis_dic['firebase'] = firebase_analysis(
                        list(set(code_analysis_dic['urls_list'])))
                    fake_bin_dict = {
                        'bin_type': code_analysis_dic['source_type'],
                        'macho': {},
                        'bin_res': [],
                        'libs': [],
                        'strings': [],
                    }
                    # Saving to DB
                    logger.info('Connecting to DB')
                    if rescan == '1':
                        logger.info('Updating Database...')
                        save_or_update('update', app_dict, infoplist_dict,
                                       code_analysis_dic, fake_bin_dict,
                                       all_files)
                        update_scan_timestamp(app_dict['md5_hash'])
                    elif rescan == '0':
                        logger.info('Saving to Database')
                        save_or_update('save', app_dict, infoplist_dict,
                                       code_analysis_dic, fake_bin_dict,
                                       all_files)
                    context = get_context_from_analysis(
                        app_dict, infoplist_dict, code_analysis_dic,
                        fake_bin_dict, all_files)
                context['average_cvss'], context['security_score'] = score(
                    context['code_analysis'])
                template = 'static_analysis/ios_source_analysis.html'
                if api:
                    return context
                else:
                    return render(request, template, context)
            else:
                msg = 'File Type not supported!'
                if api:
                    return print_n_send_error_response(request, msg, True)
                else:
                    return print_n_send_error_response(request, msg, False)
        else:
            msg = 'Hash match failed or Invalid file extension or file type'
            if api:
                return print_n_send_error_response(request, msg, True)
            else:
                return print_n_send_error_response(request, msg, False)
    except Exception as exp:
        logger.exception('Error Perfroming Static Analysis')
        msg = str(exp)
        exp_doc = exp.__doc__
        if api:
            return print_n_send_error_response(request, msg, True, exp_doc)
        else:
            return print_n_send_error_response(request, msg, False, exp_doc)
def static_analyzer_ios(request, api=False):
    """Module that performs iOS IPA/ZIP Static Analysis."""
    try:
        logger.info('iOS Static Analysis Started')
        if api:
            file_type = request.POST['scan_type']
            checksum = request.POST['hash']
            rescan = str(request.POST.get('re_scan', 0))
            filename = request.POST['file_name']
        else:
            file_type = request.GET['type']
            checksum = request.GET['checksum']
            rescan = str(request.GET.get('rescan', 0))
            filename = request.GET['name']

        md5_match = re.match('^[0-9a-f]{32}$', checksum)
        if ((md5_match) and (filename.lower().endswith('.ipa')
                             or filename.lower().endswith('.zip'))
                and (file_type in ['ipa', 'ios'])):
            app_dict = {}
            app_dict['directory'] = settings.BASE_DIR  # BASE DIR
            app_dict['file_name'] = filename  # APP ORGINAL NAME
            app_dict['md5_hash'] = checksum  # MD5
            app_dict['app_dir'] = os.path.join(
                settings.UPLD_DIR, app_dict['md5_hash'] + '/')  # APP DIRECTORY
            tools_dir = os.path.join(app_dict['directory'],
                                     'StaticAnalyzer/tools/mac/')
            if file_type == 'ipa':
                # DB
                ipa_db = StaticAnalyzerIPA.objects.filter(
                    MD5=app_dict['md5_hash'])
                if ipa_db.exists() and rescan == '0':
                    context = get_context_from_db_entry_ipa(ipa_db)
                else:
                    logger.info('iOS Binary (IPA) Analysis Started')
                    app_dict['app_file'] = app_dict[
                        'md5_hash'] + '.ipa'  # NEW FILENAME
                    app_dict['app_path'] = (app_dict['app_dir'] +
                                            app_dict['app_file'])
                    app_dict['bin_dir'] = os.path.join(app_dict['app_dir'],
                                                       'Payload/')
                    app_dict['size'] = str(file_size(
                        app_dict['app_path'])) + 'MB'  # FILE SIZE
                    app_dict['sha1'], app_dict['sha256'] = hash_gen(
                        app_dict['app_path'])  # SHA1 & SHA256 HASHES
                    logger.info('Extracting IPA')
                    # EXTRACT IPA
                    unzip(app_dict['app_path'], app_dict['app_dir'])
                    # Get Files, normalize + to x,
                    # and convert binary plist -> xml
                    files, sfiles = ios_list_files(app_dict['bin_dir'],
                                                   app_dict['md5_hash'], True,
                                                   'ipa')
                    infoplist_dict = plist_analysis(app_dict['bin_dir'], False)
                    app_dict['appstore'] = app_search(infoplist_dict.get('id'))
                    bin_analysis_dict = binary_analysis(
                        app_dict['bin_dir'], tools_dir, app_dict['app_dir'],
                        infoplist_dict.get('bin'))
                    # Saving to DB
                    logger.info('Connecting to DB')
                    if rescan == '1':
                        logger.info('Updating Database...')
                        update_db_entry_ipa(app_dict, infoplist_dict,
                                            bin_analysis_dict, files, sfiles)
                        update_scan_timestamp(app_dict['md5_hash'])
                    elif rescan == '0':
                        logger.info('Saving to Database')
                        create_db_entry_ipa(app_dict, infoplist_dict,
                                            bin_analysis_dict, files, sfiles)
                    context = get_context_from_analysis_ipa(
                        app_dict, infoplist_dict, bin_analysis_dict, files,
                        sfiles)

                context['VT_RESULT'] = None
                if settings.VT_ENABLED:
                    vt = VirusTotal.VirusTotal()
                    context['VT_RESULT'] = vt.get_result(
                        os.path.join(app_dict['app_dir'], app_dict['md5_hash'])
                        + '.ipa', app_dict['md5_hash'])
                context['average_cvss'], context['security_score'] = score(
                    context['bin_anal'])
                template = 'static_analysis/ios_binary_analysis.html'
                if api:
                    return context
                else:
                    return render(request, template, context)
            elif file_type == 'ios':
                ios_zip_db = StaticAnalyzerIOSZIP.objects.filter(
                    MD5=app_dict['md5_hash'])
                if ios_zip_db.exists() and rescan == '0':
                    context = get_context_from_db_entry_ios(ios_zip_db)
                else:
                    logger.info('iOS Source Code Analysis Started')
                    app_dict['app_file'] = app_dict[
                        'md5_hash'] + '.zip'  # NEW FILENAME
                    app_dict['app_path'] = (app_dict['app_dir'] +
                                            app_dict['app_file'])
                    # ANALYSIS BEGINS - Already Unzipped
                    logger.info('ZIP Already Extracted')
                    app_dict['size'] = str(file_size(
                        app_dict['app_path'])) + 'MB'  # FILE SIZE
                    app_dict['sha1'], app_dict['sha256'] = hash_gen(
                        app_dict['app_path'])  # SHA1 & SHA256 HASHES
                    files, sfiles = ios_list_files(app_dict['app_dir'],
                                                   app_dict['md5_hash'], False,
                                                   'ios')
                    infoplist_dict = plist_analysis(app_dict['app_dir'], True)
                    app_dict['appstore'] = app_search(infoplist_dict.get('id'))
                    code_analysis_dic = ios_source_analysis(
                        app_dict['app_dir'])
                    # Firebase DB Check
                    code_analysis_dic['firebase'] = firebase_analysis(
                        list(set(code_analysis_dic['urls_list'])))
                    # Saving to DB
                    logger.info('Connecting to DB')
                    if rescan == '1':
                        logger.info('Updating Database...')
                        update_db_entry_ios(app_dict, infoplist_dict,
                                            code_analysis_dic, files, sfiles)
                        update_scan_timestamp(app_dict['md5_hash'])
                    elif rescan == '0':
                        logger.info('Saving to Database')
                        create_db_entry_ios(app_dict, infoplist_dict,
                                            code_analysis_dic, files, sfiles)
                    context = get_context_from_analysis_ios(
                        app_dict, infoplist_dict, code_analysis_dic, files,
                        sfiles)
                context['average_cvss'], context['security_score'] = score(
                    context['insecure'])
                template = 'static_analysis/ios_source_analysis.html'
                if api:
                    return context
                else:
                    return render(request, template, context)
            else:
                msg = 'File Type not supported!'
                if api:
                    return print_n_send_error_response(request, msg, True)
                else:
                    return print_n_send_error_response(request, msg, False)
        else:
            msg = 'Hash match failed or Invalid file extension or file type'
            if api:
                return print_n_send_error_response(request, msg, True)
            else:
                return print_n_send_error_response(request, msg, False)
    except Exception as exp:
        logger.exception('Error Perfroming Static Analysis')
        msg = str(exp)
        exp_doc = exp.__doc__
        if api:
            return print_n_send_error_response(request, msg, True, exp_doc)
        else:
            return print_n_send_error_response(request, msg, False, exp_doc)
Esempio n. 4
0
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)
Esempio n. 5
0
def pdf(request, api=False, jsonres=False):
    try:
        if api:
            checksum = request.POST['hash']
        else:
            checksum = request.GET['md5']
        hash_match = re.match('^[0-9a-f]{32}$', checksum)
        if not hash_match:
            if api:
                return {'error': 'Invalid scan hash'}
            else:
                return HttpResponse(json.dumps({'md5': 'Invalid scan hash'}),
                                    content_type=ctype,
                                    status=500)
        # Do Lookups
        android_static_db = StaticAnalyzerAndroid.objects.filter(MD5=checksum)
        ios_static_db = StaticAnalyzerIOS.objects.filter(MD5=checksum)
        win_static_db = StaticAnalyzerWindows.objects.filter(MD5=checksum)

        if android_static_db.exists():
            context, template = handle_pdf_android(android_static_db)
        elif ios_static_db.exists():
            context, template = handle_pdf_ios(ios_static_db)
        elif win_static_db.exists():
            context, template = handle_pdf_win(win_static_db)
        else:
            if api:
                return {'report': 'Report not Found'}
            else:
                return HttpResponse(json.dumps({'report': 'Report not Found'}),
                                    content_type=ctype,
                                    status=500)
        # Do VT Scan only on binaries
        context['virus_total'] = None
        ext = os.path.splitext(context['file_name'].lower())[1]
        if settings.VT_ENABLED and ext != '.zip':
            app_bin = os.path.join(settings.UPLD_DIR, checksum + '/',
                                   checksum + ext)
            vt = VirusTotal.VirusTotal()
            context['virus_total'] = vt.get_result(app_bin, checksum)
        # Get Local Base URL
        proto = 'file://'
        host_os = 'nix'
        if platform.system() == 'Windows':
            proto = 'file:///'
            host_os = 'windows'
        context['base_url'] = proto + settings.BASE_DIR
        context['dwd_dir'] = proto + settings.DWD_DIR
        context['host_os'] = host_os
        try:
            if api and jsonres:
                return {'report_dat': context}
            else:
                options = {
                    'page-size': 'Letter',
                    'quiet': '',
                    'no-collate': '',
                    'margin-top': '0.50in',
                    'margin-right': '0.50in',
                    'margin-bottom': '0.50in',
                    'margin-left': '0.50in',
                    'encoding': 'UTF-8',
                    'custom-header': [
                        ('Accept-Encoding', 'gzip'),
                    ],
                    'no-outline': None,
                }
                # Added proxy support to wkhtmltopdf
                proxies, _ = upstream_proxy('https')
                if proxies['https']:
                    options['proxy'] = proxies['https']
                html = template.render(context)
                pdf_dat = pdfkit.from_string(html, False, options=options)
                if api:
                    return {'pdf_dat': pdf_dat}
                return HttpResponse(pdf_dat, content_type='application/pdf')
        except Exception as exp:
            logger.exception('Error Generating PDF Report')
            if api:
                return {
                    'error': 'Cannot Generate PDF/JSON',
                    'err_details': str(exp)
                }
            else:
                return HttpResponse(json.dumps({
                    'pdf_error': 'Cannot Generate PDF',
                    'err_details': str(exp)
                }),
                                    content_type=ctype,
                                    status=500)
    except Exception as exp:
        logger.exception('Error Generating PDF Report')
        msg = str(exp)
        exp = exp.__doc__
        if api:
            return print_n_send_error_response(request, msg, True, exp)
        else:
            return print_n_send_error_response(request, msg, False, exp)
def pdf(request, api=False, jsonres=False):
    try:
        if api:
            checksum = request.POST['hash']
            scan_type = request.POST['scan_type']
        else:
            checksum = request.GET['md5']
            scan_type = request.GET['type']
        hash_match = re.match('^[0-9a-f]{32}$', checksum)
        if hash_match:
            if scan_type.lower() in ['apk', 'andzip']:
                static_db = StaticAnalyzerAndroid.objects.filter(MD5=checksum)
                if static_db.exists():
                    logger.info('Fetching data from DB for '
                                'PDF Report Generation (Android)')
                    context = adb(static_db)
                    context['average_cvss'], context['security_score'] = score(
                        context['code_analysis'])
                    if scan_type.lower() == 'apk':
                        template = get_template(
                            'pdf/android_binary_analysis.pdf.html')
                    else:
                        template = get_template(
                            'pdf/android_source_analysis_pdf.html')
                else:
                    if api:
                        return {'report': 'Report not Found'}
                    else:
                        return HttpResponse(
                            json.dumps({'report': 'Report not Found'}),
                            content_type='application/json; charset=utf-8',
                            status=500)
            elif scan_type.lower() in ['ipa', 'ioszip']:
                if scan_type.lower() == 'ipa':
                    static_db = StaticAnalyzerIOS.objects.filter(MD5=checksum)
                    if static_db.exists():
                        logger.info('Fetching data from DB for '
                                    'PDF Report Generation (IOS IPA)')
                        context = idb(static_db)
                        context['average_cvss'], context[
                            'security_score'] = score(
                                context['binary_analysis'])
                        template = get_template(
                            'pdf/ios_binary_analysis_pdf.html')
                    else:
                        if api:
                            return {'report': 'Report not Found'}
                        else:
                            return HttpResponse(
                                json.dumps({'report': 'Report not Found'}),
                                content_type='application/json; charset=utf-8',
                                status=500)
                elif scan_type.lower() == 'ioszip':
                    static_db = StaticAnalyzerIOS.objects.filter(MD5=checksum)
                    if static_db.exists():
                        logger.info('Fetching data from DB for '
                                    'PDF Report Generation (IOS ZIP)')
                        context = idb(static_db)
                        context['average_cvss'], context[
                            'security_score'] = score(context['code_analysis'])
                        template = get_template(
                            'pdf/ios_source_analysis_pdf.html')
                    else:
                        if api:
                            return {'report': 'Report not Found'}
                        else:
                            return HttpResponse(
                                json.dumps({'report': 'Report not Found'}),
                                content_type='application/json; charset=utf-8',
                                status=500)
            elif 'appx' == scan_type.lower():
                if scan_type.lower() == 'appx':
                    db_entry = StaticAnalyzerWindows.objects.filter(
                        MD5=checksum, )
                    if db_entry.exists():
                        logger.info('Fetching data from DB for '
                                    'PDF Report Generation (APPX)')
                        context = wdb(db_entry)
                        template = get_template(
                            'pdf/windows_binary_analysis_pdf.html')
            else:
                if api:
                    return {'scan_type': 'Type is not Allowed'}
                else:
                    return HttpResponse(
                        json.dumps({'type': 'Type is not Allowed'}),
                        content_type='application/json; charset=utf-8',
                        status=500)

            context['virus_total'] = None
            if settings.VT_ENABLED:
                app_dir = os.path.join(settings.UPLD_DIR, checksum + '/')
                vt = VirusTotal.VirusTotal()
                if 'zip' in scan_type.lower():
                    context['virus_total'] = None
                else:
                    context['virus_total'] = vt.get_result(
                        os.path.join(app_dir, checksum) + '.' +
                        scan_type.lower(), checksum)
            try:
                if api and jsonres:
                    return {'report_dat': context}
                else:
                    options = {
                        'page-size': 'A4',
                        'quiet': '',
                        'no-collate': '',
                        'margin-top': '0.50in',
                        'margin-right': '0.50in',
                        'margin-bottom': '0.50in',
                        'margin-left': '0.50in',
                        'encoding': 'UTF-8',
                        'custom-header': [
                            ('Accept-Encoding', 'gzip'),
                        ],
                        'no-outline': None,
                    }
                    html = template.render(context)
                    pdf_dat = pdfkit.from_string(html, False, options=options)
                    if api:
                        return {'pdf_dat': pdf_dat}
                    return HttpResponse(pdf_dat,
                                        content_type='application/pdf')
            except Exception as exp:
                logger.exception('Error Generating PDF Report')
                if api:
                    return {
                        'error': 'Cannot Generate PDF/JSON',
                        'err_details': str(exp)
                    }
                else:
                    return HttpResponse(
                        json.dumps({
                            'pdf_error': 'Cannot Generate PDF',
                            'err_details': str(exp)
                        }),
                        content_type='application/json; charset=utf-8',
                        status=500)

        else:
            if api:
                return {'error': 'Invalid scan hash'}
            else:
                return HttpResponse(
                    json.dumps({'md5': 'Invalid MD5'}),
                    content_type='application/json; charset=utf-8',
                    status=500)
    except Exception as exp:
        logger.exception('Error Generating PDF Report')
        msg = str(exp)
        exp = exp.__doc__
        if api:
            return print_n_send_error_response(request, msg, True, exp)
        else:
            return print_n_send_error_response(request, msg, False, exp)
Esempio n. 7
0
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)
Esempio n. 8
0
def staticanalyzer_windows(request, api=False):
    """Analyse a windows app."""
    try:
        # Input validation
        logger.info('Windows Static Analysis Started')
        app_dic = {}  # Dict to store the binary attributes
        if api:
            typ = request.POST['scan_type']
            rescan = str(request.POST.get('re_scan', 0))
            checksum = request.POST['hash']
            filename = request.POST['file_name']
        else:
            typ = request.GET['type']
            rescan = str(request.GET.get('rescan', 0))
            checksum = request.GET['checksum']
            filename = request.GET['name']
        md5_regex = re.match('^[0-9a-f]{32}$', checksum)
        if (md5_regex) and (typ in ['appx']):
            app_dic['app_name'] = filename  # APP ORGINAL NAME
            app_dic['md5'] = checksum
            app_dic['app_dir'] = os.path.join(settings.UPLD_DIR,
                                              app_dic['md5'] + '/')
            app_dic['tools_dir'] = os.path.join(
                settings.BASE_DIR, 'StaticAnalyzer/tools/windows/')
            if typ == 'appx':
                # DB
                db_entry = StaticAnalyzerWindows.objects.filter(
                    MD5=app_dic['md5'], )
                if db_entry.exists() and rescan == '0':
                    logger.info('Analysis is already Done.'
                                ' Fetching data from the DB...')
                    context = get_context_from_db_entry(db_entry)
                else:
                    logger.info('Windows Binary Analysis Started')
                    app_dic['app_path'] = os.path.join(
                        app_dic['app_dir'], app_dic['md5'] + '.appx')
                    # ANALYSIS BEGINS
                    app_dic['size'] = str(file_size(
                        app_dic['app_path'])) + 'MB'
                    # Generate hashes
                    app_dic['sha1'], app_dic['sha256'] = hash_gen(
                        app_dic['app_path'])
                    # EXTRACT APPX
                    logger.info('Extracting APPX')
                    app_dic['files'] = unzip(app_dic['app_path'],
                                             app_dic['app_dir'])
                    xml_dic = _parse_xml(app_dic['app_dir'])
                    bin_an_dic = _binary_analysis(app_dic)
                    # Saving to db
                    logger.info('Connecting to DB')
                    if rescan == '1':
                        logger.info('Updating Database...')
                        save_or_update('update', app_dic, xml_dic, bin_an_dic)
                        update_scan_timestamp(app_dic['md5'])
                    elif rescan == '0':
                        logger.info('Saving to Database')
                        save_or_update('save', app_dic, xml_dic, bin_an_dic)
                    context = get_context_from_analysis(
                        app_dic, xml_dic, bin_an_dic)
                context['virus_total'] = None
                if settings.VT_ENABLED:
                    vt = VirusTotal.VirusTotal()
                    context['virus_total'] = vt.get_result(
                        os.path.join(app_dic['app_dir'], app_dic['md5']) +
                        '.appx', app_dic['md5'])
                template = 'static_analysis/windows_binary_analysis.html'
                if api:
                    return context
                else:
                    return render(request, template, context)
            else:
                msg = 'File type not supported'
                if api:
                    return print_n_send_error_response(request, msg, True)
                else:
                    return print_n_send_error_response(request, msg, False)
        else:
            msg = 'Hash match failed or Invalid file extension'
            if api:
                return print_n_send_error_response(request, msg, True)
            else:
                return print_n_send_error_response(request, msg, False)
    except Exception as exception:
        logger.exception('Error Performing Static Analysis')
        msg = str(exception)
        exp_doc = exception.__doc__
        if api:
            return print_n_send_error_response(request, msg, True, exp_doc)
        else:
            return print_n_send_error_response(request, msg, False, exp_doc)
Esempio n. 9
0
def pdf(request, api=False, jsonres=False):
    try:
        if api:
            checksum = request.POST['hash']
        else:
            checksum = request.GET['md5']
        hash_match = re.match('^[0-9a-f]{32}$', checksum)
        if not hash_match:
            if api:
                return {'error': 'Invalid scan hash'}
            else:
                return HttpResponse(json.dumps({'md5': 'Invalid scan hash'}),
                                    content_type=ctype,
                                    status=500)
        # Do Lookups
        android_static_db = StaticAnalyzerAndroid.objects.filter(MD5=checksum)
        ios_static_db = StaticAnalyzerIOS.objects.filter(MD5=checksum)
        win_static_db = StaticAnalyzerWindows.objects.filter(MD5=checksum)

        if android_static_db.exists():
            key = settings.MODEL_K % ('StaticAnalyzerAndroid', checksum)
            context, template = handle_pdf_android(android_static_db, key)
        elif ios_static_db.exists():
            context, template = handle_pdf_ios(ios_static_db)
        elif win_static_db.exists():
            context, template = handle_pdf_win(win_static_db)
        else:
            if api:
                return {'report': 'Report not Found'}
            else:
                return HttpResponse(json.dumps({'report': 'Report not Found'}),
                                    content_type=ctype,
                                    status=500)
        # Do VT Scan only on binaries
        context['virus_total'] = None
        ext = os.path.splitext(context['file_name'].lower())[1]
        if settings.VT_ENABLED and ext != '.zip':
            app_bin = os.path.join(settings.UPLD_DIR, checksum + '/',
                                   checksum + ext)
            vt = VirusTotal.VirusTotal()
            context['virus_total'] = vt.get_result(app_bin, checksum)
        # Get Local Base URL
        proto = 'file://'
        host_os = 'nix'
        if platform.system() == 'Windows':
            proto = 'file:///'
            host_os = 'windows'
        context['base_url'] = proto + settings.BASE_DIR
        context['dwd_dir'] = proto + settings.DWD_DIR
        context['host_os'] = host_os
        # 增加:返回时间
        time = RecentScansDB.objects.get(MD5=checksum).TIMESTAMP
        context['time'] = time
        # 增加:证书subject和issuer提取
        certificate_info = context['certificate_analysis']['certificate_info']
        subject = re.search(r'Subject:.*',
                            certificate_info).group().split(':')[1]
        issuer = re.search(r'Issuer:.*',
                           certificate_info).group().split(':')[1]
        context['cer_subject'] = subject
        context['cer_issuer'] = issuer
        # 增加:permmision排序
        perm_dict_items = context['permissions'].items()
        sorted_perm = sorted(perm_dict_items, key=lambda x: x[1]['status'])
        context['sorted_perm'] = sorted_perm
        #测试url
        context['test_url'] = [
            {
                "urls": [
                    "http://192.168.1.201:12345/ad_monitor/uploadReceiver.php?os=android&platform=domob"
                ],
                "path":
                "cn/domob/android/ads/C0027o.java",
                "results": [{
                    "phones": ["18337258710", "15160578228"],
                    "cards": [],
                    "passports": ["E16728736"],
                    "gps_lng_lat": [(78.356287, 120.834628)],
                    "sources":
                    "http://192.168.1.201:12345/ad_monitor/uploadReceiver.php?os=android&platform=domob"
                }]
            },
            {
                "urls": ["http://www.google.com/loc/json"],
                "path":
                "cn/domob/android/ads/C0029q.java",
                "results": [{
                    "phones": [],
                    "cards": [],
                    "passports": [],
                    "gps_lng_lat": [],
                    "sources": ""
                }]
            },
            {
                "urls": ["http://r.domob.cn/a/"],
                "path":
                "cn/domob/android/ads/C0032t.java",
                "results": [{
                    "phones": [],
                    "cards": [],
                    "passports": [],
                    "gps_lng_lat": [],
                    "sources": ""
                }]
            },
            {
                "urls":
                ["http://e.domob.cn/event_report", "http://r.domob.cn/a/"],
                "path":
                "cn/domob/android/ads/C0017e.java",
                "results": [{
                    "phones": ["18337258710", "15160578228"],
                    "cards": [],
                    "passports": ["E16728736"],
                    "gps_lng_lat": [(78.356287, 120.834628)],
                    "sources": "http://e.domob.cn/event_report"
                }]
            },
            {
                "urls": ["http://r.domob.cn/a/"],
                "path":
                "cn/domob/android/ads/C0022j.java",
                "results": [{
                    "phones": ["18337258710", "15160578228"],
                    "cards": [],
                    "passports": ["E16233236"],
                    "gps_lng_lat": [(78.356287, 120.834628)],
                    "sources": "http://r.domob.cn/a/"
                }]
            },
        ]
        try:
            if api and jsonres:
                return {'report_dat': context}
            else:
                options = {
                    'page-size': 'A4',
                    'quiet': '',
                    'no-collate': '',
                    'margin-top': '15mm',
                    'margin-right': '10mm',
                    'margin-bottom': '15mm',
                    'margin-left': '10mm',
                    'encoding': 'UTF-8',
                    'header-line': '',
                    # 页脚与正文之间的距离(默认为零)
                    'header-spacing': 2,
                    'footer-spacing': 2,
                    # 设置页码
                    'footer-center': '第 [page] 页',
                    # 'custom-header': [
                    #     ('Accept-Encoding', 'gzip'),
                    # ],

                    # 'dump-outline':'toc.xml',
                    # 'dump-default-toc-xsl': 'my.xsl',
                    'outline': '',
                    # 大纲的深度
                    'outline-depth': '2',
                }
                xsl_path = os.path.join(settings.BASE_DIR, "templates/my.xsl"),
                toc = {
                    # 'toc-header-text':'目录',
                    'toc-level-indentation': '100',
                    'disable-dotted-lines': '',
                    'xsl-style-sheet': xsl_path,
                }
                # cover = os.path.join(settings.BASE_DIR, 'templates/cover.html')
                html = template.render(context)
                # Added proxy support to wkhtmltopdf
                proxies, _ = upstream_proxy('https')
                if proxies['https']:
                    options['proxy'] = proxies['https']
                # pdf_dat = pdfkit.from_string(html,False,options,toc,cover,cover_first=True)
                pdf_dat = pdfkit.from_string(html, False, options, toc)
                if api:
                    return {'pdf_dat': pdf_dat}
                return HttpResponse(pdf_dat, content_type='application/pdf')
        except Exception as exp:
            logger.exception('Error Generating PDF Report')
            if api:
                return {
                    'error': 'Cannot Generate PDF/JSON',
                    'err_details': str(exp)
                }
            else:
                return HttpResponse(json.dumps({
                    'pdf_error': 'Cannot Generate PDF',
                    'err_details': str(exp)
                }),
                                    content_type=ctype,
                                    status=500)
    except Exception as exp:
        logger.exception('Error Generating PDF Report')
        msg = str(exp)
        exp = exp.__doc__
        if api:
            return print_n_send_error_response(request, msg, True, exp)
        else:
            return print_n_send_error_response(request, msg, False, exp)
def pdf(request, api=False, jsonres=False):
    try:
        if api:
            checksum = request.POST['hash']
        else:
            checksum = request.GET['md5']
        hash_match = re.match('^[0-9a-f]{32}$', checksum)
        if hash_match:
            android_static_db = StaticAnalyzerAndroid.objects.filter(
                MD5=checksum)
            ios_static_db = StaticAnalyzerIOS.objects.filter(MD5=checksum)
            win_static_db = StaticAnalyzerWindows.objects.filter(MD5=checksum)

            if android_static_db.exists():
                context, template = handle_pdf_android(android_static_db)
            elif ios_static_db.exists():
                context, template = handle_pdf_ios(ios_static_db)
            elif win_static_db.exists():
                context, template = handle_pdf_win(win_static_db)
            else:
                if api:
                    return {'report': 'Report not Found'}
                else:
                    return HttpResponse(
                        json.dumps({'report': 'Report not Found'}),
                        content_type='application/json; charset=utf-8',
                        status=500)
            context['virus_total'] = None
            if settings.VT_ENABLED:
                file_extension = os.path.splitext(
                    context['file_name'].lower())[1]
                app_dir = os.path.join(settings.UPLD_DIR, checksum + '/')
                vt = VirusTotal.VirusTotal()
                if file_extension.lower() == '.zip':
                    context['virus_total'] = None
                else:
                    context['virus_total'] = vt.get_result(
                        os.path.join(app_dir, checksum) +
                        file_extension.lower(), checksum)
            try:
                if api and jsonres:
                    return {'report_dat': context}
                else:
                    options = {
                        'page-size': 'A4',
                        'quiet': '',
                        'no-collate': '',
                        'margin-top': '0.50in',
                        'margin-right': '0.50in',
                        'margin-bottom': '0.50in',
                        'margin-left': '0.50in',
                        'encoding': 'UTF-8',
                        'custom-header': [
                            ('Accept-Encoding', 'gzip'),
                        ],
                        'no-outline': None,
                    }
                    html = template.render(context)
                    pdf_dat = pdfkit.from_string(html, False, options=options)
                    if api:
                        return {'pdf_dat': pdf_dat}
                    return HttpResponse(pdf_dat,
                                        content_type='application/pdf')
            except Exception as exp:
                logger.exception('Error Generating PDF Report')
                if api:
                    return {
                        'error': 'Cannot Generate PDF/JSON',
                        'err_details': str(exp)
                    }
                else:
                    return HttpResponse(
                        json.dumps({
                            'pdf_error': 'Cannot Generate PDF',
                            'err_details': str(exp)
                        }),
                        content_type='application/json; charset=utf-8',
                        status=500)

        else:
            if api:
                return {'error': 'Invalid scan hash'}
            else:
                return HttpResponse(
                    json.dumps({'md5': 'Invalid MD5'}),
                    content_type='application/json; charset=utf-8',
                    status=500)
    except Exception as exp:
        logger.exception('Error Generating PDF Report')
        msg = str(exp)
        exp = exp.__doc__
        if api:
            return print_n_send_error_response(request, msg, True, exp)
        else:
            return print_n_send_error_response(request, msg, False, exp)