예제 #1
0
def embed(vcdb_id):
    try:
        section_id = int(request.args.get("sid", -1))
        start_line = int(request.args.get("start_line", 1))
        end_line = int(request.args.get("end_line", -1))
        vulnerability_details = VulnerabilityDetails(vcdb_id)
        vulnerability_details.validate_and_simplify_id()
        view = vulnerability_details.vulnerability_view
        if not view:
            return make_response(("No vulnerability found", 404))
        if not view.master_commit:
            return make_response(
                (f"Vuln (id: {view.id}) has no linked Git commits!", 404)
            )

        master_commit = vulnerability_details.get_master_commit()
        files_schema = RepositoryFilesSchema(many=True)
        # Hack to quickly retrieve the full data.
        custom_data = json.loads(
            files_schema.jsonify(master_commit.repository_files).data
        )
        settings = {
            "section_id": section_id,
            "startLine": start_line,
            "endLine": end_line,
            "entry_data": custom_data,
        }
        return render_template(
            "vulnerability/embedded.html",
            vulnerability_details=vulnerability_details,
            embed_settings=settings,
        )
    except (ValueError, InvalidIdentifierException):
        return make_response(("No vulnerability found", 404))
예제 #2
0
def view_vuln(vuln_id, use_template):
    try:
        vulnerability_details = VulnerabilityDetails(vuln_id)
        vulnerability_details.validate()
    except InvalidIdentifierException as err:
        return flashError(str(err), "serve_index")
    return render_template(
        use_template, vulnerability_details=vulnerability_details)
예제 #3
0
def view_vuln(vcdb_id, use_template):
    try:
        vulnerability_details = VulnerabilityDetails(vcdb_id)
        vulnerability_details.validate_and_simplify_id()
        if not vulnerability_details.vulnerability_view:
            abort(404)
    except InvalidIdentifierException as err:
        return flash_error(str(err), "frontend.serve_index")
    return render_template(use_template, vulnerability_details=vulnerability_details)
예제 #4
0
def _get_vulnerability_details(vuln_id):
    try:
        vulnerability_details = VulnerabilityDetails(vuln_id)
        vulnerability_details.validate()
        # Drop everything else.
        if not vulnerability_details.vulnerability_view:
            abort(404)
        return vulnerability_details
    except InvalidIdentifierException:
        abort(404)
예제 #5
0
def _create_vuln_internal(vcdb_id=None):
    try:
        vulnerability_details = VulnerabilityDetails(vcdb_id)
        vulnerability = vulnerability_details.get_or_create_vulnerability()
    except InvalidIdentifierException as err:
        return flash_error(str(err), "frontend.serve_index")

    if vulnerability.id:
        logging.debug("Preexisting vulnerability entry found: %r",
                      vulnerability.id)
        delete_form = VulnerabilityDeleteForm()
        if delete_form.validate_on_submit():
            db.session.delete(vulnerability)
            # Remove the entry.
            db.session.commit()
            flash("The entry was deleted.", "success")
            return redirect("/")

    form = VulnerabilityDetailsForm(obj=vulnerability)
    commit = form.data["commits"][0]
    if not commit["repo_name"]:
        logging.info("Empty repository name. %r", commit)
        repo_url = commit["repo_url"]
        vcs_handler = get_vcs_handler(None, repo_url)
        if vcs_handler:
            logging.info("Found name. %r", vcs_handler.repo_name)
            form.commits[0].repo_name.process_data(vcs_handler.repo_name)

    if form.validate_on_submit():
        try:
            form.populate_obj(vulnerability)
            db.session.add(vulnerability)
            db.session.commit()
            # TODO: Improve this hack to assign a new vcdb_id here.
            #       Currently, we are just piggy backing on the auto increment
            #       of the primary key to ensure uniqueness.
            #       This will likely be prone to race conditions.
            vulnerability.vcdb_id = vulnerability.id
            db.session.add(vulnerability)
            db.session.commit()

            logging.debug("Successfully created/updated entry: %r",
                          vulnerability.id)
            flash("Successfully created/updated entry.", "success")
            return redirect(
                url_for("vuln.vuln_view", vcdb_id=vulnerability.vcdb_id))
        except InvalidIdentifierException as err:
            flash_error(str(err))

    return render_template(
        "vulnerability/create.html",
        vulnerability_details=vulnerability_details,
        form=form,
    )
