示例#1
0
    def test_json_schema_severities(self):
        v = 'CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L/E:P/CR:L/IR:L/AR:L/MAV:P'
        json = CVSS3(v).as_json()

        self.assertEqual(json['baseSeverity'], "HIGH")
        self.assertEqual(json['temporalSeverity'], "MEDIUM")
        self.assertEqual(json['environmentalSeverity'], "LOW")
示例#2
0
 def test_parse_from_text_both_versions(self):
     v1 = 'CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H'
     v2 = 'AV:N/AC:L/Au:N/C:C/I:C/A:C'
     i = 'xxx. ' + v1 + ' ' + v2 + '. xxx'
     e = set()
     e.add(CVSS3(v1))
     e.add(CVSS2(v2))
     self.assertEqual(set(parser.parse_cvss_from_text(i)), e)
示例#3
0
    def test_clean_vector(self):
        """
        Tests for cleaning-up vector, where fields are not in order or some fields have X values.
        """
        v = 'CVSS:3.0/S:C/C:H/I:H/A:N/AV:P/AC:H/PR:H/UI:R/E:H/RL:O/RC:R/CR:H/IR:X/AR:X/MAC:H/MPR:X/MUI:X/MC:L/MA:X'
        self.assertEqual(
            'CVSS:3.0/AV:P/AC:H/PR:H/UI:R/S:C/C:H/I:H/A:N/E:H/RL:O/RC:R/CR:H/MAC:H/MC:L',
            CVSS3(v).clean_vector())

        v = 'CVSS:3.0/AV:A/AC:H/PR:H/UI:R/S:U/C:N/I:L/A:N/E:P/RC:C/MAV:N/MPR:H/MUI:X/MS:U/MI:X'
        self.assertEqual(
            'CVSS:3.0/AV:A/AC:H/PR:H/UI:R/S:U/C:N/I:L/A:N/E:P/RC:C/MAV:N/MPR:H/MS:U',
            CVSS3(v).clean_vector())

        v = 'CVSS:3.0/A:N/E:P/RC:C/MAV:N/AV:A/AC:H/S:U/C:N/I:L/MPR:H/MUI:X/MS:U/MI:X/PR:H/UI:R'
        self.assertEqual(
            'CVSS:3.0/AV:A/AC:H/PR:H/UI:R/S:U/C:N/I:L/A:N/E:P/RC:C/MAV:N/MPR:H/MS:U',
            CVSS3(v).clean_vector())
示例#4
0
    def test_parse_from_text_optional_sentence_cases(self):
        # Missing space after end of sentence and before vector
        v = 'CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H'
        i = '.' + v
        e = [CVSS3(v)]
        self.assertEqual(parser.parse_cvss_from_text(i), e)

        # End of sentence
        v = 'CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H'
        i = v + '.'
        e = [CVSS3(v)]
        self.assertEqual(parser.parse_cvss_from_text(i), e)

        # Missing space after dot before vector
        v = 'CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H'
        i = 'xxx.' + v
        e = [CVSS3(v)]
        self.assertEqual(parser.parse_cvss_from_text(i), e)
示例#5
0
 def run_tests_from_file(self, test_name):
     with open(path.join(WD, test_name)) as f:
         for line in f:
             vector, expected_scores = line.split(' - ')
             expected_scores = expected_scores.replace('(', '').replace(
                 ')', '').split(', ')
             expected_scores = tuple(float(a) for a in expected_scores)
             result = CVSS3(vector)
             results_scores = result.scores()
             self.assertEqual(expected_scores, results_scores,
                              test_name + ' - ' + vector)
示例#6
0
 def run_rh_tests_from_file(self, test_name):
     with open(path.join(WD, test_name)) as f:
         for line in f:
             vector, expected_scores = line.split(' - ')
             expected_scores = expected_scores.replace('(', '').replace(
                 ')', '').strip().split(', ')
             expected_scores = tuple(
                 float(a) if a != 'None' else None for a in expected_scores)
             tested_rh_vector = str(expected_scores[0]) + '/' + vector
             result = CVSS3.from_rh_vector(tested_rh_vector)
             results_scores = result.scores()
             self.assertEqual(expected_scores, results_scores,
                              test_name + ' - ' + vector)
示例#7
0
 def test_json_ordering(self):
     vectors_to_schema = {
         'vectors_random3': 'schemas/cvss-v3.0.json',
         'vectors_random31': 'schemas/cvss-v3.1.json',
     }
     for vectors_file_path, schema_file_path in vectors_to_schema.items():
         with open(path.join(WD, vectors_file_path)) as f:
             for line in f:
                 vector, _ = line.split(' - ')
                 cvss = CVSS3(vector).as_json(sort=True)
                 old_key = ''
                 for key in cvss:
                     if key < old_key:
                         self.fail(
                             'dict ordering was not preserved: key {} less than previous key {} for CVSS object {}'
                             .format(key, old_key, cvss))
                     old_key = key
