Whitelisting observables in ServiceNow
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
3 hours ago
What it can bring you
- Reducing the noise and false positive which need to be reviewed by Analyst and thus reducing MTTR (Mean Time To Resolve)
- Better security - by not sending out information about your internal infrastructure
- Performance of the platform - by not running unnecessary flows and logic
- COSTS - some integrations are paid by the number of requests you make to the API, whitelisting can significantly reduce the amount of calls
Safe harbor notice
Keep in mind that this implementation is just a showcase to give you an idea. A lot of things are done in sake of simplicity and keep the scope on the topic (ie. accessibility of Script Include, UI Actions conditions etc).
This is not a final product! Goal is to give idea how to configure.
I'm not taking any responsibility for use of the practices shown in this article.
What you would need
- ServiceNow PDI on Xanadu or higher
- Security Incident Response [sn_si] plugin installed
- For ease of testing and access you might also want to install Threat Intelligence [sn_ti_ac] module
- Security Incident Response admin [sn_si.admin] role and Threat Intelligence admin [sn_ti.admin] role
- FOR TESTING If you don't have any integration for observable enrichment you would need MISP integration for Security Operations [sn_sec_misp] (no need of acutally having MISP instance)
Recognizing Observables to be whitelisted
First of all we need to think about based on what we will recognize whether the observable should be whitelisted.
The observable value for whitelisting would probably fall into one of these categories
- Hardcoded values
- IP Ranges
- REGEXes
- More complex rules (ie. Observables matching Windows Server CMDB records)
The Approach
The idea is to use as much OOB logic as possible. Luckily enough we already have a handy tool to for this - Security Tags and Security Tag Rules.
First, switch your Application scope to 'Security Support Common' and create an update set.
Now, since we are all set, let's
- Find a suitable Security Tag
- Define rules for that tag for all categories (ie. IP Ranges, Regexes).
- Excluding whitelisted Observables from integration capabilities
- Roll-up the rules against observable table (this will be covered in part 2)
1. Find a suitable Security Tag
- Go to the Security Tag [sn_sec_cmn_security_tag] table to see the whole "menu"
- Choose one, I strongly suggest taking either 'Enrichment: Allowlist' [71562f6fc7d310101917dac2c7c26036] or 'Enrichment: Whitelist' [e6e6ea180b503200263a089b37673a08]. We will use 'Enrichment: Whitelist'.
- If you open the 'Enrichment: Whitelist' record, you may notice that Security Tag Group is empty. Either you can select 'Enrichment allow / denylist' (which we will do for sake of simplicity) or create your own. Save the record (this will make it available on the Security Tag selection).
2. Define rules for that tag for all categories
A) Hardcoded Values
This is as simple as it gets. We basically need to create a condition for each value. Based on needs of your company, you can create one and place all conditions there, or divide it by observable type or any other parameter you fancy.
You should keep in mind the maintanance (whether it will be done by developers or handed over to Analyst teams [preferable])
- Go to the 'Enrichment: Whitelist' record on Security Tag [sn_sec_cmn_security_tag] table
- In Related list 'Security Tag Rules' click on 'New'
- Fill in the 'Name' (ie 'Hardcoded observable values'), keep in mind your company naming convention
- Make sure 'Active' is ticked true
- For table select 'Observable' [sn_ti_observable]
- In Condtion field select 'Value' and then define the condition based on what you want to whitelist (ie. IS 'google.com'). Note that you can either use OR condition or create a new rules, depends on the grouping you are looking for.
- Submit the record
- For testing go to the Observable table [sn_ti_observable] list
- Click on 'New'
- Fill in the Value 'google.com'
- Submit the record
- Open the record you have just created
- See that it has tag 'Enrichment: Whitelist' attached to it. Also, if you open the XML of the record, you can see the sys_id of the tag in <security_tags>.
- Notice that also if you go to the 'Enrichment: Whitelist' record on Security Tag [sn_sec_cmn_security_tag] table, in related list 'Applied Security Tags' you can see the M2M record
B) IP Ranges
- Go to the 'Enrichment: Whitelist' record on Security Tag [sn_sec_cmn_security_tag] table
- In Related list 'Security Tag Rules' click on 'New'
- Fill in the 'Name' (ie 'IP Range 172.16/12'), keep in mind your company naming convention
- Make sure 'Active' is ticked true
- Tick 'Use filter group'
- 'Filter Group' field appeared and you can select one of default filter groups, for simplicity we will go with "Local IP Address Range '172.16/12'". Here you can also create a new one, featuring whatever IP Range you fancy. Just change the 'Network IP Address' and the name and use 'Insert and stay'. 😉
- Submit the record
- For testing go to the Observable table [sn_ti_observable] list
- Click on 'New'
- Fill in the Value '172.16.20.30'
- Submit the record
- Open the record you have just created
- See that it has tag 'Enrichment: Whitelist' attached to it. Also, if you open the XML of the record, you can see the sys_id of the tag in <security_tags>. Note that 'Block From Sharing' tag might be also added, since that is OOB configuration.
- Notice that also if you go to the 'Enrichment: Whitelist' record on Security Tag [sn_sec_cmn_security_tag] table, in related list 'Applied Security Tags' you can see the M2M record
C) REGEXes
Since there was an issue with ServiceNow 'matches regex' operator described PRB662349, which is no longer availabe I would strongly suggest to do a thorough testing and if you experience any issues, just solve it with D) More Complex Logic.
- Go to the 'Enrichment: Whitelist' record on Security Tag [sn_sec_cmn_security_tag] table
- In Related list 'Security Tag Rules' click on 'New'
- Fill in the 'Name' (ie 'Single digit'), keep in mind your company naming convention
- Make sure 'Active' is ticked true
- For table select 'Observable' [sn_ti_observable]
- In Condtion field select 'Value' and operator 'matches regex', then the regex in form '^\d{1}$' (without quotes, for single digit)
- Submit the record
- For testing go to the Observable table [sn_ti_observable] list
- Click on 'New'
- Fill in the Value with any single digit (ie '7')
- Submit the record
- Open the record you have just created
- See that it has tag 'Enrichment: Whitelist' attached to it. Also, if you open the XML of the record, you can see the sys_id of the tag in <security_tags>.
- Notice that also if you go to the 'Enrichment: Whitelist' record on Security Tag [sn_sec_cmn_security_tag] table, in related list 'Applied Security Tags' you can see the M2M record
D) More complex logic
Here we need a bit of ingenuity.
Let's say we want to whitelist observable which has the same name as any non-retired windows server (for simplicity we will do it access-wise as simple as possible)
- Create a script include (we will use 'CustomObservableWhitelistingUtils') with 'Accessible from' set to 'All application scopes' and 'Sandbox enabled' = true
- Insert to it a function matchesWindowsServer which you can find after these steps
- Go to the 'Enrichment: Whitelist' record on Security Tag [sn_sec_cmn_security_tag] table
- In Related list 'Security Tag Rules' click on 'New'
- Fill in the 'Name' (ie 'Matches Windows Server name'), keep in mind your company naming convention
- For table select 'Observable' [sn_ti_observable]
- In Condtion field select 'Value' and operator 'IS', then you need to call the Script Include function like this 'javascript: new sn_sec_cmn.CustomObservableWhitelistingUtils().matchesWindowsServer(current.value);' Please replace script include name and scope with your own.
- For testing Go to Windows Servers [cmdb_ci_win_server] table and select any one with Operational Status IS NOT retired - copy it's name
- Then go to the Observable table [sn_ti_observable] list
- Click on 'New'
- Paste the name of the Windows Server from step 8
- Submit the record
- Open the record you have just created
- See that it has tag 'Enrichment: Whitelist' attached to it. Also, if you open the XML of the record, you can see the sys_id of the tag in <security_tags>.
- Notice that also if you go to the 'Enrichment: Whitelist' record on Security Tag [sn_sec_cmn_security_tag] table, in related list 'Applied Security Tags' you can see the M2M record
- Also repeat the steps 8-13 with a retired windows server to confirm that the 'Enrichment: Whitelist' tag was not attached
/**
* Checks if the observableValue is same as name of any Windows Server in CMDB which is not retired
* @observableValue {String} Value of observable record
* @return {String} If found, returns the observableValue, else returns false
*/
matchesWindowsServer: function(observableValue) {
if (!gs.nil(observableValue)) {
var serverGR = new GlideRecord('cmdb_ci_win_server');
serverGR.addEncodedQuery('operational_status!=6^name=' + observableValue);
serverGR.query();
if (serverGR.hasNext()) return observableValue;
}
return false;
},For custom matching of regex, we need to write our custom function and call it the same way. We will pass two arguments when calling a function from the condition field (observableValue and regex) and return the observableValue if it matched the regex (was satisfied) or false if not.
Code in the Script Include might then look like this:
/**
* Checks whether value matches the regex
* @param {String} observableValue - value to test agains regex
* @param {object Regex} regex - Regular expression (ie. /^\d{1}$/g)
* @return {Boolean} - Returns observableValueif regex matches the value, else returns false
*/
checkValueAgainstRegex: function(observableValue, regex) {
if (!gs.nil(observableValue) && !gs.nil(regex)) {
try {
regex = new RegExp(regex);
if (regex.test(observableValue)) return observableValue;
} catch (e) {
return false;
}
}
return false;
},Exclusion from integration capabilities
Now we have our Observables properly tagged but we still need to exclude them from the Integration Capabilities we don't want to get triggered.
Let's go for Observable Enrichment for showcase. We probably know the observable, since we have whitelisted it and therefore we don't need to collect pieces of information from external sources.
- Go to the Capabilities [sn_sec_cmn_capability] (Application Navigator -> Security Operations -> Integrations -> Integration Capabilities (Flows)
- Open 'Enrich Observable' record
- Notice the Related List 'Filter Conditions' and click 'New'
- Fill in 'Name' (ie. 'Filter whitelisted observables'), 'Condition Table' to 'Observable [sn_ti_observable]', then 'Conditions' - 'Security tags' CONTAINS 'Enrichment: Whitelist'
- Submit the record
- Go back to 'Enrich Observable' Capability (step 1-2)
- If you have installed MISP, then in related list 'Capability Implementation' you should see a record for MISP - open it
- Set it to 'Active' = true (ticked) and Save (you might need to change the scope to 'MISP integration for Security Operations')
- For testing go to the Security Incident table [sn_si_incident] list
- Click on 'New'
- Fill in any 'Short Description'
- Submit the record
- Open the record you have just created
- In Related Links click on 'Show All Related Lists'
- Open Related List 'Associated Observables'
- Click 'Edit' button in the related list
- Filter records for 'Security tags' CONTAINS 'Enrichment: Whitelist'
- Select some IP Address and Domain Name (ie. 172.16.20.30 and google.com) and click on 'Save'
- Back on Security Incident record stay on 'Incident Details' tab and wait for a few minutes
- If you have MISP (or any other Observable Enrichment integration installed) you should be able to see result like on the image
Exclusion from custom integrations
The story is a bit more complex here.
I would suggest add a condition at the beginning of flow or scripted logic which checks whether it has the appropriate tag ('Enrichment: Whitelist' in our case) and if so I would add a comment / worknote to the task (if it was run from the task) that it was Filtered based on the tag and end the flow / scripted logic.
Final touches
Finding = Clean
You might also want to mark whitelisted observable with Finding = 'Clean'.
For this you can do following:
- Go to Business Rule [sys_script] table
- Create a New Business Rule on Applied Security Tag [sn_sec_cmn_applied_security_tag]
- Set following values: Name = Any (ie. Set Finding for whitelisted observable), Description = Any, When = after (async can't access current object for delete), Insert = true, Delete = true, Condition = security_tag=e6e6ea180b503200263a089b37673a08^record_table=sn_ti_observable^EQ (Security Tag IS Enrichment: Whitelisted AND Record table IS sn_ti_observable), Script = You can find the script lower
- Submit the record
- For testing open any observable. Attach the 'Enrichment: Whitelisted' security tag to it
- Observe that Finding changed to 'Clean' (refresh might be needed)
- Remove the 'Enrichment: Whitelisted' security tag
- Observe that Finding changed to 'Unknown'(refresh might be needed)
(function executeRule(current, previous /*null when async*/) {
var observableGR = new GlideRecord('sn_ti_observable');
if (observableGR.get(current.getValue('record_id'))) {
if (current.operation() == 'insert')
observableGR.setValue('finding', 'clean');
else if (current.operation() == 'delete')
observableGR.setValue('finding', 'Unknown');
observableGR.update();
}
})(current, previous);Considerations
- Be careful when using CONTAINS operator and regexes. This might create a blindspot which can be abused
- Think about handing over the maintanance directly to Security Analyst teams to aleviate workload from developers and to streamline whitelisting observables and removing observables from whitelist
Specific tables used
- Observables [sn_ti_observable]
- Security Tag [sn_sec_cmn_security_tag]
- Security Tag Rule [sn_sec_cmn_security_tag_rule]
- Filter Group [sn_sec_cmn_filter_group]
- Filter Condition [sn_sec_cmn_filter_condition]
- Applied Security Tags [sn_sec_cmn_applied_security_tag]
- Capabilities [sn_sec_cmn_capability]