Security Center

Managed on-premises, the Tenable Security Center suite of products provides the industry's most comprehensive vulnerability coverage with real-time continuous assessment of your network. It's your complete end-to-end vulnerability management solution.

Validation Criteria

Your integration with Security Center should meet the following criteria:

  • Ensure that all API calls made by your integration uses a standard User-Agent string as described in the User-Agent Header guide. This helps Tenable to identify your integration's API calls to assist with debugging and troubleshooting.
  • Contact Tenable via the Tech Alliances Application to demonstrate your third-party integration with Tenable's product or platform.
  • Explain how your integration uses Tenable's API and the specific endpoints that are being utilized. Tenable may ask to look at your integration's code to ensure scalability and to suggest best practices.
  • Ensure that your integration uses the proper naming conventions, trademarks, and logos in your integration's user interface. You can download a Media Kit on Tenable's media page.

Data Model

Security Center has multiple types of repositories or databases each with a different understanding of how to construct a composite key for a finding. The hostUniqueness attribute is used to determine which attributes were used to determine a unique host for the repository that the finding resides within. The attributes from hostUniqueness in combination with the port, protocol, and pluginID attributes define a unique finding.

The following diagram illustrates the relationships between these three data types.

Security Center Data Model

Several plugins can detect vulnerabilities on several assets, and a single plugin might detect vulnerabilities on the same asset but on different ports, so you can only uniquely identify a single finding by using a composite key (as shown in the data model diagram) with these fields:

  • hostUniqueness (use attribute values listed)
  • pluginID
  • port
  • protocol

Data Exports

Tenable Security Center integrations are powered by the same API as the user interface. Due to this lack of an asynchronous API to pull data from, you should be careful how you extract data from the platform since it's possible to significantly impact the performance of the Security Center console. You can use the analysis API to export vulnerability findings from Security Center. The analysis API is a synchronous, paginated API that pulls data from the underlying data repositories.

A high-level workflow for exporting data from Security Center is illustrated in the following diagram.

Security Center Export Flow

Requests to the analysis API include three items:

  1. Data Type & Source—The type of data being exported (cumulative data, individual scans, mobile data, etc.). The most commonly used values are as follows:
    • Type
      • vuln—For vulnerability and compliance findings.
    • SourceTypes
      • cumulative—For current active vulnerability data (stateful).
      • patched—For fixed or remediated vulnerability data (stateful).
      • individual—For singular scan results (not _stateful).
  2. Visibility Tool—Determines how the data should be summarized (if at all). The tool informs Security Center what level of summarization you want from the data. Typically, for most data exports, you should avoid summarization and opt for raw data. Tenable recommends using the vulndetails tool for the majority of cases.
  3. Filters—Determines the subset of the information to include in the export. Security Center has powerful filtering capabilities, covering everything from asset groups, finding specifics, to temporal state, and vulnerability plugin specifics. Leverage the Query API to use a predetermined filter set, and then augment that filter set with known filters like temporal filters. If you follow the recommendation of fetching a predetermined filter set from the query API, then you only need to consider the following filters:
    • lastSeen (temporal, source: cumulative)—Filters the results by the last time a scan observed the vulnerability.
    • lastMitigated (temporal, source: patched)—Filters the results by the time in which a vulnerability was observed as fixed, patched, or remediated.

Note that temporal filters can be used in several ways, the most common are:

  • Temporal Delta:—Filters the results by calendar days. The format is NUM:NUM where each number represents the number of calendar days in the past. For example, 0:30 equates to "30 days ago to today." The user interface typically defaults to this style.
  • Unix Timestamp—Filters the results by Unix timestamp. This is the most commonly used format for large-scale exports. The format is NUM-NUM (note the dash instead of a colon) where each number is a Unix timestamp. Note that the order in which the numbers are used is reversed from the previous example. The first number is the oldest time and the second number is the newest. For example, 1668961007-1671552959 equates to "from Nov 20, 2022 at 16:16:47 to Dec 20, 2022 at 16:15:59."

For an exhaustive list of the supported data types and supported filters, refer to the Query Data Types detailed within the Query POST API.

