예제 #1
0
def show_generated_advisory(advisory_id, raw=False):
    entries = (db.session.query(Advisory, CVEGroup, CVEGroupPackage, CVE)
               .filter(Advisory.id == advisory_id)
               .join(CVEGroupPackage).join(CVEGroup).join(CVEGroupEntry).join(CVE)
               .order_by(CVE.id)
               ).all()
    if not entries:
        return not_found()

    advisory = entries[0][0]
    group = entries[0][1]
    package = entries[0][2]
    issues = sorted([issue for (advisory, group, package, issue) in entries])
    severity_sorted_issues = sorted(issues, key=lambda issue: issue.issue_type)
    severity_sorted_issues = sorted(severity_sorted_issues, key=lambda issue: issue.severity)

    remote = any([issue.remote is Remote.remote for issue in issues])
    issues_listing_formatted = (('\n{}'.format(' ' * len('CVE-ID  : ')))
                                .join(list(map(' '.join, chunks([issue.id for issue in issues], 4)))))
    link = TRACKER_ADVISORY_URL.format(advisory.id, group.id)
    upstream_released = group.affected.split('-')[0].split('+')[0] != group.fixed.split('-')[0].split('+')[0]
    upstream_version = group.fixed.split('-')[0].split('+')[0]
    if ':' in upstream_version:
        upstream_version = upstream_version[upstream_version.index(':') + 1:]
    unique_issue_types = []
    for issue in severity_sorted_issues:
        if issue.issue_type not in unique_issue_types:
            unique_issue_types.append(issue.issue_type)

    references = []
    if group.bug_ticket:
        references.append(TRACKER_BUGTRACKER_URL.format(group.bug_ticket))
    references.extend([ref for ref in multiline_to_list(group.reference)
                       if ref not in references])
    list(map(lambda issue: references.extend(
        [ref for ref in multiline_to_list(issue.reference) if ref not in references]), issues))

    raw_asa = render_template('advisory.txt',
                              advisory=advisory,
                              group=group,
                              package=package,
                              issues=issues,
                              remote=remote,
                              issues_listing_formatted=issues_listing_formatted,
                              link=link,
                              workaround=advisory.workaround,
                              impact=advisory.impact,
                              upstream_released=upstream_released,
                              upstream_version=upstream_version,
                              unique_issue_types=unique_issue_types,
                              references=references,
                              TRACKER_ISSUE_URL=TRACKER_ISSUE_URL,
                              TRACKER_GROUP_URL=TRACKER_GROUP_URL)
    if raw:
        return raw_asa

    raw_asa = '\n'.join(raw_asa.split('\n')[2:])
    raw_asa = str(escape(raw_asa))
    raw_asa = advisory_extend_html(raw_asa, issues, package)
    return render_html_advisory(advisory=advisory, package=package, group=group, raw_asa=raw_asa, generated=True)
예제 #2
0
def get_bug_data(cves, pkgs, versions, group):
    references = []
    references = [
        ref for ref in multiline_to_list(group.reference)
        if ref not in references
    ]
    list(
        map(
            lambda issue: references.extend([
                ref for ref in multiline_to_list(issue.reference)
                if ref not in references
            ]), cves))

    severity_sorted_issues = sorted(cves, key=lambda issue: issue.issue_type)
    severity_sorted_issues = sorted(severity_sorted_issues,
                                    key=lambda issue: issue.severity)
    unique_issue_types = []
    for issue in severity_sorted_issues:
        if issue.issue_type not in unique_issue_types:
            unique_issue_types.append(issue.issue_type)

    bug_desc = render_template('bug.txt',
                               cves=cves,
                               group=group,
                               references=references,
                               pkgs=pkgs,
                               unique_issue_types=unique_issue_types,
                               TRACKER_ISSUE_URL=TRACKER_ISSUE_URL,
                               TRACKER_GROUP_URL=TRACKER_GROUP_URL)
    pkg_str = ' '.join((pkg.pkgname for pkg in pkgs))
    group_type = 'multiple issues' if len(
        unique_issue_types) > 1 else unique_issue_types[0]
    summary = '[{}] [Security] {} ({})'.format(
        pkg_str, group_type, ' '.join([cve.id for cve in cves]))

    if TRACKER_SUMMARY_LENGTH_MAX != 0 and len(
            summary) > TRACKER_SUMMARY_LENGTH_MAX:
        summary = "[{}] [Security] {} (Multiple CVE's)".format(
            pkg_str, group_type)

    # 5: critical, 4: high, 3: medium, 2: low, 1: very low.
    severitiy_mapping = {
        'unknown': 3,
        'critical': 5,
        'high': 4,
        'medium': 3,
        'low': 2,
    }

    task_severity = severitiy_mapping.get(group.severity.name)
    project = get_bug_project((pkg.database for pkg in versions))

    return {
        'project': project,
        'product_category': 13,  # security
        'item_summary': summary,
        'task_severity': task_severity,
        'detailed_desc': bug_desc
    }