示例#8
0
 def test_json_schema_repr(self):
     try:
         import jsonschema
     except ImportError:
         return
     vectors_to_schema = {
         'vectors_random3': 'schemas/cvss-v3.0.json',
         'vectors_random31': 'schemas/cvss-v3.1.json',
     }
     for vectors_file_path, schema_file_path in vectors_to_schema.items():
         with open(path.join(WD, vectors_file_path)) as f:
             for line in f:
                 vector, _ = line.split(' - ')
                 cvss = CVSS3(vector)
                 with open(path.join(WD, schema_file_path)) as schema_file:
                     schema = json.load(schema_file)
                 try:
                     jsonschema.validate(instance=cvss.as_json(),
                                         schema=schema)
                 except jsonschema.exceptions.ValidationError:
                     self.fail('jsonschema validation failed on vector: {}'.
                               format(vector))
示例#9
0
 def test_parse_from_text_multiple_vectors_same_cvss(self):
     v = 'CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H'
     e = [CVSS3(v)]
     i = 'Title: {0}\nThis is an overview of {0} problem.\nLinks: {0}'.format(
         v)
     self.assertEqual(parser.parse_cvss_from_text(i), e)
示例#10
0
    def test_parse_from_text_cvss3(self):
        i = 'CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H'
        e = [CVSS3(i)]
        self.assertEqual(parser.parse_cvss_from_text(i), e)

        i = 'CVSS'
        e = []
        self.assertEqual(parser.parse_cvss_from_text(i), e)

        # Truncated vector
        i = 'CVSS:3'
        e = []
        self.assertEqual(parser.parse_cvss_from_text(i), e)

        i = 'CVSS:3.0'
        e = []
        self.assertEqual(parser.parse_cvss_from_text(i), e)

        i = 'CVSS:3.0/'
        e = []
        self.assertEqual(parser.parse_cvss_from_text(i), e)

        i = 'CVSS:3.0/AV:N'
        e = []
        self.assertEqual(parser.parse_cvss_from_text(i), e)

        i = 'CVSS:3.0/AV:X'
        e = []
        self.assertEqual(parser.parse_cvss_from_text(i), e)

        i = 'CVSS:3.0/AV:ZZZ'
        e = []
        self.assertEqual(parser.parse_cvss_from_text(i), e)

        i = 'CVSS:3.0/AV:L/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N/MAV:A/MAC:L/MPR:N/MUI:N/MS:U/MC:N/MI:N/MA:N'
        e = [CVSS3(i)]
        self.assertEqual(parser.parse_cvss_from_text(i), e)

        # Missing mandatory prefix
        i = 'AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:N'
        e = []
        self.assertEqual(parser.parse_cvss_from_text(i), e)

        v1 = 'CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H'
        v2 = 'CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N'
        i = ' '.join([v1, v2])
        e = set()
        e.add(CVSS3(v1))
        e.add(CVSS3(v2))
        self.assertEqual(set(parser.parse_cvss_from_text(i)), e)

        # Correct text
        v = 'CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H'
        i = 'xxx ' + v
        e = [CVSS3(v)]
        self.assertEqual(parser.parse_cvss_from_text(i), e)

        v = 'CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H'
        i = v + ' xxx'
        e = [CVSS3(v)]
        self.assertEqual(parser.parse_cvss_from_text(i), e)
示例#11
0
    def test_severities(self):
        """
        Tests for computing severities.
        """
        v = 'CVSS:3.0/AV:N/AC:H/PR:L/UI:N/S:C/C:N/I:N/A:N'
        self.assertEqual(('None', 'None', 'None'), CVSS3(v).severities(), v)

        v = 'CVSS:3.0/AV:P/AC:H/PR:L/UI:R/S:U/C:N/I:L/A:N'
        self.assertEqual(('Low', 'Low', 'Low'), CVSS3(v).severities(), v)

        v = 'CVSS:3.0/AV:N/AC:H/PR:L/UI:R/S:U/C:N/I:L/A:N'
        self.assertEqual(('Low', 'Low', 'Low'), CVSS3(v).severities(), v)

        v = 'CVSS:3.0/AV:N/AC:H/PR:L/UI:N/S:U/C:N/I:N/A:L'
        self.assertEqual(('Low', 'Low', 'Low'), CVSS3(v).severities(), v)

        v = 'CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:L'
        self.assertEqual(('Medium', 'Medium', 'Medium'),
                         CVSS3(v).severities(), v)

        v = 'CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:L'
        self.assertEqual(('Medium', 'Medium', 'Medium'),
                         CVSS3(v).severities(), v)

        v = 'CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:N'
        self.assertEqual(('Medium', 'Medium', 'Medium'),
                         CVSS3(v).severities(), v)

        v = 'CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L'
        self.assertEqual(('High', 'High', 'High'), CVSS3(v).severities(), v)

        v = 'CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:H'
        self.assertEqual(('High', 'High', 'High'), CVSS3(v).severities(), v)

        v = 'CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:L/A:N'
        self.assertEqual(('Critical', 'Critical', 'Critical'),
                         CVSS3(v).severities(), v)

        v = 'CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:H'
        self.assertEqual(('Critical', 'Critical', 'Critical'),
                         CVSS3(v).severities(), v)

        v = 'CVSS:3.0/AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H/E:P/RL:W/IR:M/AR:H/MAV:N/MAC:H/MPR:L/MUI:N/MC:N/MI:N'
        self.assertEqual(('High', 'High', 'Medium'), CVSS3(v).severities(), v)

        v = 'CVSS:3.0/AV:P/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:N/E:H/RC:U/CR:M/MAV:P/MAC:L/MUI:R/MC:N/MI:N'
        self.assertEqual(('Medium', 'Low', 'None'), CVSS3(v).severities(), v)