Additionally, Tenable recommends a page size between 2000 to 10000 for the pagination of export data from Security Center. If the page size is too large the Security Center console might not be able to field the request since it first constructs the page in memory before sending the response. If the page size is too small, Security Center experience additional churn on the system as it pulls data from the various repositories and it takes a long time to return the entire dataset.

Export Asset Data

To export asset data, you can use the built-in sumip tool to query the Tenable Security Center API for asset details.

For example, to export asset data, you could use the following request:

POST /rest/analysis
{
    "type": "vuln",
    "sourceType": "cumulative",
    "query": {
        "tool": "sumip",
        "type": "vuln",
        "filters": [],
        "startOffset": 0,
        "endOffset": 5000
    }
}

The same request using pyTenable:

from tenable.sc import TenableSC

tsc = TenableSC(url='https://sc-instance', access_key='abc', secret_key='def')

assets = tsc.analysis.vulns(tool='sumip')

The response for the asset objects returned by the request is in the following format:

{
    "acrScore": "7.0",
    "assetExposureScore": "0",
    "biosGUID": "",
    "dnsName": "",
    "hostUUID": "",
    "hostUniqueness": "repositoryID,ip,dnsName",
    "ip": "0.0.11.39",
    "keyDrivers": "{\"internet exposure\":\"internal\",\"device capability\":\"\",\"device type\":\"network_switch\"}",
    "lastAuthRun": "",
    "lastUnauthRun": "1663044810",
    "macAddress": "00:00:00:5a:6e:3e",
    "mcafeeGUID": "",
    "netbiosName": "",
    "osCPE": "cpe:/o:Arista:EOS",
    "pluginSet": "202209121748",
    "policyName": "Basic Network Scan",
    "repository": {
        "dataFormat": "IPv4",
        "description": "",
        "id": "2",
        "name": "Staged-Large"
    },
    "score": "10",
    "severityCritical": "0",
    "severityHigh": "0",
    "severityInfo": "43",
    "severityLow": "1",
    "severityMedium": "3",
    "total": "47",
    "tpmID": "",
    "uniqueness": "repositoryID,ip,dnsName",
    "uuid": "8040dcf3-3fa6-44a7-89a3-770bff34ef0c"
}

Some relevant fields in the response are:

  • hostUniqueness—The field names that Tenable Security Center used to determine that the host is unique. You can use the field names listed here to reconstruct the uniqueness value.
  • lastAuthRun—The Unix timestamp of the last authenticated scan against the host.
  • lastUnauthRun—The Unix timestamp of the last unauthenticated scan against the host.
  • osCPE—The operating system of the host in CPE format.
  • acrScore—The ACR (Asset Criticality Score) score of the host.
  • assetExposureScore—The AES (Asset Exposure Score) of the host.
  • score—The score of the asset based on the findings on the asset. Note that this value is calculated based on the current view and filters.
  • severity<SEVERITY>—The number of vulnerability findings at each of the criticality levels. Note that these values are calculated based on the current view and filters.
  • uuid—The UUID (if available) of the agent associated with the asset.
  • hostUUID—The internal UUID of the host (universal repositories only).

Export Vulnerability Findings

To export vulnerability findings from Tenable Security Center, it's recommended to first perform an initial sync of the data and then to export temporal deltas thereafter. Additionally, for most use cases, you should exclude informational plugins.

For the initial sync, you could use the following request:

POST /rest/analysis
{
    "type": "vuln",
    "sourceType": "cumulative",
    "query": {
        "tool": "vulndetails",
        "type": "vuln",
        "filters": [
            {
                "filterName": "severity",
                "operator": "=",
                "value": "1,2,3,4"
            },
            {
                "filterName": "wasVuln",
                "operator": "=",
                "value": "excludeWas"
            }
        ],
        "startOffset": 0,
        "endOffset": 2000
    }
}

The same request using pyTenable:

from tenable.sc import TenableSC

tsc = TenableSC(url='https://sc-instance', access_key='abc', secret_key='def')

findings = tsc.analysis.vulns(('severity', '=', '1,2,3,4'))