예제 #3
0
 def __call__(self, form, field):
     pkgnames = set(multiline_to_list(field.data))
     pkgbases = db.session.query(Package) \
         .filter(Package.name.in_(pkgnames)) \
         .group_by(Package.base).all()
     pkgbases = [pkg.base for pkg in pkgbases]
     if len(pkgbases) > 1:
         self.fail(', '.join(pkgbases))
예제 #4
0
 def __call__(self, form, field):
     pkgnames = set(multiline_to_list(field.data))
     for pkgname in pkgnames:
         if not match(pkgname_regex, pkgname):
             self.fail(pkgname)
     db_packages = db.session.query(Package) \
         .filter(Package.name.in_(pkgnames)) \
         .group_by(Package.name).all()
     db_packages = set([pkg.name for pkg in db_packages])
     diff = [pkg for pkg in pkgnames if pkg not in db_packages]
     if hasattr(form, 'packages'):
         diff = [pkg for pkg in diff if pkg not in form.packages]
     for pkgname in diff:
         self.fail(pkgname)
예제 #5
0
def add_group():
    form = GroupForm()
    if not form.validate_on_submit():
        return render_template('form/group.html',
                               title='Add AVG',
                               form=form,
                               CVEGroup=CVEGroup)

    issue_ids = multiline_to_list(form.cve.data)
    issue_ids = set(filter(lambda s: s.startswith('CVE-'), issue_ids))

    existing_issues = CVE.query.filter(CVE.id.in_(issue_ids)).all()
    existing_issue_ids = [issue.id for issue in existing_issues]

    pkgnames = multiline_to_list(form.pkgnames.data)

    # check if a package with a CVE clashes with an existing group
    if not form.force_creation.data:
        same_group = (db.session.query(CVEGroup, CVE, CVEGroupPackage).join(
            CVEGroupEntry, CVEGroup.issues).join(CVE, CVEGroupEntry.cve).join(
                CVEGroupPackage, CVEGroup.packages).filter(
                    CVEGroupPackage.pkgname.in_(pkgnames)))
        if issue_ids:
            same_group = same_group.filter(CVE.id.in_(issue_ids))
        same_group = same_group.all()
        if same_group:
            for group, cve, package in same_group:
                flash(
                    ERROR_GROUP_WITH_ISSUE_EXISTS.format(
                        group.id, cve.id, package.pkgname), 'warning')
            return render_template('form/group.html',
                                   title='Add AVG',
                                   form=form,
                                   CVEGroup=CVEGroup,
                                   show_force_creation=True)

    for cve_id in list(
            filter(lambda issue: issue not in existing_issue_ids, issue_ids)):
        cve = db.create(CVE, id=cve_id)
        existing_issues.append(cve)
        flash('Added {}'.format(cve.id))

    fixed = form.fixed.data
    affected = Affected.fromstring(form.status.data)
    status = affected_to_status(affected, pkgnames[0], fixed)
    severity = highest_severity([issue.severity for issue in existing_issues])
    advisory_qualified = form.advisory_qualified.data and status is not Status.not_affected

    group = db.create(CVEGroup,
                      affected=form.affected.data,
                      status=status,
                      fixed=fixed,
                      bug_ticket=form.bug_ticket.data,
                      reference=form.reference.data,
                      notes=form.notes.data,
                      severity=severity,
                      advisory_qualified=advisory_qualified)

    for cve in existing_issues:
        db.create(CVEGroupEntry, group=group, cve=cve)

    for pkgname in pkgnames:
        db.get_or_create(CVEGroupPackage, pkgname=pkgname, group=group)
        flash('Added {}'.format(pkgname))

    db.session.commit()
    flash('Added {}'.format(group.name))
    return redirect('/{}'.format(group.name))