예제 #6
0
def _get_vulnerability_details(vcdb_id, vuln_id=None,
                               simplify_id: bool = True):
    try:
        vulnerability_details = VulnerabilityDetails(vcdb_id, vuln_id)
        if simplify_id:
            vulnerability_details.validate_and_simplify_id()
        # Drop everything else.
        if not vulnerability_details.vulnerability_view:
            abort(404)
        return vulnerability_details
    except InvalidIdentifierException:
        abort(404)
예제 #7
0
def get_vulnerability_details(vcdb_id, vuln_id=None, simplify_id: bool = True):
    # pylint: disable=import-outside-toplevel,cyclic-import
    from app.vulnerability.views.details import VulnerabilityDetails

    # pylint: enable=import-outside-toplevel,cyclic-import
    try:
        vulnerability_details = VulnerabilityDetails(vcdb_id, vuln_id)
        if simplify_id:
            vulnerability_details.validate_and_simplify_id()
        # Drop everything else.
        if not vulnerability_details.vulnerability_view:
            abort(404)
        return vulnerability_details
    except InvalidIdentifierException:
        abort(404)
예제 #8
0
def _create_vuln_internal(vuln_id=None):
    try:
        vulnerability_details = VulnerabilityDetails(vuln_id)
        vulnerability = vulnerability_details.get_or_create_vulnerability()
    except InvalidIdentifierException as err:
        return flashError(str(err), "serve_index")

    if vulnerability.id:
        logging.debug("Preexisting vulnerability entry found: %s",
                      vulnerability.id)
        delete_form = VulnerabilityDeleteForm()
        if delete_form.validate_on_submit():
            db.session.delete(vulnerability)
            # Remove the entry.
            db.session.commit()
            flash("The entry was deleted.", "success")
            return redirect("/")

    form = VulnerabilityDetailsForm(obj=vulnerability)
    commit = form.data["commits"][0]
    if not commit["repo_name"]:
        logging.info("Empty repository name. %r", commit)
        repo_url = commit["repo_url"]
        vcs_handler = get_vcs_handler(None, repo_url)
        if vcs_handler:
            logging.info("Found name. %r", vcs_handler.repo_name)
            form.commits[0].repo_name.process_data(vcs_handler.repo_name)

    if form.validate_on_submit():
        try:
            form.populate_obj(vulnerability)
            db.session.add(vulnerability)
            db.session.commit()
            logging.debug("Successfully created/updated entry: %s",
                          vulnerability.id)
            flash("Successfully created/updated entry.", "success")
            return redirect(url_for("vuln.vuln_view", vuln_id=vulnerability.id))
        except InvalidIdentifierException as err:
            flashError(str(err))

    return render_template(
        "create_entry.html",
        vulnerability_details=vulnerability_details,
        form=form)
예제 #9
0
def _edit_vuln_internal(vcdb_id: str = None):
    try:
        vulnerability_details = VulnerabilityDetails(vcdb_id)
        vulnerability_view = vulnerability_details.vulnerability_view
        vulnerability = vulnerability_details.get_or_create_vulnerability()
    except InvalidIdentifierException as err:
        return flash_error(str(err), "frontend.serve_index")
    form = VulnerabilityDetailsForm(obj=vulnerability)

    # Populate the form data from the vulnerability view if necessary.
    if form.comment.data == "":
        form.comment.data = vulnerability_view.comment

    form_submitted = form.validate_on_submit()
    if form_submitted and _can_add_proposal(vulnerability):
        add_proposal(vulnerability, form)

    return render_template("vulnerability/edit.html",
                           vulnerability_details=vulnerability_details,
                           form=form)