Next, for the temporal deltas, you should make two separate series of requests. One request for the cumulative (open) findings and a second request for the patched (closed/fixed) findings. Additionally, you should invoke the wasVuln filter and set it to excludeWas to exclude WAS results. The proper way to retrieve Tenable Web App Scanning (WAS) data is explained here.

For example, to export the temporal delta for cumulative (open) findings, you could use the following request:

POST /rest/analysis
{
    "type": "vuln",
    "sourceType": "cumulative",
    "query": {
        "tool": "vulndetails",
        "type": "vuln",
        "filters": [
            {
                "filterName ": "lastSeen",
                "operator ": "=",
                "value": "0:1"
            },
            {
                "filterName": "severity",
                "operator": "=",
                "value": "1,2,3,4"
            },
            {
                "filterName": "wasVuln",
                "operator": "=",
                "value": "excludeWas"
            }
        ],
        "startOffset": 0,
        "endOffset": 2000
    }
}

To Export the temporal delta for patched (closed/fixed) findings, you could use the following request:

POST /rest/analysis
{
    "type": "vuln",
    "sourceType": "patched",
    "query": {
        "tool": "vulndetails",
        "type": "vuln",
        "filters": [
            {
                "filterName ": "lastMitigated",
                "operator ": "=",
                "value": "0:1"
            },
            {
                "filterName": "severity",
                "operator": "=",
                "value": "1,2,3,4"
            },
            {
                "filterName": "wasVuln",
                "operator": "=",
                "value": "excludeWas"
            }
        ],
        "startOffset": 0,
        "endOffset": 2000
    }
}

The two requests can be combined if using pyTenable:

from tenable.sc import TenableSC

tsc = TenableSC(url='https://sc-instance', access_key='abc', secret_key='def')

findings = tsc.analysis.vulns(('severity', '=', '1,2,3,4'),
                              ('lastSeen', '=', '0:1')
                              )
closed_findings = tsc.analysis.vulns(('severity', '=', '1,2,3,4'),
                                     ('lastMitigated', '=', '0:1')
                                     )

The response looks like the following:

{
    "acceptRisk": "0",
    "acceptRiskRuleComment": "",
    "acrScore": "4.0",
    "assetExposureScore": "563",
    "baseScore": "10.0",
    "bid": "",
    "checkType": "local",
    "cpe": "p-cpe:/a:centos:centos:curl<br/>p-cpe:/a:centos:centos:libcurl<br/>p-cpe:/a:centos:centos:libcurl-devel<br/>cpe:/o:centos:centos:7",
    "cve": "CVE-2018-14618",
    "cvssV3BaseScore": "9.8",
    "cvssV3TemporalScore": "8.5",
    "cvssV3Vector": "AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H/E:U/RL:O/RC:C",
    "cvssVector": "AV:N/AC:L/Au:N/C:C/I:C/A:C/E:U/RL:OF/RC:C",
    "description": "An update for curl is now available for Red Hat Enterprise Linux 7.\n\nRed Hat Product Security has rated this update as having a security impact of Low. A Common Vulnerability Scoring System (CVSS) base score, which gives a detailed severity rating, is available for each vulnerability from the CVE link (s) in the References section.\n\nThe curl packages provide the libcurl library and the curl utility for downloading files from servers using various protocols, including HTTP, FTP, and LDAP.\n\nSecurity Fix(es) :\n\n* curl: NTLM password overflow via integer overflow (CVE-2018-14618)\n\nFor more details about the security issue(s), including the impact, a CVSS score, acknowledgments, and other related information, refer to the CVE page(s) listed in the References section.\n\nBug Fix(es) :\n\n* baseurl with file:// hangs and then timeout in yum repo (BZ#1709474)\n\n* curl crashes on http links with rate-limit (BZ#1711914)",
    "dnsName": "target-cent7.incus",
    "exploitAvailable": "No",
    "exploitEase": "No known exploits are available",
    "exploitFrameworks": "",
    "family": {
        "id": "18",
        "name": "CentOS Local Security Checks",
        "type": "active"
    },
    "firstSeen": "1708664620",
    "hasBeenMitigated": "0",
    "hostUUID": "",
    "hostUniqueness": "repositoryID,ip,dnsName",
    "ip": "10.238.64.10",
    "ips": "10.238.64.10",
    "keyDrivers": "{\"internet exposure\":\"internal\",\"device capability\":\"\",\"device type\":\"general_purpose\"}",
    "lastSeen": "1714626296",
    "macAddress": "00:16:3e:5d:7a:71",
    "netbiosName": "",
    "operatingSystem": "Linux Kernel 5.15.0-1056-aws on CentOS Linux release 7.6.1810 (Core)",
    "patchPubDate": "1564574400",
    "pluginID": "127470",
    "pluginInfo": "127470 (0/6) CentOS 7 : curl (CESA-2019:1880)",
    "pluginModDate": "1578312000",
    "pluginName": "CentOS 7 : curl (CESA-2019:1880)",
    "pluginPubDate": "1565611200",
    "pluginText": "<plugin_output>\nRemote package installed : curl-7.29.0-51.el7\nShould be                : curl-7.29.0-51.el7_6.3\n\nRemote package installed : libcurl-7.29.0-51.el7\nShould be                : libcurl-7.29.0-51.el7_6.3\n\n</plugin_output>",
    "port": "0",
    "protocol": "TCP",
    "recastRisk": "0",
    "recastRiskRuleComment": "",
    "repository": {
        "dataFormat": "IPv4",
        "description": "",
        "id": "1",
        "name": "Live"
    },
    "riskFactor": "Critical",
    "seeAlso": "http://www.nessus.org/u?fe980d88",
    "seolDate": "-1",
    "severity": {
        "description": "Critical Severity",
        "id": "4",
        "name": "Critical"
    },
    "solution": "Update the affected curl packages.",
    "stigSeverity": "",
    "synopsis": "The remote CentOS host is missing one or more security updates.",
    "temporalScore": "7.4",
    "uniqueness": "repositoryID,ip,dnsName",
    "uuid": "116411f4-083c-42c7-beaf-5b4a046811d0",
    "version": "1.4",
    "vprContext": "[{\"id\":\"age_of_vuln\",\"name\":\"Vulnerability Age\",\"type\":\"string\",\"value\":\"730 days+\"},{\"id\":\"cvssV3_impactScore\",\"name\":\"CVSS v3 Impact Score\",\"type\":\"number\",\"value\":5.9},{\"id\":\"exploit_code_maturity\",\"name\":\"Exploit Code Maturity\",\"type\":\"string\",\"value\":\"Unproven\"},{\"id\":\"product_coverage\",\"name\":\"Product Coverage\",\"type\":\"string\",\"value\":\"Medium\"},{\"id\":\"threat_intensity_last_28\",\"name\":\"Threat Intensity\",\"type\":\"string\",\"value\":\"Very Low\"},{\"id\":\"threat_recency\",\"name\":\"Threat Recency\",\"type\":\"string\",\"value\":\"No recorded events\"},{\"id\":\"threat_sources_last_28\",\"name\":\"Threat Sources\",\"type\":\"string\",\"value\":\"No recorded events\"}]",
    "vprScore": "5.9",
    "vulnPubDate": "1536148800",
    "vulnUUID": "",
    "vulnUniqueness": "repositoryID,ip,port,protocol,pluginID",
    "xref": "RHSA #2019:1880"
}

