Esempio n. 1
0
def pdf(request, api=False):
    try:
        if api:
            checksum = request.POST['hash']
            scan_type = request.POST['scan_type']
        else:
            checksum = request.GET['md5']
            scan_type = request.GET['type']
        hash_match = re.match('^[0-9a-f]{32}$', checksum)
        if hash_match:
            if scan_type.lower() in ['apk', 'andzip']:
                static_db = StaticAnalyzerAndroid.objects.filter(MD5=checksum)
                if static_db.exists():
                    print "\n[INFO] Fetching data from DB for PDF Report Generation (Android)"
                    context = get_context_from_db_entry(static_db)
                    if scan_type.lower() == 'apk':
                        template = get_template("pdf/static_analysis_pdf.html")
                    else:
                        template = get_template(
                            "pdf/static_analysis_zip_pdf.html")
                else:
                    if api:
                        return {"report": "Report not Found"}
                    else:
                        return HttpResponse(
                            json.dumps({"report": "Report not Found"}),
                            content_type="application/json; charset=utf-8",
                            status=500)
            elif re.findall('ipa|ioszip', scan_type.lower()):
                if scan_type.lower() == 'ipa':
                    static_db = StaticAnalyzerIPA.objects.filter(MD5=checksum)
                    if static_db.exists():
                        print "\n[INFO] Fetching data from DB for PDF Report Generation (IOS IPA)"
                        context = get_context_from_db_entry_ipa(static_db)
                        template = get_template(
                            "pdf/ios_binary_analysis_pdf.html")
                    else:
                        if api:
                            return {"report": "Report not Found"}
                        else:
                            return HttpResponse(
                                json.dumps({"report": "Report not Found"}),
                                content_type="application/json; charset=utf-8",
                                status=500)
                elif scan_type.lower() == 'ioszip':
                    static_db = StaticAnalyzerIOSZIP.objects.filter(
                        MD5=checksum)
                    if static_db.exists():
                        print "\n[INFO] Fetching data from DB for PDF Report Generation (IOS ZIP)"
                        context = get_context_from_db_entry_ios(static_db)
                        template = get_template(
                            "pdf/ios_source_analysis_pdf.html")
                    else:
                        if api:
                            return {"report": "Report not Found"}
                        else:
                            return HttpResponse(
                                json.dumps({"report": "Report not Found"}),
                                content_type="application/json; charset=utf-8",
                                status=500)
            elif re.findall('appx', scan_type.lower()):
                if scan_type.lower() == 'appx':
                    db_entry = StaticAnalyzerWindows.objects.filter(  # pylint: disable-msg=E1101
                        MD5=checksum)
                    if db_entry.exists():
                        print "\n[INFO] Fetching data from DB for PDF Report Generation (APPX)"

                        context = {
                            'title':
                            db_entry[0].TITLE,
                            'name':
                            db_entry[0].APP_NAME,
                            'pub_name':
                            db_entry[0].PUB_NAME,
                            'size':
                            db_entry[0].SIZE,
                            'md5':
                            db_entry[0].MD5,
                            'sha1':
                            db_entry[0].SHA1,
                            'sha256':
                            db_entry[0].SHA256,
                            'bin_name':
                            db_entry[0].BINNAME,
                            'version':
                            db_entry[0].VERSION,
                            'arch':
                            db_entry[0].ARCH,
                            'compiler_version':
                            db_entry[0].COMPILER_VERSION,
                            'visual_studio_version':
                            db_entry[0].VISUAL_STUDIO_VERSION,
                            'visual_studio_edition':
                            db_entry[0].VISUAL_STUDIO_EDITION,
                            'target_os':
                            db_entry[0].TARGET_OS,
                            'appx_dll_version':
                            db_entry[0].APPX_DLL_VERSION,
                            'proj_guid':
                            db_entry[0].PROJ_GUID,
                            'opti_tool':
                            db_entry[0].OPTI_TOOL,
                            'target_run':
                            db_entry[0].TARGET_RUN,
                            'files':
                            python_list(db_entry[0].FILES),
                            'strings':
                            python_list(db_entry[0].STRINGS),
                            'bin_an_results':
                            python_list(db_entry[0].BIN_AN_RESULTS),
                            'bin_an_warnings':
                            python_list(db_entry[0].BIN_AN_WARNINGS)
                        }
                        template = get_template(
                            "pdf/windows_binary_analysis_pdf.html")
            else:
                if api:
                    return {"scan_type": "Type is not Allowed"}
                else:
                    return HttpResponse(
                        json.dumps({"type": "Type is not Allowed"}),
                        content_type="application/json; charset=utf-8",
                        status=500)

            context['VT_RESULT'] = None
            if settings.VT_ENABLED:
                app_dir = os.path.join(settings.UPLD_DIR, checksum + '/')
                vt = VirusTotal.VirusTotal()
                context['VT_RESULT'] = vt.get_result(
                    os.path.join(app_dir, checksum) + '.' + scan_type.lower(),
                    checksum)

            html = template.render(context)
            try:
                options = {
                    'page-size': 'A4',
                    'quiet': '',
                    'no-collate': '',
                    'margin-top': '0.50in',
                    'margin-right': '0.50in',
                    'margin-bottom': '0.50in',
                    'margin-left': '0.50in',
                    'encoding': "UTF-8",
                    'custom-header': [('Accept-Encoding', 'gzip')],
                    'no-outline': None
                }

                BASE_DIR = os.path.dirname(
                    os.path.dirname(os.path.dirname(
                        os.path.abspath(__file__))))
                path_wk = os.path.join(BASE_DIR,
                                       'windows/wkhtmltopdf/wkhtmltopdf.exe')
                # path_wk = r'C:\Program Files\wkhtmltopdf\bin\wkhtmltopdf.exe'  # 安装位置
                config = pdfkit.configuration(wkhtmltopdf=path_wk)
                pdf_dat = pdfkit.from_string(html,
                                             False,
                                             options=options,
                                             configuration=config)
                if api:
                    return {"pdf_dat": pdf_dat}
                else:
                    return HttpResponse(pdf_dat,
                                        content_type='application/pdf')
            except Exception as exp:
                if api:
                    return {
                        "error": "Cannot Generate PDF",
                        "err_details": str(exp)
                    }
                else:
                    return HttpResponse(
                        json.dumps({
                            "pdf_error": "Cannot Generate PDF",
                            "err_details": str(exp)
                        }),
                        content_type="application/json; charset=utf-8",
                        status=500)

        else:
            if api:
                return {"error": "Invalid scan hash"}
            else:
                return HttpResponse(
                    json.dumps({"md5": "Invalid MD5"}),
                    content_type="application/json; charset=utf-8",
                    status=500)
    except Exception as exp:
        msg = str(exp)
        exp = exp.__doc__
        if api:
            return print_n_send_error_response(request, msg, True, exp)
        else:
            return print_n_send_error_response(request, msg, False, exp)