示例#12
0
    def get_item(self, vulnerability, test):

        # vulnerable and unaffected versions can be in string format for a single vulnerable version,
        # or an array for multiple versions depending on the language.
        if isinstance(vulnerability['semver']['vulnerable'], list):
            vulnerable_versions = ", ".join(
                vulnerability['semver']['vulnerable'])
        else:
            vulnerable_versions = vulnerability['semver']['vulnerable']

        # Following the CVSS Scoring per https://nvd.nist.gov/vuln-metrics/cvss
        if 'cvssScore' in vulnerability:
            # If we're dealing with a license finding, there will be no cvssScore
            if vulnerability['cvssScore'] <= 3.9:
                severity = "Low"
            elif vulnerability['cvssScore'] >= 4.0 and vulnerability[
                    'cvssScore'] <= 6.9:
                severity = "Medium"
            elif vulnerability['cvssScore'] >= 7.0 and vulnerability[
                    'cvssScore'] <= 8.9:
                severity = "High"
            else:
                severity = "Critical"
        else:
            # Re-assign 'severity' directly
            severity = vulnerability['severity'].title()

        # Construct "file_path" removing versions
        vulnPath = ''
        for index, item in enumerate(vulnerability['from']):
            if index == 0:
                vulnPath += "@".join(item.split("@")[0:-1])
            else:
                vulnPath += " > " + "@".join(item.split("@")[0:-1])

        # create the finding object
        finding = Finding(
            title=vulnerability['from'][0] + ": " + vulnerability['title'],
            test=test,
            severity=severity,
            severity_justification="Issue severity of: **" + severity +
            "** from a base " + "CVSS score of: **" +
            str(vulnerability.get('cvssScore')) + "**",
            description="## Component Details\n - **Vulnerable Package**: " +
            vulnerability['packageName'] + "\n- **Current Version**: " +
            str(vulnerability['version']) + "\n- **Vulnerable Version(s)**: " +
            vulnerable_versions + "\n- **Vulnerable Path**: " +
            " > ".join(vulnerability['from']) + "\n" +
            vulnerability['description'],
            mitigation=
            "A fix (if available) will be provided in the description.",
            component_name=vulnerability['packageName'],
            component_version=vulnerability['version'],
            false_p=False,
            duplicate=False,
            out_of_scope=False,
            impact=severity,
            static_finding=True,
            dynamic_finding=False,
            file_path=vulnPath,
            vuln_id_from_tool=vulnerability['id'],
        )

        # CVSSv3 vector
        if 'CVSSv3' in vulnerability:
            finding.cvssv3 = CVSS3(vulnerability['CVSSv3']).clean_vector()

        # manage CVE and CWE with idnitifiers
        cve_references = ''
        cwe_references = ''
        if 'identifiers' in vulnerability:
            if 'CVE' in vulnerability['identifiers']:
                cves = vulnerability['identifiers']['CVE']
                if cves:
                    # Per the current json format, if several CVEs listed, take the first one.
                    finding.cve = cves[0]
                    if len(cves) > 1:
                        cve_references = ', '.join(cves)

            if 'CWE' in vulnerability['identifiers']:
                cwes = vulnerability['identifiers']['CWE']
                if cwes:
                    # Per the current json format, if several CWEs, take the first one.
                    finding.cwe = int(cwes[0].split("-")[1])
                    if len(vulnerability['identifiers']['CVE']) > 1:
                        cwe_references = ', '.join(cwes)
                else:
                    finding.cwe = 1035

        references = ''
        if 'id' in vulnerability:
            references = "**SNYK ID**: https://app.snyk.io/vuln/{}\n\n".format(
                vulnerability['id'])

        if cve_references or cwe_references:
            references += "Several CVEs or CWEs were reported: \n\n{}\n{}\n".format(
                cve_references, cwe_references)

        # Append vuln references to references section
        for item in vulnerability.get('references', []):
            references += "**" + item['title'] + "**: " + item['url'] + "\n"

        finding.references = references

        finding.description = finding.description.strip()

        # Find remediation string limit indexes
        remediation_index = finding.description.find("## Remediation")
        references_index = finding.description.find("## References")

        # Add the remediation substring to mitigation section
        if (remediation_index != -1) and (references_index != -1):
            finding.mitigation = finding.description[
                remediation_index:references_index]

        return finding