Some relevant fields in the response are:

  • acceptRisk—Indicates whether the risk is an accepted risk (1) or not (0).
  • recastRisk—Indicates whether the risk was recasted (1) or not (0).
  • riskFactor—The default severity of the finding as set by the plugin.
  • vprScore—The Vulnerability Priority Rating (VPR) score for the finding. For more information about VPR scores, see CVSS vs. VPR in the Tenable Security Center User Guide.
  • baseScore—The CVSSv2 base score.
  • cvssVector—The CVSSv2 vector.
  • temporalScore—The CVSSv2 temporal score.
  • hasBeenMitigated—Indicates whether the vulnerability was previously fixed in the past and then reopened (1) or not (0).
  • severity.{}—Information about the severity of the finding.
  • hostUniqueness—The field names that Tenable Security Center used to determine the host is unique. You can use the field names listed here to reconstruct the uniqueness value.
  • vulnUniqueness—The field names that Tenable Security Center used to determine the uniqueness of the vulnerability finding.
  • firstSeen—The Unix timestamp when this vulnerability finding was first discovered.
  • lastSeen—The Unix timestamp when this vulnerability finding was last observed from any scan. In the case of patched (fixed) findings, this field relays when the finding was determined to be fixed.
  • patchPubDate—The Unix timestamp when the patch addressing this vulnerability was published.
  • pluginPubDate—The Unix timestamp when the plugin was published to the feed.
  • pluginModDate—The Unix timestamp of the last modification of the plugin.
  • uuid—The UUID (if available) of the agent associated with the asset.
  • hostUUID—The internal UUID of the host (universal repositories only).
  • xref—Additional third-party references relating to the vulnerability finding. For example, a Microsoft KB ID or a Red Hat Security Article ID (as in this case). If multiple third-party references exist, they are returned as a comma-separated list within the string value.

Export WAS Findings

Tenable Web App Scanning (WAS) findings should be exported independently of the traditional vulnerability findings since they're returned in a different format. To export WAS findings, you can use tools available within the analysis API to return the WAS findings similar to how the user interface represents them.

For example, to export WAS findings, you could use the following request with the wasvulndetail tool:

POST /rest/analysis
{
    "type": "vuln",
    "sourceType": "cumulative",
    "query": {
        "tool": "wasvulndetail",
        "type": "vuln",
        "filters": [
            {
                "filterName": "severity",
                "operator": "=",
                "value": "1,2,3,4"
            },
            {
                "filterName": "wasVuln",
                "operator": "=",
                "value": "onlyWas"
            }
        ],
        "startOffset": 0,
        "endOffset": 2000
    }
}

The same request using pyTenable:

from tenable.sc import TenableSC

tsc = TenableSC(url='https://sc-instance', access_key='abc', secret_key='def')

findings = tsc.analysis.vulns(('severity', '=', '1,2,3,4'),
                              ('wasVuln', '=', 'onlyWas'),
                              tool='wasvulndetail'
                              )

The response object for the WAS findings returned by the request is in the following format:

{
    "pluginID": "98054",
    "severity": {
        "id": "2",
        "name": "Medium",
        "description": "Medium Severity"
    },
    "hasBeenMitigated": "0",
    "acceptRisk": "0",
    "recastRisk": "0",
    "ips": "10.238.64.122",
    "port": "8082",
    "protocol": "TCP",
    "pluginName": "Unvalidated Redirection",
    "firstSeen": "1710320002",
    "lastSeen": "1714545238",
    "exploitAvailable": "No",
    "exploitEase": "",
    "exploitFrameworks": "",
    "synopsis": "Unvalidated Redirection",
    "description": "Web applications occasionally use parameter values to store the address of the page to which the client will be redirected -- for example: yoursite.com/page.asp?redirect=www.yoursite.com/404.asp\n\nAn unvalidated redirect occurs when the client is able to modify the affected parameter value in the request and thus control the location of the redirection. For example, the following URL yoursite.com/page.asp?redirect=www.anothersite.com will redirect to www.anothersite.com.\n\nThere are several ways a redirection can occur:\n\n1) A response with a 3xx status code will tell the browser to redirect to the URL in the \"Location\" header\n\n2) A response with a \"Refresh\" header tells the browser to reload the page after a set interval (which can be 0). The header can take an arbitrary URL parameter to load\n\n3) The HTML <meta> tag can take a \"http-equiv\" attribute which can be used instead of an HTTP response header. Using this, a \"Refresh\" can be simulated\n\n4) Javascript is used to redirect the browser to an arbitrary URL\n\nCyber-criminals will abuse these vulnerabilities in social engineering attacks to get users to unknowingly visit malicious web sites.\n\nThe scanner has discovered that the server does not validate the parameter value prior to redirecting the client to the injected value.",
    "solution": "The application should ensure that the supplied value for a redirect is permitted. This can be achieved by performing whitelisting on the parameter value.\nThe whitelist should contain a list of pages or sites that the application is permitted to redirect users to. If the supplied value does not match any value in the whitelist then the server should redirect to a standard error page.",
    "seeAlso": "https://www.owasp.org/index.php/Unvalidated_Redirects_and_Forwards_Cheat_Sheet",
    "riskFactor": "Medium",
    "stigSeverity": "",
    "vprScore": "",
    "vprContext": "[]",
    "baseScore": "4.3",
    "temporalScore": "",
    "cvssVector": "AV:N/AC:M/Au:N/C:N/I:P/A:N",
    "cvssV3BaseScore": "4.7",
    "cvssV3TemporalScore": "",
    "cvssV3Vector": "AV:N/AC:L/PR:N/UI:R/S:C/C:N/I:L/A:N",
    "cpe": "",
    "vulnPubDate": "-1",
    "patchPubDate": "-1",
    "pluginPubDate": "1490961600",
    "pluginModDate": "1689249600",
    "checkType": "remote",
    "version": "",
    "cve": "",
    "bid": "",
    "xref": "CWE #601,HIPAA #164.306(a)(1),HIPAA #164.306(a)(2),OWASP #2021-A1,OWASP_API #2019-API7,OWASP_API #2023-API8,PCI_DSS #3.2-6.5.8,ISO #27001-A.14.2.5,DISA_STIG #APSC-DV-002560,NIST #sp800_53-SI-10,WASC #URL Redirector Abuse,OWASP #2010-A10,OWASP #2013-A10,OWASP_ASVS #4.0.2-5.1.5",
    "seolDate": "-1",
    "pluginText": "<plugin_output>An unvalidated redirect was found on http://webapps.incus:8082/app/redirect?url=http%3A%2F%2F6a003732-d5f5-497a-9e7d-db827232439b.com by injecting http://6a003732-d5f5-497a-9e7d-db827232439b.com into the query parameter 'url' to create the url 'http://webapps.incus:8082/app/redirect?url=http%3A%2F%2F6a003732-d5f5-497a-9e7d-db827232439b.com'.</plugin_output>",
    "dnsName": "webapps.incus",
    "operatingSystem": "Linux Kernel 2.6 on Ubuntu",
    "recastRiskRuleComment": "",
    "acceptRiskRuleComment": "",
    "hostUniqueness": "repositoryID,hostUUID",
    "hostUUID": "e36b474f-e7d5-41a5-9665-366053782ed5",
    "acrScore": "4.0",
    "keyDrivers": "{\"internet exposure\":\"internal\",\"device capability\":\"\",\"device type\":\"general_purpose\"}",
    "assetExposureScore": "619",
    "vulnUniqueness": "repositoryID,vulnUUID",
    "vulnUUID": "12f83075-cc89-41fb-8d29-2ce61d349aab",
    "url": "http://webapps.incus:8082/app/redirect",
    "proof": "The issue was raised because the scanner was redirected to http://6a003732-d5f5-497a-9e7d-db827232439b.com",
    "pageID": "",
    "httpMethod": "get",
    "inputName": "url",
    "inputType": "link",
    "attachment": "[{\"id\":\"3382\",\"name\":\"HTTP Request.txt\"},{\"id\":\"3383\",\"name\":\"HTTP Response.txt\"}]",
    "family": {
        "id": "2000012",
        "name": "Web Applications",
        "type": "was"
    },
    "repository": {
        "id": "13",
        "name": "Live-Universal",
        "description": "",
        "dataFormat": "universal"
    },
    "pluginInfo": "98054 (8082/6) Unvalidated Redirection"
}

Some relevant fields unique to the WAS findings are:

  • vulnUUID—The unique identifier for the finding.
  • url—The URL that the finding was observed on.
  • httpMethod—The HTTP method that was used to call the URL.
  • inputName—The input parameter that was tested for the finding.
  • inputType—The type of data that was used to test the finding.
  • proof—The finding proof details.