Creating the automation script to fetch alerts from Claroty

About this task

An automation script is created for fetching alerts from Claroty.

Follow the steps below to create the automation script:

Procedure

  1. Open the Automation Scripts application.
  2. On the navigation panel, click Create and select Script with Action Launch Point : Step 1 of 3, and enter data in the fields as follows:
    • Launch Point: Specify the launch point name, for example, CLAROTY_VULNERABILITY
    • Object: Search for the ASSET object and select it
    • Action: Specify the Action name same as the name given for Launch Point, for example, CLAROTY_VULNERABILITY.
    • Check the checkbox for Active? and click Next.
  3. On the Create Script with Action Launch Point : Step 2 of 3 pop-up, enter the details in the fields as follows:
    • Script: Specify as jython
    • Script Language: Search and select jython
    • Log level: Search and select ERROR.
    • Click Next.
  4. On the Create Script with Action Launch Point : Step 3 of 3

    In the Script box, enter the following script and click Create.

    Note: This is a sample script that fetches alerts from Claroty and stores them in the cdalert table of Maximo IT. The script is designed to limit the data to 100 records per request and increment the offset (0, 100, 200, and so on) until all records are fetched. The below script is a sample and for reference only, update the script as per your custom field ID's and other changes as necessary.
    from psdi.server import MXServer
    #from psdi.mbo import MboConstants
    from psdi.mbo import Mbo, MboRemote, MboSet, MboSetRemote,MboConstants,SqlFormat
    from org.apache.http.impl.client import DefaultHttpClient
    from org.apache.http.client.methods import HttpPost
    from org.apache.http import HttpEntity, HttpHeaders, HttpResponse, HttpVersion
    from com.ibm.json.java import JSON, JSONObject,JSONArray
    from org.apache.http.client.methods import HttpPost
    from java.util import HashMap
    from com.google.gson import JsonParser, JsonElement,JsonObject,Gson
    
    from psdi.security import UserInfo
    from org.apache.http.params import BasicHttpParams, HttpParams, HttpProtocolParamBean
    from org.apache.http.entity import StringEntity
    #from psdi.iface.app.location import MaxOperLocProcess
    from psdi.security import UserInfo
    from psdi.server import MXServer
    
    urldata = “https://demo-api.claroty.com/api/v1/device_vulnerability_relations/”
    token = “Enter your api token”
    
    def updateOldStatus():
        server = MXServer.getMXServer()
        userInfo = server.getSystemUserInfo()
        
        # Replace with your actual MBO name, like "ITALERT"
        mboSet = server.getMboSet("alert_entity_relationship", userInfo)
        
        if mboSet is not None:
            mbo = mboSet.moveFirst()
            while mbo is not None:
                currentStatus = mbo.getInt("ALERT_STATUS")
                if currentStatus != 0:
                    mbo.setValue("ALERT_STATUS", 0)
                mbo = mboSet.moveNext()
            
            mboSet.save()
            mboSet.close()
            print "Done"
        return "done"
     # We are here passing the device_site_name ,vulnerability_is _known_exploited, vulnerability_epss_score, device_category & vulnerability_relevance  as filtering arguments to get related data. (these filters & their respective values can be change as per the need)
    def generateJSON(os):
      filterObj = {
          "filter_by": {
          "operation": "and",
          "operands": [
              {
              "field": "device_site_name",
                "operation": "equals",
                "value": "Washington"
              },
              { 
                "field": "vulnerability_is_known_exploited",
                "operation": "equals",
                "value": True
              },
              {
                "field": "vulnerability_epss_score",
                "operation": "greater_or_equal",
                "value":"0.8"
              },
              {
                "field": "device_category",
                "operation": "in",
                "value": [
                  "IT",
                  "OT"
                  ,"IoT"
                ]
              },
              {
                "field": "vulnerability_relevance",
                "operation": "equals",
                "value":"Confirmed"
              }
            ]
          },
          "offset": os,
          "include_count": True,
          "limit": 100,
          "fields": [
            "device_category",
            "device_vulnerability_detection_date",
            "device_known_vulnerabilities",
             "device_site_name",
            "vulnerability_id",
            "vulnerability_name",
            "device_asset_id",
            "device_site_name",
            "device_risk_score",
            "device_risk_score_points",
            "vulnerability_epss_score",
            "vulnerability_exploits_count",
            "vulnerability_is_known_exploited",
            "vulnerability_last_updated",
            "vulnerability_relevance"
          ]
        
      }
      jsonData = Gson().toJson(filterObj)
      return jsonData
      
    # jsonStr = generateJSON()
    
    # method for http POST using url, JSON body and token with bearer authorization
    def httpPost(uri, jsonstring):
        # get http parameters
        params = BasicHttpParams()
        paramsBean = HttpProtocolParamBean(params)
       
        # get http body entities
        entity = StringEntity(jsonstring)
    
        # get client, http headers and request
        client = DefaultHttpClient()
        request = HttpPost(uri)
        request.setParams(params)
        request.addHeader(HttpHeaders.CONTENT_TYPE, "application/json")
        request.addHeader('Authorization',str(token))
        request.setEntity(entity)
    
        # get client response
        response = client.execute(request)
        # return JSON response and reference number
        status = response.getStatusLine().getStatusCode()
        obj = JSONObject.parse(response.getEntity().getContent())
        return obj
    jsonStr = generateJSON(0)
    jsdata = str(jsonStr).replace("\'", "\"")
    url= str(urldata)
    logArr=[]
    log = httpPost(url, jsdata)
    
    offset=0
    limit=100
    
    jsonElement = JsonParser().parse(log.toString())
    jsonObject = jsonElement.getAsJsonObject()
    # append 0 offset data into logarr
    logArr.append(jsonObject.get('devices_vulnerabilities'))
    # fetch total count of data from claroty
    result=jsonObject.get('count') 
    totalCount = int(result.toString())
    
    if(totalCount//limit != 0):
        maxval = -(totalCount//-limit)    
        for i in range(1,maxval):
            offset = offset+100
            jsonStr = generateJSON(offset)
            jsdata = str(jsonStr).replace("\'", "\"")
            logs = httpPost(url, jsdata)
            jsonElement = JsonParser().parse(logs.toString())
            jsonObject = jsonElement.getAsJsonObject()
            # append next offset data into logarr
            logArr.append(jsonObject.get('devices_vulnerabilities'))
    
    # Create a new object to accumulate the arrays under one key
    accumulated_array = {"devices_vulnerabilities":[]}
    
    # Loop through each key-value pair in the original object and accumulate the values
    for val in logArr:
        accumulated_array["devices_vulnerabilities"].extend(val)
    accumulated_data = str(accumulated_array).replace("\'", "\"")
    
    updateOldStatus()
    # # pass claroty api response to alert script
    varx = HashMap()
    varx.put("respData",accumulated_data)
    service.invokeScript("VULNERABILITY",varx)
    

    In the below sample script, we are mapping alert data from Claroty to Maximo IT’s alert attributes. Some examples of these mappings include:

    • ALERT_ID (Maximo) is mapped to vulnerability_id (Claroty)
    • description (Maximo) is mapped to vulnerability_name (Claroty)
    • location (Maximo) is mapped to device_site_name (Claroty)

    These mappings are stored in a local JSON file (/opt/ibm/wlp/usr/servers/defaultServer/alert.json), which allows for easy updates to the attribute mappings as needed. The script fetches device details from Claroty, applies the mappings from the file, and then inserts the mapped data into Maximo IT. These can be updated as needed.

    Alert.json file structure
    {
    "result":
    	[{
    		"ALERT_ID":"vulnerability_id",
    		"DESCRIPTION":"vulnerability_name",
    		"LOCATION":"device_site_name",
    		"PRIORITY":"device_known_vulnerabilities",
    		"SEVERITY":"device_risk_score",
    		"CREATED_AT":"device_vulnerability_detection_date",
    		"DESCRIPTION_LONGDESCRIPTION":"vulnerability_description",
    		"VULNERABILITY_SCORE":"device_risk_score_points",
    		"STATUS":"vulnerability_relevance"
    	}]
    }
    
  5. Save your changes.

Table Schema in Maximo IT

To import the alerts into Maximo IT, two new tables are created: cdalert and ALERT_ENTITY_RELATIONSHIP in Maximo IT Db2. A sample table schemas for both are shown below.
  1. cdalert Table Schema
    Note: This is a sample table schema for the cdalert table. You can modify the schema based on your custom fields and other changes as necessary.
    CDALERT Table Schema 
    
    ALERT_ID 
    Description: Claroty's vulnerability ID. 
    Type: VARCHAR 
     
    DESCRIPTION 
    Description: Vulnerability Name. 
    Type: VARCHAR 
     
    PRIORITY 
    Description: Represents the priority of the vulnerability, derived from device_known_vulnerabilities. 
    Type: VARCHAR 
     
    VULNERABILITY_SCORE 
    Description: Represent the risk level, based on device_risk_score_points. 
    Type: VARCHAR 
     
    SEVERITY 
    Description: Describes the severity of the vulnerability, derived from device_risk_score. 
    Type: VARCHAR 
     
    STATUS 
    Description: Status of alert. 
    Type: VARCHAR 
     
    CREATED_BY 
    Description: Source of the alert. 
    Type: VARCHAR 
     
     
    MODIFIED_BY 
    Description: The user that updated the alert details (if applicable). 
    Type: VARCHAR 
     
    CREATED_AT 
    Description: The date and time when the vulnerability was first detected. 
    Type: VARCHAR 
     
    LOCATION 
    Description: Site name where the vulnerability was found. 
    Type: VARCHAR 
    
  2. ALERT_ENTITY_RELATIONSHIP Table Schema
    Note: This is a sample table schema for the ALERT_ENTITY_RELATIONSHIP table. You can modify the schema based on your custom fields and other changes as necessary.
    ALERT_ENTITY_RELATIONSHIP Table Schema  
    ENTITY_NAME 
    Description: Name of the source related to the vulnerability. 
    Type: VARCHAR 
     
    ENTITY_ID 
    Description: The unique identifier for the source id 
    Type: VARCHAR 
     
    ALERT_ID 
    Description: Alert id from cdalert table 
    Type: VARCHAR 
     
    ALERT_STATUS 
    Description: Indicates the current status. 
    Type: VARCHAR 
    
    INCIDENT_STATUS
    Description: Indicates the current status of Incident. 
    Type: VARCHAR 
    
    INCIDENT_ID
    Description: Unique ID of Incident. 
    Type: VARCHAR