예제 #10
0
def _edit_vuln_internal(vcdb_id: str = None):
    try:
        vulnerability_details = VulnerabilityDetails(vcdb_id)
        vulnerability_view = vulnerability_details.vulnerability_view
        vulnerability = vulnerability_details.get_or_create_vulnerability()
    except InvalidIdentifierException as err:
        return flash_error(str(err), "frontend.serve_index")
    form = VulnerabilityDetailsForm(obj=vulnerability)

    # Populate the form data from the vulnerability view if necessary.
    if form.comment.data == "":
        form.comment.data = vulnerability_view.comment

    form_submitted = form.validate_on_submit()
    if form_submitted and _can_add_proposal(vulnerability):
        # TODO: This is incomplete/incorrect as the attached relationships such a GitCommit objects get updated.
        #       We have to ensure everything is properly detached and gets copied before any modifications happen.
        #       Currently, this will incorrectly update relationship objects instead of copying them.
        form.populate_obj(vulnerability)
        add_proposal(vulnerability)

    return render_template("vulnerability/edit.html",
                           vulnerability_details=vulnerability_details,
                           form=form)
예제 #11
0
def bug_save_editor_data():
    try:
        vulnerability_details = VulnerabilityDetails()
        vulnerability_details.validate()
    except InvalidIdentifierException as e:
        return create_json_response(str(e), 400)
    vuln_view = vulnerability_details.vulnerability_view

    if request.method == "POST":
        if not vuln_view:
            return create_json_response("Please create an entry first", 404)

        if not vuln_view.master_commit:
            current_app.logger.error(
                f"Vuln (id: {vuln_view.id}) has no linked Git commits!")
            return create_json_response("Entry has no linked Git link!", 404)

        master_commit = vulnerability_details.getMasterCommit()

        # print("DATA: {request.json}"
        old_files = master_commit.repository_files
        current_app.logger.debug("%d old files", len(old_files))
        # Flush any old custom content of this vulnerability first.
        new_files = []
        for file in request.get_json():
            for of in old_files:
                if of.file_path == file["path"] or of.file_hash == file["hash"]:
                    current_app.logger.debug(
                        "Found old file: %s",
                        (file["path"], file["hash"], file["name"]))
                    file_obj = of
                    break
            else:
                current_app.logger.debug(
                    "Creating new file: %s",
                    (file["path"], file["hash"], file["name"]))
                file_obj = RepositoryFiles(
                    file_name=file["name"],
                    file_path=file["path"],
                    file_patch="DEPRECATED",
                    file_hash=file["hash"],
                )
            # Create comment objects.
            new_comments = []
            for comment in file["comments"]:
                comment_obj = RepositoryFileComments(
                    row_from=comment["row_from"],
                    row_to=comment["row_to"],
                    text=comment["text"],
                    sort_pos=comment["sort_pos"],
                    creator=g.user,
                )
                new_comments.append(comment_obj)
            update_file_comments(file_obj, new_comments)
            # Create marker objects.
            new_markers = []
            for marker in file["markers"]:
                marker_obj = RepositoryFileMarkers(
                    row_from=marker["row_from"],
                    row_to=marker["row_to"],
                    column_from=marker["column_from"],
                    column_to=marker["column_to"],
                    marker_class=marker["class"],
                    creator=g.user,
                )
                new_markers.append(marker_obj)
            update_file_markers(file_obj, new_markers)
            new_files.append(file_obj)

        current_app.logger.debug("Setting %d files", len(new_files))
        master_commit.repository_files = new_files

        # Update / Insert entries into the database.
        db.session.commit()
        return create_json_response("Update successful.")
    return create_json_response("Accepting only POST requests.", 400)
