cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
2880
Views
0
Helpful
0
Comments
AdvocateRick
Cisco Employee
Cisco Employee

I heard from our software consulting engineers that our customers would like a risk meter that scores CISA vulnerabilities. So here is my implementation.

First off, CISA stands for Cybersecurity & Infrastructure Security Agency.  You know it has to be secure with "security" twice in the name.  The CISA mission is to work with partners to defend against today’s threats and collaborates to build a more secure and resilient infrastructure for the future; and, lead the national effort to understand, manage, and reduce risk to our cyber and physical infrastructure.  It publishes a vulnerability catalog which can be obtained via an API endpoint.  Here are some reasons why the CISA catalog should be used.  If you're interested, there is a small stand-alone program to obtain the CISA vulnerability catalog, get_cisa_catalog.py.

Here is an outline of how I created a "CISA Risk Meter:"

  • Obtain the CISA vulnerability catalog labeled by a CVE ID.
  • Create a risk meter that has a CISA custom field criteria
  • For each CVE ID in the CISA catalog, find the Kenna (now Cisco) vulnerabilities associated with the CVE ID and mark the vulnerability's CISA custom field so a risk meter will pick it up.

The code for this blog is in blog_build_cisa_risk_meter.py; however, the latest code is at build_cisa_risk_meter.py.  And remember, a risk meter score is the vulnerability score of an asset group. The terms risk meter and asset group are used interchangeably.

Logging is used throughout the program.  The log is in the file cisa_vulns.log.  It is not cleared or managed, so you will have to clean it up from time to time.

Check for Custom Field

The first thing the program does is check to see if the "CISA" custom field is present in: check_for_custom_field() on line 65.  I was disappointed to discover that custom fields can only be created in the UI.  After a custom field is created, it is assigned a custom field ID and a none value.  This search can be skipped if the custom field ID is entered on the command line.

The "Search Vulnerabilities" API is used to filter all vulnerabilities with the CISA custom field with the value of none.  Search parameters are in the URL query parameters with the format:

custom_fields:<custom_field>[]=none, and for our CISA example: custom_fields:CISA[]=none

Here is the code:

 68     # Assemble the search URL.
 69     page_size_query = f"per_page={SEARCH_PAGE_SIZE}"
 70     custom_field_query = f"custom_fields:{custom_field}[]=none"
 71     search_url = f"{base_url}vulnerabilities/search?{page_size_query}&{custom_field_query}"

Note the return HTTP error codes.  Error code 422 means the CISA custom field is not present and needs to be created in the UI.

After error checking, the CISA custom field ID is obtained and returned. We only need the first vulnerability to obtain the custom field ID.

 97     # Return the CISA custom field ID based on the first vulnerability found with CISA custom field.
 98     vulns = resp_json['vulnerabilities']
 99     if len(vulns) == 0:
100         return 0
101     cisa_custom_field = get_custom_field(vulns[0], CISA_CUSTOM_FIELD_NAME)
102     return cisa_custom_field['custom_field_definition_id']

In the above code snippet, get_custom_field() for the vulnerability. This function runs through all the custom fields of a vulnerability looking for a custom field name in our case "CISA," and returns the CISA custom field or None. Finally, in line 102, the custom field ID is extracted and returned.

Get CISA catalog

After the "CISA" custom field ID is obtained, the CISA vulnerability catalog is fetched in get_cisa_catalog().  This function is straightforward, invoking the API endpoint, https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json 

  {
    "cveID": "CVE-2021-27102",
    "dateAdded": "2021-11-03",
    "dueDate": "2021-11-17",
    "product": "FTA",
    "requiredAction": "Apply updates per vendor instructions.",
    "shortDescription": "Accellion FTA 9_12_411 and earlier is affected by OS command execution via a local web service call.",
    "vendorProject": "Accellion",
    "vulnerabilityName": "Accellion FTA OS Command Injection Vulnerability"
  },

The catalog is returned.  Some fields are extracted for logging purposes, but the array of vulnerabilities is what we really want.  Later in the code, you'll see that for each CISA vulnerability, the CVE ID is used.  This CVE ID is the link between CISA vulnerabilities and Kenna (now Cisco) vulnerabilities.

Creating the CISA Risk Meter

As you may recall, risk meter creation was discussed in the blog, Automating Risk Meter Creation, where asset tags were used as criteria.  Here vulnerability custom fields are used as criteria.  But first, before a risk meter is created, the code checks to see if one already exists in get_a_risk_meter() by the name, "CISA Exploited Vulnerabilities."

Looking at get_a_risk_meter(), you'll see the code takes into account there can be more than 100 risk meters.  This is done by scanning through all the risk meter pages.

and returning the CISA vulnerabilities along with a vulnerability count and request ISO 8601 date.  Here is what one of the CISA vulnerabilities looks like:

175         page_size_query = f"per_page={RISK_METER_PAGE_SIZE}"
176         list_risk_meters_url = f"{base_url}asset_groups?{page_size_query}&page={page_num}"
177         logging.info(f"List risk meter URL: {list_risk_meters_url}")

