JetPatch vulnerability parser can support any report from a Vulnerability Scanner by uploading the report into JetPatch.
In this article, you will find how to customize the JetPatch Vulnerability Parser to support the needed report.
Glossary
Term | Description |
Endpoint | Any computer entity in your environment, Workstation, Desktop, Laptop, Server |
Patch ID |
For Windows - KB number, With or without the KB prefix (both are supported). For Linux - Full advisory name. CVE is not a Patch ID |
Report entity | a row in the uploaded report |
regex |
Regular Expression statement to fetch information from a string. The regex that appears in the parser configuration file should be escaped with \ (so \ char should be escaped with \\) |
Requirements
Report Type: The report must be in a CSV type
Report Rows: Each entity in the report should have 1:1 connection between a Patch ID to an endpoint. It means that every row should represent a single vulnerability that is needed on a single endpoint.
Report Structure:
- JetPatch supports reports that have the headers row, or without headers at all.
- The report information should be divided into columns (not a single column with all the information inside the cell)
Report Information: Each entity should be consist of the following information):
- IP Address
- DNS Name
- Patch ID
- CVE List (Optional) - space-separated list of CVEs
Each of the needed information for the reporting entity should exist in a different column. Other information can also exist in the cell.
Vulnerability Scanner Parser Structure
After you verified that the report is valid for the JetPatch Vulnerability Scanner, the Vulnerability Parser can be customized.
The JetPatch Vulnerability Parser located in the "conf" folder, usually in /usr/share/tomcat/default/conf/intigua_vulnerability_parser.conf.json
The content of the JetPatch vulnerability Parser is a list of the parsers, to support multiple reports at the same time.
After making changes to this file, restart tomcat:
service tomcat restart
Parser Root Entities
Each Vulnerability Parser has the following JSON entities:
- "name" = (String) The name of the vulnerability Parser. This name will appear in the JetPatch console in multiple locations. The name of the Vulnerability Scanner is recommended.
- "enabled" = (Boolean) A flag to enable or disable the relevant Vulnerablilty Parser
- "config" = (List) Consist with the parser configuration:
- "type" = (String) The type of the report. At the moment JetPatch supports CSV type only
- "headerExists" = (Boolean) A flag to decide if there is a header row in the report.
- True - the data will be pulled based on the column name (can be configured below)
- False - the data will be pulled based on the index (can be configured below)
- "skipRowsUntilHeader" = (Number) If headers exist, how many rows in the report should JetPatch skip in order to be on the headers row.
- "columns" = (List) The columns data structure.
Example:
[
{
"name":"Nessus",
"enabled":true,
"config":[
{
"type":"csv",
"headerExists":true,
"skipRowsUntilHeader":0,
"columns":[......]
}
]
}
]
Parser "columns" Structure
The "column" values are representing the parser logic.
There are two types of columns:
Simple Column
Extracting the value from a defined cell.
If the report has a header row, JetPatch will take the value based on the column name.
Otherwise (no headers), JetPatch will take the values based on the indexed column, starting from 0.
- "name" = (String) the column name.
- "required" = (Boolean) Define if the optional data (like CVE) must be included in the report, or not.
- "index" = (Number) the column number. If this value is not needed (because the report is with headers) the value should be -1.
- "regex" = (List) A list of the possible regular expressions. Sometimes the information is presented in the cell is different based on the Vulnerability type of Endpoint OS. In this list, you should define all the possible regex.
- "value" = (String) the regex logic to pull the right information from the cell
- "group" = (Number) If the regex "value" is pulling different regex groups the "group" number will specify which group to take. Check the example below.
- "matchFullLine" = (Boolean, default=true) if found a match, get the whole line (true) or only the substring found (false)
Regex group example:
Need to pull the Advisory ID ("RHBA-2020:1155") from RHEL (RHBA-2020:1155)
Regex Value = ^RHEL.*\((RHBA-\d*[:-]\d*)\).*$
The matches from this regex will be:
- Full match - the whole line
- Group 1 - RHBA-2020:1155 = this is the vaule we want
Example - A "Column" entity in a report WITHOUT headers:
In this report, there are no headers and the IP value exists in the first column (index 0) of the report.
The IP value is all the text inside the cell (regex = .*)
...
"columns":[
{
"name":"IP",
"index":0,
"regex":[
{
"value":".*",
"group":0
}
]
},
...
]
...
Example = A "Column" entity in a report WITH headers:
In this report, there is a column named "IP Address" that has the IP value.
The IP value is all the text inside the cell (regex = .*)
...
"columns":[
{
"name":"IP Address",
"index":-1,
"regex":[
{
"value":".*",
"group":0
}
]
},
...
]
...
If-Then-Else Column
The "If-Then-Else" column is for fetching information based on other columns or in different structures.
For example, in one cell you have the OS type (Windows/Linux):
- If it is "Windows" - the Patch ID should be pulled from the "Solution" column or the "Plugin Name" (first found).
- Otherwise - the Patch ID should be pulled from the "Plugin Name" column.
Although eventually both Windows and Linux can pull the information from the "Plugin Name", the structure of the information can be different as well.
- If it is "Windows" - the "Plugin Name" regex should be (KB\\d+)
- Otherwise - the "Plugin Name" regex should be:
- For RHEL - RHEL.*\\((RHSA-\\d*[:-]\\d*)\\).*$
- For CentOS - ^CentOS.*\\((CESA-\\d*[:-]\\d*)\\).*$
The "If-Then-Else" column is a Simple Column, wrapped in an if statement:
- "type" = (String) Representing the "If-Then-Else" column. Should be always if
- "if" = (JSON Object) Representing the "if" statement. The result from the "if" statement will be true if a value returned from the defined regex.
- "type" = (String) Represent the operator to do between the tested columns:
- or - JetPatch will check the information from the defined columns (in order of appearance in the list). If JetPatch found a result in one column it won't continue to search for a result in the next columns and will execute the THEN block.
If nothing returned from all of the regex searches - JetPatch will execute the ELSE block. - and - JetPatch will check if each of the tested columns will have a return value. If all of them will return a value JetPatch will continue to the THEN block. If one column will return an empty result, it will continue to the ELSE block.
- or - JetPatch will check the information from the defined columns (in order of appearance in the list). If JetPatch found a result in one column it won't continue to search for a result in the next columns and will execute the THEN block.
- "columns" = (List) A list of a simple column object structure (as described above)
- "type" = (String) Represent the operator to do between the tested columns:
- "then" = (JSON Object) Representing the logic to apply if the "if" is statement is true.
- "type" = (String) Represent the operator to do between the columns:
- or - JetPatch will pull the information from the defined columns (in order of appearance in the list). If JetPatch found a result in one column it won't continue to search a result in the next columns.
- and - ????
- "columns" = (List) A list of a simple column object structure (as described above) to pull the information from this column/s.
- "type" = (String) Represent the operator to do between the columns:
- "else" = (JSON Object) Representing the logic to apply if the "if" is statement is false.
- "type" = (String) Represent the operator to do between the columns:
- or - JetPatch will pull the information from the defined columns (in order of appearance in the list). If JetPatch found a result in one column it won't continue to search a result in the next columns.
- and - ????
- "columns" = (List) A list of a simple column object structure (as described above) to pull the information from this column/s.
- "type" = (String) Represent the operator to do between the columns:
Notes:
- The "If-Then-Else" logic is that if the regex got a result for the "if" regex - it will continue to the "Then" block. Otherwise, it will continue to the "Else" block.
Example - "If-Then_Else" of a report WITH headers:
In this report, the Patch ID structure and location is depending on the "Family" information.
- The if is checking the entity family - if it's Windows it will continue to the then. Otherwise, it will go to the else.
- The then is pulling the Patch ID from the Plugin Name column or the Solution column. If it finds a value in the Plugin Name column (based on the defined regex) it will take this value as the Patch ID. If it didn't find, JetPatch will continue to the Solution column and will search it in it.
- The else is pulling the Patch ID from the Plugin Name. The value can exist in different formats (based on the Linux flavor). To support all structures, there are multiple regex. The first result to return will be the Patch ID value.
...
"columns":[
...
{
"type":"if",
"if": {
"type":"and",
"columns":[
{
"name":"Family",
"index":-1,
"regex":[
{
"value":"^Windows : Microsoft Bulletins$",
"group":0
}
]
}
]
},
"then": {
"type":"or",
"columns":[
{
"name":"Plugin Name",
"index":-1,
"regex":[
{
"value":"^(KB\\d+):.*$",
"group":1
}
]
},
{
"name":"Solution",
"index":-1,
"regex":[
{
"value":"(KB\\d+)",
"group":1,
"matchFullLine":false
}
]
}
]
},
"else": {
"type":"and",
"columns":[
{
"name":"Plugin Name",
"index":-1,
"regex":[
{
"value":"^RHEL.*\\((RHSA-\\d*[:-]\\d*)\\).*$",
"group":1
},
{
"value":"^CentOS.*\\((CESA-\\d*[:-]\\d*)\\).*$",
"group":1
},
{
"value":"^Oracle Linux.*\\((ELSA-\\d*[:-]\\d*)\\).*$",
"group":1
},
{
"value":"^Amazon Linux.*\\((ALAS-\\d*[:-]\\d*)\\).*$",
"group":1
}
]
}
]
}
},
...
]
...
Comments
0 comments
Please sign in to leave a comment.