예제 #6
0
def edit_group(avg):
    group_id = avg.replace('AVG-', '')
    group_data = (db.session.query(CVEGroup, CVE, func.group_concat(CVEGroupPackage.pkgname, ' '), Advisory)
                  .filter(CVEGroup.id == group_id)
                  .join(CVEGroupEntry, CVEGroup.issues)
                  .join(CVE, CVEGroupEntry.cve)
                  .join(CVEGroupPackage, CVEGroup.packages)
                  .outerjoin(Advisory, Advisory.group_package_id == CVEGroupPackage.id)
                  .group_by(CVEGroup.id).group_by(CVE.id).group_by(CVEGroupPackage.pkgname)
                  .order_by(CVE.id)).all()
    if not group_data:
        return not_found()

    group = group_data[0][0]
    issues = set([cve for (group, cve, pkg, advisory) in group_data])
    issue_ids = set([cve.id for cve in issues])
    pkgnames = set(chain.from_iterable([pkg.split(' ') for (group, cve, pkg, advisory) in group_data]))
    advisories = set(advisory for (group, cve, pkg, advisory) in group_data if advisory)

    if not user_can_edit_group(advisories):
        return forbidden()

    form = GroupForm(pkgnames)
    if not form.is_submitted():
        form.affected.data = group.affected
        form.fixed.data = group.fixed
        form.pkgnames.data = "\n".join(sorted(pkgnames))
        form.status.data = status_to_affected(group.status).name
        form.reference.data = group.reference
        form.notes.data = group.notes
        form.bug_ticket.data = group.bug_ticket
        form.advisory_qualified.data = group.advisory_qualified and group.status is not Status.not_affected

        issue_ids = sorted(issue_ids, key=issue_to_numeric)
        form.cve.data = "\n".join(issue_ids)
    if not form.validate_on_submit():
        if advisories:
            flash('WARNING: This is referenced by an already published advisory!', 'warning')
        return render_template('form/group.html',
                               title='Edit {}'.format(avg),
                               form=form,
                               CVEGroup=CVEGroup)

    pkgnames_edited = multiline_to_list(form.pkgnames.data)
    group.affected = form.affected.data
    group.fixed = form.fixed.data
    group.status = affected_to_status(Affected.fromstring(form.status.data), pkgnames_edited[0], group.fixed)
    group.bug_ticket = form.bug_ticket.data
    group.reference = form.reference.data
    group.notes = form.notes.data
    group.advisory_qualified = form.advisory_qualified.data and group.status is not Status.not_affected

    cve_ids = multiline_to_list(form.cve.data)
    cve_ids = set(filter(lambda s: s.startswith('CVE-'), cve_ids))
    issues_removed = set(filter(lambda issue: issue not in cve_ids, issue_ids))
    issues_added = set(filter(lambda issue: issue not in issue_ids, cve_ids))
    issues_final = set(filter(lambda issue: issue.id not in issues_removed, issues))
    issues_changed = any(issues_added) or any(issues_removed)

    # remove old issues
    for issue in filter(lambda issue: issue.cve_id in issues_removed, list(group.issues)):
        group.issues.remove(issue)
        flash('Removed {}'.format(issue.cve_id))

    # add new issues
    severities = [issue.severity for issue in list(filter(lambda issue: issue.id not in issues_removed, issues))]
    for cve_id in issues_added:
        # TODO check if we can avoid this by the latter append call
        cve = db.get(CVE, id=cve_id)
        if not cve:
            cve = CVE.new(id=cve_id)
        db.get_or_create(CVEGroupEntry, group=group, cve=cve)
        flash('Added {}'.format(cve.id))

        severities.append(cve.severity)
        issues_final.add(cve)
    group.severity = highest_severity(severities)

    pkgnames_removed = set(filter(lambda pkgname: pkgname not in pkgnames_edited, pkgnames))
    pkgnames_added = set(filter(lambda pkgname: pkgname not in pkgnames, pkgnames_edited))
    pkgnames_changed = any(pkgnames_removed) or any(pkgnames_added)

    # remove old packages
    for pkg in filter(lambda pkg: pkg.pkgname in pkgnames_removed, list(group.packages)):
        group.packages.remove(pkg)
        flash('Removed {}'.format(pkg.pkgname))

    #  add new packages
    for pkgname in pkgnames_added:
        db.get_or_create(CVEGroupPackage, pkgname=pkgname, group=group)
        flash('Added {}'.format(pkgname))

    # update scheduled advisories
    for advisory in advisories:
        if Publication.published == advisory.publication:
            continue
        issue_type = 'multiple issues' if len(set([issue.issue_type for issue in issues_final])) > 1 else next(iter(issues_final)).issue_type
        advisory.advisory_type = issue_type

    # update changed date on modification
    if pkgnames_changed or issues_changed or db.session.is_modified(group):
        group.changed = datetime.utcnow()
        flash('Edited {}'.format(group.name))

    db.session.commit()
    return redirect('/{}'.format(group.name))
예제 #7
0
 def __call__(self, form, field):
     urls = multiline_to_list(field.data)
     for url in urls:
         if not self.regex.match(url):
             self.fail(url)
예제 #8
0
 def __call__(self, form, field):
     issues = multiline_to_list(field.data)
     for issue in issues:
         if not match(cve_id_regex, issue):
             self.fail(issue)