예제 #12
0
    def __init__(self):

        self.keyword = None
        self.top_contributors = []
        # TODO: Look into neabling this once public contributions are enabled.
        # self.fetch_top_contributors()

        has_annotations_col = Vulnerability.has_annotations
        vcdb_entries = db.session.query(Vulnerability, Nvd,
                                        has_annotations_col)
        vcdb_entries = vcdb_entries.filter(
            Vulnerability.state == VulnerabilityState.PUBLISHED)
        vcdb_entries = vcdb_entries.outerjoin(
            Nvd, Vulnerability.cve_id == Nvd.cve_id)
        vcdb_entries = vcdb_entries.options(default_nvd_view_options)
        vcdb_entries = vcdb_entries.from_self()
        vcdb_entries = vcdb_entries.order_by(
            desc(has_annotations_col),
            asc(Vulnerability.date_created),
            desc(Vulnerability.id),
        )
        self.vcdb_entries = vcdb_entries

        nvd_entries = db.session.query(Nvd)
        nvd_entries = nvd_entries.outerjoin(Vulnerability,
                                            Nvd.cve_id == Vulnerability.cve_id)
        nvd_entries = nvd_entries.options(default_nvd_view_options)
        nvd_entries = nvd_entries.filter(Vulnerability.cve_id.is_(None))
        nvd_entries = nvd_entries.order_by(desc(Nvd.published_date),
                                           desc(Nvd.id))
        self.nvd_entries = nvd_entries

        self.keyword = request.args.get("keyword", None, type=str)

        apply_filter = None
        if self.keyword:
            # TODO: Make the filtering work with fulltext search as well.
            if VulnerabilityDetails.is_cve_id(self.keyword):
                apply_filter = or_(False, Nvd.cve_id == self.keyword)
            elif VulnerabilityDetails.is_vcdb_id(self.keyword):
                apply_filter = or_(False, Vulnerability.id == self.keyword)
            else:
                escaped_keyword = self.keyword.replace("%", "")
                # escaped_keyword = re.sub('[\W]+', ' ', self.keyword)
                # Attention: We can't use FullText search here because of some
                # buggy Mysql 5.7 behavior (using FullText on Join results seems
                # is doing bad things. We might need to apply the filter before
                # joining below.
                # apply_filter = or_(
                #     FullTextSearch(escaped_keyword, Nvd,
                #                    FullTextMode.BOOLEAN),
                #     FullTextSearch(escaped_keyword, Vulnerability,
                #                    FullTextMode.BOOLEAN))
                apply_filter = or_(
                    Nvd.descriptions.any(
                        Description.value.like("%" + escaped_keyword + "%")),
                    Vulnerability.comment.like("%" + escaped_keyword + "%"),
                )

            # TODO: add product search support.
            # apply_filter = or_(apply_filter, Cpe.product == keyword)

        if apply_filter is not None:
            self.vcdb_entries = self.vcdb_entries.filter(apply_filter)
            self.nvd_entries = self.nvd_entries.filter(apply_filter)

        per_page = 7
        vcdb_bookmarked_page = parse_pagination_param("vcdb_p")
        # Replace a sqlakeyset function to support our use case.
        # TODO: File a PR for this?
        sqlakeyset.paging.value_from_thing = custom_value_from_thing
        self.vcdb_pagination = get_page(self.vcdb_entries,
                                        per_page,
                                        page=vcdb_bookmarked_page)
        self.vcdb_pagination = VulnViewTypesetPaginationObjectWrapper(
            self.vcdb_pagination.paging)
        num_vuln_entries = db.session.query(func.count(
            Vulnerability.id)).scalar()
        self.vcdb_pagination.set_total(num_vuln_entries)

        nvd_bookmarked_page = parse_pagination_param("nvd_p")
        self.nvd_pagination = get_page(self.nvd_entries,
                                       per_page,
                                       page=nvd_bookmarked_page)
        self.nvd_pagination = VulnViewTypesetPaginationObjectWrapper(
            self.nvd_pagination.paging)
        num_nvd_entries = db.session.query(func.count(Nvd.id)).scalar()
        num_unique_nvd_estimate = num_nvd_entries - num_vuln_entries
        self.nvd_pagination.set_total(num_unique_nvd_estimate)
