Example #1
0
    def test_track_detail_app_removed_tracker(self):
        tracker1 = Tracker(
            id=1,
            name='Teemo',
        )
        tracker1.save()
        application_handle1 = "com.handle.one"
        report1 = Report()
        report1.save()
        application1 = Application(
            handle=application_handle1,
            report=report1
        )
        application1.save()
        report1.found_trackers = [tracker1.id]
        report1.save()

        report2 = Report()
        report2.save()
        application2 = Application(
            handle=application_handle1,
            report=report2
        )
        application2.save()
        # Removing trackers in the version of the app
        report2.found_trackers = []
        report2.save()

        c = Client()
        url = self.TRACKER_DETAIL_PATH.format(tracker1.id)
        response = c.get(url)
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.context['tracker'].id, tracker1.id)
        self.assertEqual(len(response.context['reports']), 0)
Example #2
0
    def test_track_detail_app_multiple_reports(self):
        tracker2 = Tracker(
            id=2,
            name='Exodus Super Tracker',
        )
        tracker2.save()
        application_handle2 = "com.handle.two"
        report2 = Report()
        report2.save()
        application2 = Application(
            handle=application_handle2,
            report=report2
        )
        application2.save()
        report2.found_trackers = [tracker2.id]
        report2.save()
        report3 = Report()
        report3.save()
        application3 = Application(
            handle=application_handle2,
            report=report3
        )
        application3.save()
        report3.found_trackers = [tracker2.id]
        report3.save()

        c = Client()
        url = self.TRACKER_DETAIL_PATH.format(tracker2.id)
        response = c.get(url)

        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.context['tracker'].id, tracker2.id)
        self.assertEqual(len(response.context['reports']), 1)
        self.assertEqual(response.context['reports'][0].application.handle, application_handle2)
        self.assertEqual(response.context['reports'][0], report3)
Example #3
0
    def test_should_return_stats_with_multiple_reports_multiple_application(self):
        tracker1 = Tracker(
            id=1,
            name='Teemo',
        )
        tracker1.save()
        tracker2 = Tracker(
            id=2,
            name='Exodus Super Tracker',
        )
        tracker2.save()
        application_handle1 = "com.handle.one"
        application_handle2 = "com.handle.two"
        report1 = Report()
        report1.save()
        application1 = Application(
            handle=application_handle1,
            report=report1
        )
        application1.save()
        report1.found_trackers = [tracker2.id]
        report1.save()
        report2 = Report()
        report2.save()
        application2 = Application(
            handle=application_handle2,
            report=report2
        )
        application2.save()
        report2.found_trackers = []
        report2.save()
        report3 = Report()
        report3.save()
        application3 = Application(
            handle=application_handle2,
            report=report3
        )
        application3.save()
        report3.found_trackers = [tracker1.id, tracker2.id]
        report3.save()

        c = Client()
        response = c.get(self.STATS_PATH)

        self.assertEqual(response.status_code, 200)
        self.assertContains(response, tracker1.name, 1)
        self.assertContains(response, tracker2.name, 1)
        self.assertEqual(response.context['trackers'][0].name, tracker2.name)
        # Only recent for an application is considered
        self.assertEqual(response.context['trackers'][0].count, 2)
        self.assertEqual(response.context['trackers'][0].score, 100)
        self.assertEqual(response.context['trackers'][1].name, tracker1.name)
        self.assertEqual(response.context['trackers'][1].count, 1)
        self.assertEqual(response.context['trackers'][1].score, 50)
Example #4
0
    def test_should_return_stats_with_multiple_trackers_found(self):
        tracker1 = Tracker(
            id=1,
            name='Teemo',
        )
        tracker1.save()
        tracker2 = Tracker(
            id=2,
            name='Exodus Super Tracker',
        )
        tracker2.save()

        report1 = Report()
        report1.save()
        report1.found_trackers = [tracker2.id]
        report1.save()
        report2 = Report()
        report2.save()
        report2.found_trackers = []
        report2.save()
        report3 = Report()
        report3.save()
        report3.found_trackers = [tracker1.id, tracker2.id]
        report3.save()

        c = Client()
        response = c.get(self.STATS_PATH)

        self.assertEqual(response.status_code, 200)
        self.assertContains(response, tracker1.name, 1)
        self.assertContains(response, tracker2.name, 1)
        self.assertEqual(response.context['trackers'][0].name, tracker2.name)
        self.assertEqual(response.context['trackers'][0].count, 2)
        self.assertEqual(response.context['trackers'][0].score, 66)
        self.assertEqual(response.context['trackers'][1].name, tracker1.name)
        self.assertEqual(response.context['trackers'][1].count, 1)
        self.assertEqual(response.context['trackers'][1].score, 33)
Example #5
0
    def test_should_return_stats_with_1_tracker_found(self):
        tracker = Tracker(
            id=1,
            name='Teemo',
        )
        tracker.save()
        report = Report()
        report.save()
        report.found_trackers = [tracker.id]
        report.save()

        c = Client()
        response = c.get(self.STATS_PATH)

        self.assertEqual(response.status_code, 200)
        self.assertContains(response, tracker.name, 1)
        self.assertEqual(response.context['trackers'][0].name, tracker.name)
        self.assertEqual(response.context['trackers'][0].count, 1)
        self.assertEqual(response.context['trackers'][0].score, 100)
