Skip to content

Commit

Permalink
Added example : Nessus Integration
Browse files Browse the repository at this point in the history
  • Loading branch information
namysTarek authored and Amine committed Sep 2, 2024
1 parent 1e6b7cb commit 967cae4
Show file tree
Hide file tree
Showing 6 changed files with 274 additions and 0 deletions.
31 changes: 31 additions & 0 deletions examples/nessus_integration/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
## Cyberwatch & Nessus Integration

This script will retrieve vulnerabilities of assets on Nessus and import them into Cyberwatch automatically.

For this, sets of credentials for the Nessus and Cyberwatch APIs will be required to allow the retrieval of data from Nessus, and the creation of assets on Cyberwatch.

Given the technical constraints, only the list of vulnerabilities for each asset on Nessus can be exported to Cyberwatch, without any association related to the affected technologies and recommended corrective actions.

### Use case

Let's consider the following Nessus assets.

![image](img/image1.png)

After executing the script, these assets will be available on Cyberwatch, along with their associated list of vulnerabilities.

![image](img/image2.png)

The vulnerabilities come from the Reference Information panel of the Nessus plugins results. However, not all plugins associate vulnerabilities with their results.

![image](img/image3.png)

The name of the assets created on Cyberwatch can be customized, particularly to customize the string "Nessus |" in front of it.

_Caution : When using the script, all assets starting with the identifier ('Nessus |' by default) will be deleted, make sure no conflict can happen with any other unwanted asset._

### How to use

1. Generate a set of [Nessus](https://docs.tenable.com/vulnerability-management/Content/Settings/my-account/GenerateAPIKey.htm#To-generate-API-keys-for-your-own-account:) and [Cyberwatch](https://docs.cyberwatch.fr/help/en/API_documentation/API_use/#authenticate-to-the-api-and-test-your-connection) Api keys ;
2. Fill out the `api.conf` file accordingly ;
3. Launch the script without any needed arguments.
147 changes: 147 additions & 0 deletions examples/nessus_integration/cbw_helper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
from cyberwatch_api import Cyberwatch_Pyhelper
import json
import requests
import configparser
import urllib3
urllib3.disable_warnings(category=urllib3.exceptions.InsecureRequestWarning)

def jprint(text):
print(json.dumps(text, indent=4))
return json.dumps(text, indent=4)

def cbw_createAirgapAsset(HOSTNAME, TECHNOLOGIES):
output = "HOSTNAME:{}\n".format(HOSTNAME)
# for TECHNOLOGIE in TECHNOLOGIES:
# (package, version) = TECHNOLOGIE.split("_")
# output += "NVD_APPLICATION:(from nessus : unanalyzed) {}|{}\n".format(package, version)

apiResponse = Cyberwatch_Pyhelper().request(
method="POST",
endpoint="/api/v2/cbw_scans/scripts",
body_params={
"output" : output
},
timeout=90,
verify_ssl=False
)
result = next(apiResponse)

if 'error' in result:
raise "ERROR : " + result["error"]["message"]
return result.json()["server_id"]


def cbw_deleteAsset(id):
apiResponse = Cyberwatch_Pyhelper().request(
method="DELETE",
endpoint="/api/v3/assets/servers/{}".format(id),
verify_ssl=False,
)

return next(apiResponse).json()

def cbw_retrieveSecurityIssue(sid):
apiResponse = Cyberwatch_Pyhelper().request(
method="GET",
endpoint="/api/v3/security_issues",
verify_ssl=False,
body_params={
"sid" : sid,
}
)

return next(apiResponse).json()

def cbw_deleteSecurityIssue(id):
apiResponse = Cyberwatch_Pyhelper().request(
method="DELETE",
endpoint="/api/v3/security_issues/{}".format(id),
verify_ssl=False,
)

return next(apiResponse).json()

def cbw_createSecurityIssue(sid, title, cve_announcements, servers):
apiResponse = Cyberwatch_Pyhelper().request(
method="POST",
endpoint="/api/v3/security_issues",
verify_ssl=False,
body_params={
"sid" : sid,
"title" : title,
"cve_announcements" : cve_announcements,
"servers" : servers,
}
)

return next(apiResponse).json()

def cbw_refreshAssetAnalysis(server_id):
apiResponse = Cyberwatch_Pyhelper().request(
method="PUT",
endpoint="/api/v3/vulnerabilities/servers/{}/refresh".format(server_id),
verify_ssl=False,
)

return next(apiResponse).json()

def cbw_clearNessusData():
#####
# Clear All Nessus Security Issues
#####

apiResponse = Cyberwatch_Pyhelper().request(
method="GET",
endpoint="/api/v3/security_issues",
verify_ssl=False,
)

security_issues = []
for page in apiResponse:
security_issues = security_issues + page.json()

for security_issue in security_issues:
if security_issue["title"].startswith(PARSE_CONFIG()["SCRIPT_ASSET_IDENTIFIER"]):
print("Deleting Security Issue {}".format(security_issue["title"]))
cbw_deleteSecurityIssue(security_issue["id"])

#####
# Clear All Nessus Assets
#####

apiResponse = Cyberwatch_Pyhelper().request(
method="GET",
endpoint="/api/v3/assets/servers",
verify_ssl=False,
)
print("Retrieving assets : 0")
assets = []
for page in apiResponse:
assets = assets + page.json()
print("\033[A\033[A\nRetrieving assets : " + str(len(assets)))

for asset in assets:
if asset["hostname"].startswith(PARSE_CONFIG()["SCRIPT_ASSET_IDENTIFIER"]):
print("Deleting Asset {}".format(asset["hostname"]))
cbw_deleteAsset(asset["id"])

def PARSE_CONFIG():
config = configparser.ConfigParser()
config.read('api.conf')
NESSUS_API_KEY = config['nessus']['api_key']
NESSUS_SECRET_KEY = config['nessus']['secret_key']
NESSUS_URL = config['nessus']['url']
SCRIPT_DEBUG = config['script']['debug']
SCRIPT_ASSET_IDENTIFIER = config['script']['asset_identifier']

return {
"NESSUS_API_KEY" : NESSUS_API_KEY,
"NESSUS_SECRET_KEY" : NESSUS_SECRET_KEY,
"NESSUS_URL" : NESSUS_URL,
"SCRIPT_DEBUG" : "true" in SCRIPT_DEBUG.lower(),
"SCRIPT_ASSET_IDENTIFIER" : SCRIPT_ASSET_IDENTIFIER
}

def NESSUS_API(URL):
nessus_config = PARSE_CONFIG()
return requests.get(URL, headers={'X-ApiKeys': f'accessKey={nessus_config["NESSUS_API_KEY"]}; secretKey={nessus_config["NESSUS_SECRET_KEY"]}'}, verify=False)
Binary file added examples/nessus_integration/img/image1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added examples/nessus_integration/img/image2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added examples/nessus_integration/img/image3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
96 changes: 96 additions & 0 deletions examples/nessus_integration/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
from cyberwatch_api import Cyberwatch_Pyhelper
from cbw_helper import *
import sys
import urllib3
urllib3.disable_warnings(category=urllib3.exceptions.InsecureRequestWarning)

#####
# Initializing global variables
#####
NESSUS_URL = PARSE_CONFIG()["NESSUS_URL"]
DEBUG = PARSE_CONFIG()["SCRIPT_DEBUG"]
NESSUS_ASSETS = {}

#####
# Retrieving all Nessus Scans
#####

SCANS = NESSUS_API('{}/scans'.format(NESSUS_URL)).json()["scans"]

for SCAN in SCANS:
print("[+] Nessus - Retrieving scan {}".format(SCAN["id"]))
#####
# Retrieve all hosts associated to the current scan
#####
HOSTS = NESSUS_API('{}/scans/{}'.format(NESSUS_URL, SCAN["id"])).json()["hosts"]

for HOST in HOSTS:
print("\t Host : {}".format(HOST["hostname"]))
#####
# Clean the previous host data
#####
CVE_LIST = []

#####
# Get the current host informations and plugins list
#####
HOST_ID = HOST["host_id"]
HOST_NAME = HOST["hostname"]
HOST_INFORMATIONS = NESSUS_API('{}/scans/{}/hosts/{}'.format(NESSUS_URL, SCAN["id"], HOST_ID)).json()
HOST_PLUGINS_LIST = list(set([CVE["plugin_id"] for CVE in HOST_INFORMATIONS["vulnerabilities"] if CVE["plugin_id"]]))
print("\t\t Plugins : {}".format(len(HOST_PLUGINS_LIST)))

#####
# For each plugin, retrieve the associated CVEs
#####
for PLUGIN in HOST_PLUGINS_LIST:
try:
URL = '{}/scans/{}/hosts/{}/plugins/{}'.format(NESSUS_URL, SCAN["id"], HOST_ID, PLUGIN)
RESPONSE = NESSUS_API(URL)
CVE_LIST = list(set(CVE_LIST + next(ref["values"]["value"] for ref in NESSUS_API(URL).json()["info"]["plugindescription"]["pluginattributes"]["ref_information"]["ref"] if ref["name"] == "cve")))
except:
next

#####
# If it is the first time we find the host, we save it. Otherwise, we just append the found CVEs
#####

if HOST_NAME not in NESSUS_ASSETS:
NESSUS_ASSETS[HOST_NAME] = {
"id" : HOST_ID,
"hostname" : HOST_NAME,
"cve_list" : CVE_LIST,
}
else:
NESSUS_ASSETS[HOST_NAME]["cve_list"] = list(set(NESSUS_ASSETS[HOST_NAME]["cve_list"] + CVE_LIST))

print("\t\t Total CVEs : {}".format(len(NESSUS_ASSETS[HOST_NAME]["cve_list"])))

#####
# Clean cyberwatch data related to nessus
#####
print("[+] Cleaning all related Nessus data on Cyberwatch")
cbw_clearNessusData()

#####
# Foreach found nessus host, we create a security issue linking all the found CVEs, then we associate it to the matching airgap asset
#####

for NESSUS_ASSET_ID, NESSUS_ASSET in NESSUS_ASSETS.items():
#####
# Creating or updating the airgap asset
#####
CBW_ASSET_HOSTNAME = "Nessus | {}".format(NESSUS_ASSET["hostname"])
CBW_ASSET_ID = cbw_createAirgapAsset(CBW_ASSET_HOSTNAME, [])
print("[+] Cyberwatch - Creating asset {}".format(CBW_ASSET_HOSTNAME))

#####
# Creating the security issue
#####
CBW_HOST_SID = "Nessus_{}".format(NESSUS_ASSET["hostname"])
CBW_HOST_SID_TITLE = "Nessus | {}".format(NESSUS_ASSET["hostname"])

if bool(cbw_retrieveSecurityIssue(CBW_HOST_SID)): # Security Issues Already Exists
cbw_deleteSecurityIssue(cbw_retrieveSecurityIssue(CBW_HOST_SID)[0]["id"])

cbw_createSecurityIssue(CBW_HOST_SID, CBW_HOST_SID_TITLE, NESSUS_ASSET["cve_list"], [CBW_ASSET_ID])

0 comments on commit 967cae4

Please sign in to comment.