예제 #13
0
    def __init__(self):

        self.keyword = None
        # TODO: Look into neabling this once public contributions are enabled.
        # self.top_contributors = []
        # self.fetch_top_contributors()

        vcdb_entries = db.session.query(Vulnerability, Nvd)
        vcdb_entries = vcdb_entries.outerjoin(
            Nvd, Vulnerability.cve_id == Nvd.cve_id)
        vcdb_entries = vcdb_entries.options(default_nvd_view_options)
        vcdb_entries = vcdb_entries.order_by(
            asc(Vulnerability.date_created), desc(Vulnerability.id))
        self.vcdb_entries = vcdb_entries

        nvd_entries = db.session.query(Nvd)
        nvd_entries = nvd_entries.outerjoin(Vulnerability,
                                            Nvd.cve_id == Vulnerability.cve_id)
        nvd_entries = nvd_entries.options(default_nvd_view_options)
        nvd_entries = nvd_entries.filter(Vulnerability.cve_id.is_(None))
        nvd_entries = nvd_entries.order_by(
            desc(Nvd.published_date), desc(Nvd.id))
        self.nvd_entries = nvd_entries

        self.keyword = request.args.get("keyword", None, type=str)

        apply_filter = None
        if self.keyword:
            # TODO: Make the filtering work with fulltext search as well.
            if VulnerabilityDetails.is_cve_id(self.keyword):
                apply_filter = or_(False, Nvd.cve_id == self.keyword)
            elif VulnerabilityDetails.is_vcdb_id(self.keyword):
                apply_filter = or_(False, Vulnerability.id == self.keyword)
            else:
                escaped_keyword = self.keyword.replace("%", "")
                # escaped_keyword = re.sub('[\W]+', ' ', self.keyword)
                # Attention: We can't use FullText search here because of some buggy
                # Mysql 5.7 behavior (using FullText on Join results seems is doing bad
                # things. We might need to apply the filter before joining below.
                # apply_filter = or_(
                #     FullTextSearch(escaped_keyword, Nvd, FullTextMode.BOOLEAN),
                #     FullTextSearch(escaped_keyword, Vulnerability, FullTextMode.BOOLEAN))
                apply_filter = or_(
                    Nvd.descriptions.any(
                        Description.value.like("%" + escaped_keyword + "%")),
                    Vulnerability.comment.like("%" + escaped_keyword + "%"),
                )

            # TODO: add product search support.
            # apply_filter = or_(apply_filter, Cpe.product == keyword)

        if apply_filter is not None:
            self.vcdb_entries = self.vcdb_entries.filter(apply_filter)
            self.nvd_entries = self.nvd_entries.filter(apply_filter)

        per_page = 7
        vcdb_page = request.args.get("vcdb_p", 1, type=int)
        self.vcdb_pagination = self.vcdb_entries.paginate(
            vcdb_page, per_page=per_page)
        self.vcdb_pagination = VulnViewSqlalchemyPaginationObjectWrapper(
            self.vcdb_pagination)

        def filter_pagination_param(param):
            filtered = re.sub('[^a-zA-Z\d\- <>:~]', '', param)
            return filtered

        nvd_bookmarked_page = request.args.get('nvd_p', None)
        if nvd_bookmarked_page:
            nvd_bookmarked_page = filter_pagination_param(nvd_bookmarked_page)
            nvd_bookmarked_page = unserialize_bookmark(nvd_bookmarked_page)

        self.nvd_pagination = get_page(
            self.nvd_entries, per_page, page=nvd_bookmarked_page)
        self.nvd_pagination = VulnViewTypesetPaginationObjectWrapper(
            self.nvd_pagination.paging)
        num_nvd_entries = db.session.query(Nvd).count()
        num_vuln_entries = db.session.query(Vulnerability).count()
        num_unique_nvd_estimate = num_nvd_entries - num_vuln_entries
        self.nvd_pagination.set_total(num_unique_nvd_estimate)