Esempio n. 2
0
def static_analyzer_ios(request, api=False):
    """Module that performs iOS IPA/ZIP Static Analysis"""
    try:
        print("[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/')  # TOOLS DIR
            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:
                    print("[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 PATH
                    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
                    print("[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)
                    bin_analysis_dict = binary_analysis(
                        app_dict["bin_dir"], tools_dir, app_dict["app_dir"], infoplist_dict.get("bin"))
                    # Saving to DB
                    print("\n[INFO] Connecting to DB")
                    if rescan == '1':
                        print("\n[INFO] Updating Database...")
                        update_db_entry_ipa(
                            app_dict, infoplist_dict, bin_analysis_dict, files, sfiles)
                    elif rescan == '0':
                        print("\n[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']
                    )

                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:
                    print("[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 PATH
                    # ANALYSIS BEGINS - Already Unzipped
                    print("[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)
                    code_analysis_dic = ios_source_analysis(
                        app_dict["app_dir"])
                    # Saving to DB
                    print("\n[INFO] Connecting to DB")
                    if rescan == '1':
                        print("\n[INFO] Updating Database...")
                        update_db_entry_ios(
                            app_dict, infoplist_dict, code_analysis_dic, files, sfiles)
                    elif rescan == '0':
                        print("\n[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)
                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:
        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(request, api=False):
    """Do static analysis on an request and save to db."""
    try:
        if api:
            typ = request.POST['scan_type']
            checksum = request.POST['hash']
            filename = request.POST['file_name']
            rescan = str(request.POST.get('re_scan', 0))
        else:
            typ = request.GET['type']
            checksum = request.GET['checksum']
            filename = request.GET['name']
            rescan = str(request.GET.get('rescan', 0))
        # Input validation
        app_dic = {}
        match = re.match('^[0-9a-f]{32}$', checksum)
        if (
                (
                    match
                ) and (
                    filename.lower().endswith('.apk') or
                    filename.lower().endswith('.zip')
                ) and (
                    typ in ['zip', 'apk']
                )
        ):
            app_dic['dir'] = settings.BASE_DIR  # BASE DIR
            app_dic['app_name'] = filename  # APP ORGINAL NAME
            app_dic['md5'] = checksum  # MD5
            app_dic['app_dir'] = os.path.join(settings.UPLD_DIR, app_dic[
                                              'md5'] + '/')  # APP DIRECTORY
            app_dic['tools_dir'] = os.path.join(
                app_dic['dir'], 'StaticAnalyzer/tools/')  # TOOLS DIR
            # DWD_DIR = settings.DWD_DIR # not needed? Var is never used.
            print("[INFO] Starting Analysis on : " + app_dic['app_name'])

            if typ == 'apk':
                # Check if in DB
                # pylint: disable=E1101
                db_entry = StaticAnalyzerAndroid.objects.filter(
                    MD5=app_dic['md5'])
                if db_entry.exists() and rescan == '0':
                    context = get_context_from_db_entry(db_entry)
                else:
                    app_dic['app_file'] = app_dic[
                        'md5'] + '.apk'  # NEW FILENAME
                    app_dic['app_path'] = app_dic['app_dir'] + \
                        app_dic['app_file']  # APP PATH

                    # ANALYSIS BEGINS
                    app_dic['size'] = str(
                        file_size(app_dic['app_path'])) + 'MB'  # FILE SIZE
                    app_dic['sha1'], app_dic[
                        'sha256'] = hash_gen(app_dic['app_path'])

                    app_dic['files'] = unzip(
                        app_dic['app_path'], app_dic['app_dir'])
                    app_dic['certz'] = get_hardcoded_cert_keystore(app_dic[
                                                                   'files'])

                    print("[INFO] APK Extracted")

                    # Manifest XML
                    app_dic['parsed_xml'] = get_manifest(
                        app_dic['app_path'],
                        app_dic['app_dir'],
                        app_dic['tools_dir'],
                        '',
                        True
                    )

                    # Get icon
                    res_path = os.path.join(app_dic['app_dir'], 'res')
                    app_dic['icon_hidden'] = True
                    # Even if the icon is hidden, try to guess it by the
                    # default paths
                    app_dic['icon_found'] = False
                    app_dic['icon_path'] = ''
                    # TODO: Check for possible different names for resource
                    # folder?
                    if os.path.exists(res_path):
                        icon_dic = get_icon(
                            app_dic['app_path'], res_path)
                        if icon_dic:
                            app_dic['icon_hidden'] = icon_dic['hidden']
                            app_dic['icon_found'] = bool(icon_dic['path'])
                            app_dic['icon_path'] = icon_dic['path']

                    # Set Manifest link
                    app_dic['mani'] = '../ManifestView/?md5=' + \
                        app_dic['md5'] + '&type=apk&bin=1'
                    man_data_dic = manifest_data(app_dic['parsed_xml'])

                    man_an_dic = manifest_analysis(
                        app_dic['parsed_xml'],
                        man_data_dic
                    )
                    bin_an_buff = []
                    bin_an_buff += elf_analysis(app_dic['app_dir'])
                    bin_an_buff += res_analysis(app_dic['app_dir'])
                    cert_dic = cert_info(
                        app_dic['app_dir'], app_dic['tools_dir'])
                    apkid_results = apkid_analysis(app_dic[
                        'app_dir'], app_dic['app_path'])
                    dex_2_jar(app_dic['app_path'], app_dic[
                              'app_dir'], app_dic['tools_dir'])
                    dex_2_smali(app_dic['app_dir'], app_dic['tools_dir'])
                    jar_2_java(app_dic['app_dir'], app_dic['tools_dir'])
                    code_an_dic = code_analysis(
                        app_dic['app_dir'],
                        man_an_dic['permissons'],
                        "apk"
                    )
                    print("\n[INFO] Generating Java and Smali Downloads")
                    gen_downloads(app_dic['app_dir'], app_dic[
                                  'md5'], app_dic['icon_path'])

                    # Get the strings
                    app_dic['strings'] = strings_jar(
                        app_dic['app_file'],
                        app_dic['app_dir']
                    )
                    app_dic['zipped'] = '&type=apk'

                    print("\n[INFO] Connecting to Database")
                    try:
                        # SAVE TO DB
                        if rescan == '1':
                            print("\n[INFO] Updating Database...")
                            update_db_entry(
                                app_dic,
                                man_data_dic,
                                man_an_dic,
                                code_an_dic,
                                cert_dic,
                                bin_an_buff,
                                apkid_results,
                            )
                        elif rescan == '0':
                            print("\n[INFO] Saving to Database")
                            create_db_entry(
                                app_dic,
                                man_data_dic,
                                man_an_dic,
                                code_an_dic,
                                cert_dic,
                                bin_an_buff,
                                apkid_results,
                            )
                    except:
                        PrintException("[ERROR] Saving to Database Failed")
                    context = get_context_from_analysis(
                        app_dic,
                        man_data_dic,
                        man_an_dic,
                        code_an_dic,
                        cert_dic,
                        bin_an_buff,
                        apkid_results,
                    )
                context["average_cvss"], context[
                    "security_score"] = score(context["findings"])
                context['dynamic_analysis_done'] = os.path.exists(
                    os.path.join(app_dic['app_dir'], 'logcat.txt'))

                context['VT_RESULT'] = None
                if settings.VT_ENABLED:
                    vt = VirusTotal.VirusTotal()
                    context['VT_RESULT'] = vt.get_result(
                        os.path.join(app_dic['app_dir'],
                                     app_dic['md5']) + '.apk',
                        app_dic['md5']
                    )
                template = "static_analysis/static_analysis.html"
                if api:
                    return context
                else:
                    return render(request, template, context)
            elif typ == 'zip':
                # Check if in DB
                # pylint: disable=E1101
                cert_dic = {}
                cert_dic['cert_info'] = ''
                cert_dic['issued'] = ''
                cert_dic['sha256Digest'] = False
                bin_an_buff = []
                app_dic['strings'] = ''
                app_dic['zipped'] = ''
                # Above fields are only available for APK and not ZIP
                db_entry = StaticAnalyzerAndroid.objects.filter(
                    MD5=app_dic['md5'])
                if db_entry.exists() and rescan == '0':
                    context = get_context_from_db_entry(db_entry)
                else:
                    app_dic['app_file'] = app_dic[
                        'md5'] + '.zip'  # NEW FILENAME
                    app_dic['app_path'] = app_dic['app_dir'] + \
                        app_dic['app_file']  # APP PATH
                    print("[INFO] Extracting ZIP")
                    app_dic['files'] = unzip(
                        app_dic['app_path'], app_dic['app_dir'])
                    # Check if Valid Directory Structure and get ZIP Type
                    pro_type, valid = valid_android_zip(app_dic['app_dir'])
                    if valid and pro_type == 'ios':
                        print("[INFO] Redirecting to iOS Source Code Analyzer")
                        if api:
                            return {"type": "ios"}
                        else:
                            return HttpResponseRedirect(
                                '/StaticAnalyzer_iOS/?name=' + app_dic['app_name'] +
                                '&type=ios&checksum=' + app_dic['md5']
                            )
                    app_dic['certz'] = get_hardcoded_cert_keystore(app_dic[
                                                                   'files'])
                    app_dic['zipped'] = pro_type
                    print("[INFO] ZIP Type - " + pro_type)
                    if valid and (pro_type in ['eclipse', 'studio']):
                        # ANALYSIS BEGINS
                        app_dic['size'] = str(
                            file_size(app_dic['app_path'])) + 'MB'  # FILE SIZE
                        app_dic['sha1'], app_dic[
                            'sha256'] = hash_gen(app_dic['app_path'])

                        # Manifest XML
                        app_dic['persed_xml'] = get_manifest(
                            "",
                            app_dic['app_dir'],
                            app_dic['tools_dir'],
                            pro_type,
                            False
                        )

                        # Set manifest view link
                        app_dic['mani'] = (
                            '../ManifestView/?md5=' +
                            app_dic['md5'] + '&type=' + pro_type + '&bin=0'
                        )

                        man_data_dic = manifest_data(app_dic['persed_xml'])

                        man_an_dic = manifest_analysis(
                            app_dic['persed_xml'],
                            man_data_dic
                        )

                        # Get icon
                        eclipse_res_path = os.path.join(
                            app_dic['app_dir'], 'res')
                        studio_res_path = os.path.join(
                            app_dic['app_dir'], 'app', 'src', 'main', 'res')
                        if os.path.exists(eclipse_res_path):
                            res_path = eclipse_res_path
                        elif os.path.exists(studio_res_path):
                            res_path = studio_res_path
                        else:
                            res_path = ''

                        app_dic['icon_hidden'] = man_an_dic['icon_hidden']
                        app_dic['icon_found'] = False
                        app_dic['icon_path'] = ''
                        if res_path:
                            app_dic['icon_path'] = find_icon_path_zip(
                                res_path, man_data_dic['icons'])
                            if app_dic['icon_path']:
                                app_dic['icon_found'] = True

                        if app_dic['icon_path']:
                            if os.path.exists(app_dic['icon_path']):
                                shutil.copy2(app_dic['icon_path'], os.path.join(
                                    settings.DWD_DIR, app_dic['md5'] + '-icon.png'))

                        code_an_dic = code_analysis(
                            app_dic['app_dir'],
                            man_an_dic['permissons'],
                            pro_type
                        )
                        print("\n[INFO] Connecting to Database")
                        try:
                            # SAVE TO DB
                            if rescan == '1':
                                print("\n[INFO] Updating Database...")
                                update_db_entry(
                                    app_dic,
                                    man_data_dic,
                                    man_an_dic,
                                    code_an_dic,
                                    cert_dic,
                                    bin_an_buff,
                                    {},
                                )
                            elif rescan == '0':
                                print("\n[INFO] Saving to Database")
                                create_db_entry(
                                    app_dic,
                                    man_data_dic,
                                    man_an_dic,
                                    code_an_dic,
                                    cert_dic,
                                    bin_an_buff,
                                    {},
                                )
                        except:
                            PrintException("[ERROR] Saving to Database Failed")
                        context = get_context_from_analysis(
                            app_dic,
                            man_data_dic,
                            man_an_dic,
                            code_an_dic,
                            cert_dic,
                            bin_an_buff,
                            {},
                        )
                    else:
                        msg = "This ZIP Format is not supported"
                        if api:
                            return print_n_send_error_response(request, msg, True)
                        else:
                            print_n_send_error_response(request, msg, False)
                            return HttpResponseRedirect('/zip_format/')
                context["average_cvss"], context[
                    "security_score"] = score(context["findings"])
                template = "static_analysis/static_analysis_android_zip.html"
                if api:
                    return context
                else:
                    return render(request, template, context)
            else:
                print(
                    "\n[ERROR] Only APK,IPA and Zipped Android/iOS Source code supported now!")
        else:
            msg = "Hash match failed or Invalid file extension or file type"
            if api:
                return print_n_send_error_response(request, msg, True)
            else:
                return print_n_send_error_response(request, msg, False)

    except Exception as excep:
        msg = str(excep)
        exp = excep.__doc__
        if api:
            return print_n_send_error_response(request, msg, True, exp)
        else:
            return print_n_send_error_response(request, msg, False, exp)