Note that the page number is in the query parameters and the maximum page size for risk meters is 100.  If the risk meter is found, it is returned.  However, if the "CISA Exploited Vulnerabilities" are not found, the code creates one in create_risk_meter().

The salient point in: create_risk_meter() is the risk meter criteria.

206     vuln_custom_fields = f"custom_fields:{cisa_custom_field_id}:{CISA_CUSTOM_FIELD_NAME}"
207     create_data = {
208         "name": risk_meter_name,
209         "query": {
210             "status": [
211                 "active"
212             ],
213             "vulnerability": {
214                 vuln_custom_fields: [
215                     "any"
216                 ],
217                 "status": [
218                     "open"
219                 ]
220             }
221         }
222     }

The custom field key format which for me is custom_fields:8114:CISA.  This custom field key is located vulnerability array as an element with the value of any.  The vulnerability array also contains the vulnerability status key with the value of "open".  With the above risk meter criteria, the "Create Asset Group" API is invoked.

Search for CISA Vulnerabilities

Now with a risk meter in hand, it is time to run through all the CISA vulnerabilities and see what Kenna (now Cisco) vulnerabilities are associated with each CISA vulnerability.  As stated early, CISA vulnerabilities are unique by CVE ID.

305     print(f"Search vulnerabilities associated with CISA CVE IDs")
306     for cisa_vuln in cisa_vulns:
307         cisa_cve_id = cisa_vuln['cveID']
308 
309         # Search for vulns associated with the CVE ID.
310         cve_vulns = search_vulns_for_cve_id(base_url, headers, cisa_cve_id)
311         print(".",  end='', flush=True)
312 
313         # Check in CISA custom field is assiocated with each vulnerability.
314         # If not, add it to the list.
315         # If the number of vulnerabilities is over the update limit, do a bulk update.
316         for cve_vuln in cve_vulns:
317             if not custom_field_is_set(cve_vuln, CISA_CUSTOM_FIELD_NAME):
318                 cve_vuln_id = cve_vuln['id']
319                 logging.info(f"Add Vuln ID {cve_vuln_id} to custom field update list")
320                 vulns_to_update.append(cve_vuln_id)
321                 if len(vulns_to_update) > VULN_UPDATE_LIMIT:
322                     update_cisa_vulns(base_url, headers, vulns_to_update, cisa_custom_field_id)
323                     logging.info(f"Updated CISA custom field for {len(vulns_to_update)} vulns")
324                     vulns_updated += len(vulns_to_update)
325                     vulns_to_update.clear()

The outer loop at line 386 goes through each CISA vulnerability. On line 310, the "Search Vulnerability" API is invoked with the search criteria being the CVE-ID. An array of Kenna (now Cisco) vulnerabilities is returned.

The inner loop at line 316 goes through each Kenna (now Cisco) vulnerability for the CISA vulnerability.  In this loop, the existence of the "CISA" custom field is checked.  If the custom field for the vulnerability does not exist, the vulnerability ID is added to the vulns_to_update array in line 320.

When the length of vulns_to_update becomes 5000 or greater,  all the vulnerabilities in: vulns_to_update are updated with the CISA custom field with the "Bulk Update Vulnerabilities" API.  If there are any vulnerabilities to be updated after running through the loops, a final vulnerability bulk update is invoked in line 329.

Bulk Vulnerabilities Update

The Bulk Update Vulnerabilities is used to set the "CISA" custom fields for the vulnerabilities that are associated with the CVE IDs from the CISA catalog to a "true" value.  Remember that custom field values can only be strings or dates.

150     bulk_update_url = f"{base_url}vulnerabilities/bulk"
151     update_custom_field_id = f"{custom_field_id}"
152     update_data = {
153         "vulnerability_ids": vuln_ids,
154         "vulnerability": {
155             "custom_fields": {
156                 update_custom_field_id: "true"
157             }
158         }
159     }

Here the update_custom_field_id is composed only of the custom field ID.

Conclusion

Here is the output of the program:

Build CISA Exploited Vulnerabilities Risk Meter

400329 vulnerabilities with CISA custom field.
Search vulnerabilities associated with CISA CVE IDs
......................................................................................
......................................................................................
......................................................................................
......................................................................................
......................................................................................
......................................................................................
.....................................................................................
.........
CISA Exploited Vulnerabilities created with 1577 vulnerabilities updated.

This run took approximately 7.5 minutes.  Each . represents a search for vulnerabilities associated with a CISA CVE ID.

I hope this program helps with vulnerability risk management and provides you with a clear indication of which vulnerabilities are associated with the CISA catalog along with a risk score.

I would like to thank Jared Kalmus for his assistance and suggestions.  As you may have noticed, most of the functions have been written with re-usability in mind.  For example, check_for_custom_fields() has a custom field parameter instead of hardcoding "CISA" in the function.  As always this code is in Kenna Security’s GitHub repository.

Until next time,

Rick Ehrhart - Apr 5, 2022

API Evangelist

This blog was originally written for Kenna Security, which has been acquired by Cisco Systems.
Learn more about Cisco Vulnerability Management.

Getting Started

Find answers to your questions by entering keywords or phrases in the Search bar above. New here? Use these resources to familiarize yourself with the community: