IBM QRadar SOAR

IBM QRadar

Join this online topic group to communicate across Security product users and IBM experts by sharing advice and best practices with peers and staying up to date regarding product enhancements.


#Security
#QRadar
#SecuringhybridcloudandAI
 View Only

Dynamically map a products severity code to a Resilient one.

  • 1.  Dynamically map a products severity code to a Resilient one.

    Posted 12/04/18 11:31 AM
    Edited by Ryan Gordon 12/04/18 11:46 AM
    Quite often when developing an integration between some other product and Resilient, you will encounter a need to take some severity value from this product and find its equivalent severity value in Resilient. The why you need to do this, could be that you are creating an incident and want to give it an appropriate severity or you are editing one, and need to update the severity.

    Objective: 

    This post will attempt to outline a way to reliably map another products security code to a Resilient one

    Taking a given product - i, this solution assumes that: 
    • Product i has a list of severity codes which are sorted in some way.
    • You either know the amount of severity codes in product or you can query this. 
    • You can access the Resilient REST API

    Getting the severity codes from Resilient : 

    This solution will require knowing how many severity codes are active in a given Resilient Org. Through this, 2 values are gotten, the upper and lower bounds of the available security codes. 
    In order to get the 2 values on the Resilient side of the equation, you will need access to the REST API of your resilient solution.  

    Below is an example script which will read config values from your app.config file and then attempt to send a REST query to the Resilient instance detailed in this app.config file. 
    It inherits from ExampleArgumentParser so you can expand upon it to add command line options if desired.
    class ExampleArgumentParser(resilient.ArgumentParser):
        """Arguments for this command-line application, extending the standard Resilient arguments"""
    
        def __init__(self, config_file=None):
            super(ExampleArgumentParser, self).__init__(config_file=config_file)
    
    other_product_codes = range(1,(6+1)) # 6 being the upped bound, add 1 so its included in list
    def main ():
    
        parser = ExampleArgumentParser(config_file=resilient.get_config_file())
        opts = parser.parse_args()
        client = resilient.get_client(opts)
    
        try:
            uri = '/types/incident/fields/severity_code'
    
            # Get the severity codes 
            severity_codes = client.get(uri)

    At this point we now have a handle on the severity_codes for this Resilient Org with a caveat; We have a list of both enabled/disabled and hidden/unhidden values. 

    The hidden and disabled values need to be parsed out to make this solution work dynamically. 
    Conveniently we can assume that in Resilient, only severity_codes with a enabled property of True and a hidden property of False are active and should be considered for this. To do this pruning, we will use a list comprehension like so :
    # Make a new list with these values 
    active_codes = [value for value in incident["values"] if value["enabled"] and not value["hidden"]]

    As a result now we have a list of all the Resilient Severity codes that we are concerned with for that Org. 

    Affine Transformation: 

    Now we get to the section which has the magic. How we actually map one code to the other. Everything up until now has been setting up for this moment by grabbing relevant values. Now comes time to do a calculation on these values and solve the problem.

    We will need to perform an Affine Transformation. An Affine Transformation allows us to take input X which resides in the domain [a,b] and transform it relative to the domain [c,d] giving an output of Y. This transformation can be used with the values we got previously to determine the best Resilient severity to use. The formula for our transformation is as such: 
    Where : 
    • x is the severity code from the other product 
    • a is the lower bound of severities in other product (usually 1)
    • b is the upper bound of severities in other product 
    • c is the lower bound of severities in Resilient (usually 1)
    • d is the upper bound of severities in Resilient 

    Both a and c will generally be 1 as severity code systems generally range from 1-N with 1 being the least severe.

    While mathematical formulas can look scary, the above equation can be turned into the following python code : 
    y = ((x-a)*((d-c)/(b-a)))+c )
    Note: All the brackets present aren't definitely needed, but I feel they help to explain how the equation evaluates according to BOMDAS

    At this point, we know what we need to do and have the python code to do it. So the time has come to solve the problem. For readability, we will define each part of the equation just before the calculation is done. 

    a = other_product_codes[0] #usually 1
    b = other_product_codes[len(other_product_codes)-1] #last index 
    c = 1 #usually 1
    d = active_codes
    
    # Where active_codes is the result of the list comprehension earlier in the post 
    
    #Perform the affine transformation, rounding the result
    result = round(((x-a)*((d-c)/(b-a)))+c )

    This result of this calculation can now be used to get Y; the most appropriate severity code for our needs. To get this, the active_codes list used in previous examples will be accessed like so : 
    # Get the determined best severity code
    active_codes["values"][result-1]
    
    # Get the determined best severity code's Label
    active_codes["values"][result-1]["label"]
    
    # Get the determined best severity code's ID
    active_codes["values"][result-1]["value"]


    After all this, you should now be able to not only determine the best Resilient severity_code to use but also should have everything you need (The Severity Code's ID Value) to set that severity level using our REST API on a new or existing incident. 

    Note: Alot of the REST Endpoints take severity_code as an int reference the ID Value of that severity. If you intend to hit any of these endpoints use the value attribute detailed in the code snippet

    Conclusion :


    The Affine Transformation is a powerful way we can dynamically map  a products severity code to a Resilient one. The biggest problem I had when trying to solve this problem was thinking how to account for disabled/hidden/not-in-use severity codes and also how to make the solution work across different locales where the Severity code labels may be different. This works perfectly for my use case and might give you some value too.

    ------------------------------
    Ryan Gordon,
    Security Software Engineer
    ------------------------------