Example #6
0
    def test_should_not_include_more_than_X_trackers(self):
        tracker_limit = 21
        for x in range(0, tracker_limit):
            tracker = Tracker(name='Tracker{}.'.format(x))
            tracker.save()

        extra_tracker = Tracker(name='Exodus Super Tracker')
        extra_tracker.save()

        first_trackers = Tracker.objects.exclude(name=extra_tracker.name)

        report = Report()
        report.save()
        report.found_trackers = [t.id for t in first_trackers]
        report.save()

        c = Client()
        response = c.get(self.STATS_PATH)

        self.assertEqual(response.status_code, 200)
        self.assertNotContains(response, extra_tracker.name)
        for t in first_trackers:
            self.assertContains(response, t.name, 1)
Example #7
0
def start_static_analysis(analysis):
    """
    Compute the entire static analysis
    :param analysis: a StaticAnalysis instance
    """
    request = AnalysisRequest.objects.get(pk=analysis.query.id)
    request.description = _('Your request is running')
    request.save()
    storage_helper = RemoteStorageHelper(analysis.bucket)

    # Download APK and put it on Minio storage
    dl_r = download_apk(storage_helper, request.handle, analysis.tmp_dir, analysis.apk_name, analysis.apk_tmp)
    if not dl_r:
        msg = _('Unable to download the APK')
        exit_code = save_error(storage_helper, analysis, request, msg)
        return exit_code

    change_description(request, _('Download APK: success'))

    # Decode the APK file
    try:
        static_analysis = StaticAnalysis(analysis.apk_tmp)
        static_analysis.load_apk()
    except Exception as e:
        logging.info(e)
        msg = _('Unable to decode the APK')
        exit_code = save_error(storage_helper, analysis, request, msg)
        return exit_code

    change_description(request, _('Decode APK: success'))

    # List and save embedded classes
    try:
        with tempfile.NamedTemporaryFile(delete=True) as fp:
            static_analysis.save_embedded_classes_in_file(fp.name)
            storage_helper.put_file(fp.name, analysis.class_list_file)
    except Exception as e:
        logging.info(e)
        msg = _('Unable to compute the class list')
        exit_code = save_error(storage_helper, analysis, request, msg)
        return exit_code

    change_description(request, _('List embedded classes: success'))

    # APK
    shasum = static_analysis.get_sha256()

    # Application
    handle = static_analysis.get_package()
    version = static_analysis.get_version()
    version_code = static_analysis.get_version_code()

    # If a report exists for the same handle, version & version_code, return it
    existing_report = Report.objects.filter(
        application__handle=handle,
        application__version=version,
        application__version_code=version_code
    ).order_by('-creation_date').first()

    if existing_report is not None:
        clear_analysis_files(storage_helper, analysis.tmp_dir, analysis.bucket, True)
        request.description = _('A report already exists for this application version')
        request.processed = True
        request.report_id = existing_report.id
        request.save()
        return existing_report.id

    # APK
    try:
        certificates = static_analysis.get_certificates()
    except Exception as e:
        logging.info(e)
        msg = _('Unable to get certificates')
        exit_code = save_error(storage_helper, analysis, request, msg)
        return exit_code

    # Fingerprint
    try:
        perms = static_analysis.get_permissions()

        app_uid = static_analysis.get_application_universal_id()
        if len(app_uid) < 16:
            raise Exception('Unable to compute the Universal Application ID')

        icon_file, icon_phash = static_analysis.get_icon_and_phash(storage_helper, analysis.icon_name)
        if len(str(icon_phash)) < 16:
            raise Exception('Unable to compute the icon perceptual hash')
    except Exception as e:
        logging.info(e)
        msg = _('Unable to compute APK fingerprint')
        exit_code = save_error(storage_helper, analysis, request, msg)
        return exit_code

    # Application details
    try:
        app_info = static_analysis.get_app_info()
    except Exception as e:
        logging.info(e)
        msg = _('Unable to get application details from Google Play')
        exit_code = save_error(storage_helper, analysis, request, msg)
        return exit_code

    change_description(request, _('Get application details: success'))

    # Find trackers
    trackers = static_analysis.detect_trackers()

    change_description(request, _('Tracker analysis: success'))

    report = Report(
        apk_file=analysis.apk_name,
        storage_path='',
        bucket=request.bucket,
        class_list_file=analysis.class_list_file
    )
    report.save()

    net_analysis = NetworkAnalysis(report=report)
    net_analysis.save()

    app = Application(
        report=report,
        handle=handle,
        version=version,
        version_code=version_code,
        name=static_analysis.get_app_name(),
        icon_phash=icon_phash,
        app_uid=app_uid
    )
    if app_info is not None:
        app.name = app_info['title']
        app.creator = app_info['creator']
        app.downloads = app_info['downloads']
    if icon_file != '':
        app.icon_path = analysis.icon_name
    app.save(force_insert=True)

    apk = Apk(
        application=app,
        name=analysis.apk_name,
        sum=shasum
    )
    apk.save(force_insert=True)

    for certificate in certificates:
        c = Certificate(
            apk=apk,
            issuer=certificate.issuer,
            fingerprint=certificate.fingerprint,
            subject=certificate.subject,
            serial_number=certificate.serial
        )
        c.save(force_insert=True)

    for perm in perms:
        p = Permission(
            application=app,
            name=perm
        )
        p.save(force_insert=True)

    report.found_trackers = trackers
    report.save()

    change_description(request, _('Static analysis complete'))
    clear_analysis_files(storage_helper, analysis.tmp_dir, analysis.bucket, False)
    request.processed = True
    request.report_id = report.id
    request.save()
    return report.id