If you are reading this blog post via a 3rd party source it is very likely that many parts of it will not render correctly (usually, the interactive graphs). Please view the post on dogesec.com for the full interactive viewing experience.
tl;dr
Developing on last weeks post, I show you how to construct STIX Patterns to automatically flag which products are affected by published CVEs.
Pre-reading
- My tutorial on STIX Patterns explains how they can be constructed
- My last post explains how to interpret the CPE configorations affecting a CVE returned by the NVD APIs. This is essential knowledge to be able to define the logic of a STIX pattern.
STIX software objects and CPEs
STIX patterns must contain a reference to a property in a STIX object.
Luckily, the STIX Software object contains a cpe
property.
Thus I can refer to CPE match strings returned by the NVD APIs as follows;
software.cpe = '<CPE MATCH STRING>'
e.g.
software.cpe = 'cpe:2.3:a:dell:powerscale_onefs:9.0.0:*:*:*:*:*:*:*'
The basics of pattern construction
At a high-level, the STIX patterns are constructed like so;
Let me explain…
Match criteria grouping parenthesis
As covered in the last post, the matchCriteriaId
lookup might contain multiple CPEs in its response.
To capture this in the pattern, all CPEs returned by a single match criteria ID are wrapped in parenthesis and joined with the OR
operator.
e.g. 86619D7A-ACB6-489C-9C29-37C6018E5B4B
returns 3 CPEs producing a pattern a group of 3 CPEs in the pattern wrapped in parenthesis, as follows;
(software.cpe = 'cpe:2.3:o:tesla:model_3_firmware:-:*:*:*:*:*:*:*' OR software.cpe = 'cpe:2.3:o:tesla:model_3_firmware:11.0:*:*:*:*:*:*:*' OR software.cpe = 'cpe:2.3:o:tesla:model_3_firmware:2022-03-26:*:*:*:*:*:*:*')
Note, even if only one CPE is returned for a match criteria API, the CPE is still wrapped up in brackets to indicate it is part of a CPE match string group.
cpeMatch grouping square brackets
All items inside a cpematch, once match criteria responses have been obtained are captured in square brackets. The final pattern is wrapped in parentheses.
A cpematch
will have a corresponding operator
property. This defines how all the CPE match entries are joined together.
For example CVE-2022-29098 contains 5 items in the cpeMatch once analysed against the match criteria API, so only one set of square brackets is used
( [ (software.cpe='cpe:2.3:a:dell:powerscale_onefs:9.0.0:*:*:*:*:*:*:*') OR (software.cpe='cpe:2.3:a:dell:powerscale_onefs:9.1.0:*:*:*:*:*:*:*') OR (software.cpe='cpe:2.3:a:dell:powerscale_onefs:9.1.1:*:*:*:*:*:*:*') OR (software.cpe='cpe:2.3:a:dell:powerscale_onefs:9.2.0:*:*:*:*:*:*:*') OR (software.cpe='cpe:2.3:a:dell:powerscale_onefs:9.2.1:*:*:*:*:*:*:*') OR (software.cpe='cpe:2.3:a:dell:powerscale_onefs:9.3.0:*:*:*:*:*:*:*') ] )
However in CVE-2022-27948 there are two cpeMatch entries, which result in two square brackets in the pattern. The two cpeMatch entries are joined with an AND
operator as this is the operator
defined at the nodes
level in the CVE API response.
( [ (software.cpe = 'cpe:2.3:o:tesla:model_3_firmware:-:*:*:*:*:*:*:*' OR software.cpe = 'cpe:2.3:o:tesla:model_3_firmware:11.0:*:*:*:*:*:*:*' OR software.cpe = 'cpe:2.3:o:tesla:model_3_firmware:2022-03-26:*:*:*:*:*:*:*') OR (software.cpe = 'cpe:2.3:o:tesla:model_s_firmware:-:*:*:*:*:*:*:*' OR software.cpe = 'cpe:2.3:o:tesla:model_s_firmware:2022-03-26:*:*:*:*:*:*:*') OR (software.cpe = 'cpe:2.3:o:tesla:model_x_firmware:-:*:*:*:*:*:*:*' OR software.cpe = 'cpe:2.3:o:tesla:model_x_firmware:2020-11-23:*:*:*:*:*:*:*' OR software.cpe = 'cpe:2.3:o:tesla:model_x_firmware:2022-03-26:*:*:*:*:*:*:*') ] AND [ (software.cpe = 'cpe:2.3:h:tesla:model_3:-:*:*:*:*:*:*:*') OR (software.cpe = 'cpe:2.3:h:tesla:model_s:-:*:*:*:*:*:*:*') OR (software.cpe = 'cpe:2.3:h:tesla:model_x:-:*:*:*:*:*:*:*') ] )
Dealing with node groupings
In CVEs with advance relationships there might be more than one node reported. Nodes contain one or more cpeMatch groups.
For example, CVE-2019-18939 has 4 nodes containing cpematches.
Content inside a node is captured in parenthesis. For example, the 4 nodes for CVE-2019-18939
( [ (software.cpe = 'cpe:2.3:a:hm-print_project:hm-print:1.2a:*:*:*:*:*:*:*') AND (software.cpe = 'cpe:2.3:h:eq-3:homematic_ccu2:-:*:*:*:*:*:*:*') AND (software.cpe = 'cpe:2.3:o:eq-3:homematic_ccu2_firmware:2.47.20:*:*:*:*:*:*:*') ] ) OR ( [ (software.cpe = 'cpe:2.3:a:hm-print_project:hm-print:1.2:*:*:*:*:*:*:*') AND (software.cpe = 'cpe:2.3:h:eq-3:homematic_ccu3:-:*:*:*:*:*:*:*') AND (software.cpe = 'cpe:2.3:o:eq-3:homematic_ccu3_firmware:3.47.18:*:*:*:*:*:*:*') ] ) OR ( [ (software.cpe = 'cpe:2.3:a:hm-print_project:hm-print:1.2a:*:*:*:*:*:*:*') AND (software.cpe = 'cpe:2.3:h:eq-3:homematic_ccu3:-:*:*:*:*:*:*:*') AND (software.cpe = 'cpe:2.3:o:eq-3:homematic_ccu3_firmware:3.47.18:*:*:*:*:*:*:*') ] ) OR ( [ (software.cpe = 'cpe:2.3:a:hm-print_project:hm-print:1.2:*:*:*:*:*:*:*') AND (software.cpe = 'cpe:2.3:h:eq-3:homematic_ccu2:-:*:*:*:*:*:*:*') AND (software.cpe = 'cpe:2.3:o:eq-3:homematic_ccu2_firmware:2.47.20:*:*:*:*:*:*:*') ] )
Node groups are always joined with an OR
operator.
Using real CVEs to demonstrate with examples
Not all CVEs have CPE nodes
Some CVEs (typically older ones, but also ones yet to be analysed), e.g. CVE-1999-0635
, do not contain any CPE node
configurations.
Simple Relationships
CVE-2022-29098 offers a good example of simple relationships.
GET https://services.nvd.nist.gov/rest/json/cves/2.0?cveId=CVE-2022-29098
In this case, the 6 configurations variations that lead to matches inside one nodes
.
"configurations": [
{
"nodes": [
{
"operator": "OR",
"negate": false,
"cpeMatch": [
{
"vulnerable": true,
"criteria": "cpe:2.3:a:dell:powerscale_onefs:9.0.0:*:*:*:*:*:*:*",
"matchCriteriaId": "30687628-5C7F-4BB5-B990-93703294FDF0"
},
{
"vulnerable": true,
"criteria": "cpe:2.3:a:dell:powerscale_onefs:9.1.0:*:*:*:*:*:*:*",
"matchCriteriaId": "68291D44-DBE1-4923-A848-04E64288DC23"
},
{
"vulnerable": true,
"criteria": "cpe:2.3:a:dell:powerscale_onefs:9.1.1:*:*:*:*:*:*:*",
"matchCriteriaId": "DCC55FA4-AD91-4DA6-B60E-A4E34DDAE95A"
},
{
"vulnerable": true,
"criteria": "cpe:2.3:a:dell:powerscale_onefs:9.2.0:*:*:*:*:*:*:*",
"matchCriteriaId": "B948CD53-3D17-4230-9B77-FCE8E0E548B9"
},
{
"vulnerable": true,
"criteria": "cpe:2.3:a:dell:powerscale_onefs:9.2.1:*:*:*:*:*:*:*",
"matchCriteriaId": "5AB99A1A-8DD3-4DDE-B70C-0E91D1D3B682"
},
{
"vulnerable": true,
"criteria": "cpe:2.3:a:dell:powerscale_onefs:9.3.0:*:*:*:*:*:*:*",
"matchCriteriaId": "61F14753-D64C-4E8B-AA94-07E014848B4D"
}
]
}
]
}
],
cpe:2.3:a:dell:powerscale_onefs:9.0.0:*:*:*:*:*:*:*
(30687628-5C7F-4BB5-B990-93703294FDF0) OR
,cpe:2.3:a:dell:powerscale_onefs:9.1.0:*:*:*:*:*:*:*
(68291D44-DBE1-4923-A848-04E64288DC23
)OR
,cpe:2.3:a:dell:powerscale_onefs:9.1.1:*:*:*:*:*:*:*
(DCC55FA4-AD91-4DA6-B60E-A4E34DDAE95A
)OR
,cpe:2.3:a:dell:powerscale_onefs:9.2.0:*:*:*:*:*:*:*
(B948CD53-3D17-4230-9B77-FCE8E0E548B9
)OR
,cpe:2.3:a:dell:powerscale_onefs:9.2.1:*:*:*:*:*:*:*
(5AB99A1A-8DD3-4DDE-B70C-0E91D1D3B682
)OR
,cpe:2.3:a:dell:powerscale_onefs:9.3.0:*:*:*:*:*:*:*
(61F14753-D64C-4E8B-AA94-07E014848B4D
)
Now the match criteria API must be checked for each entry. For example, 30687628-5C7F-4BB5-B990-93703294FDF0
GET https://services.nvd.nist.gov/rest/json/cpematch/2.0?matchCriteriaId=30687628-5C7F-4BB5-B990-93703294FDF0
Returns;
"matchStrings": [
{
"matchString": {
"matchCriteriaId": "30687628-5C7F-4BB5-B990-93703294FDF0",
"criteria": "cpe:2.3:a:dell:powerscale_onefs:9.0.0:*:*:*:*:*:*:*",
"lastModified": "2022-06-07T14:26:54.180",
"cpeLastModified": "2021-04-26T17:43:46.887",
"created": "2021-04-26T17:43:45.753",
"status": "Active",
"matches": [
{
"cpeName": "cpe:2.3:a:dell:powerscale_onefs:9.0.0:*:*:*:*:*:*:*",
"cpeNameId": "2B8F2852-98F4-44E1-BBF2-6597C2481DB1"
}
]
}
}
]
}
As you can see only one CPE belongs to this matchCriteriaId
, so only one CPE will be used for this entry in the pattern. All matchCriteriaId
’s for this CVE return just one CPE entry, so only that CPE is used in the pattern.
As such, in this example the pattern
in the Indicator would be as follow;
"pattern": "( [ (software.cpe='cpe:2.3:a:dell:powerscale_onefs:9.0.0:*:*:*:*:*:*:*') OR (software.cpe='cpe:2.3:a:dell:powerscale_onefs:9.1.0:*:*:*:*:*:*:*') OR (software.cpe='cpe:2.3:a:dell:powerscale_onefs:9.1.1:*:*:*:*:*:*:*') OR (software.cpe='cpe:2.3:a:dell:powerscale_onefs:9.2.0:*:*:*:*:*:*:*') OR (software.cpe='cpe:2.3:a:dell:powerscale_onefs:9.2.1:*:*:*:*:*:*:*') OR (software.cpe='cpe:2.3:a:dell:powerscale_onefs:9.3.0:*:*:*:*:*:*:*') ] )"
The CPE statements are joined by OR
as this is the top level operator
in the API response (of course, in many cases this can be an AND
).
Running On/With Relationships
Let me demonstrate how more complex Relationships are modelled using the example CVE-2022-27948.
In total there are 24 possible product combinations that are vulnerable in this CVE (see the last post for an explanation).
GET https://services.nvd.nist.gov/rest/json/cves/2.0?cveId=CVE-2022-27948
"configurations": [
{
"operator": "AND",
"nodes": [
{
"operator": "OR",
"negate": false,
"cpeMatch": [
{
"vulnerable": true,
"criteria": "cpe:2.3:o:tesla:model_3_firmware:*:*:*:*:*:*:*:*",
"versionEndIncluding": "2022-03-26",
"matchCriteriaId": "86619D7A-ACB6-489C-9C29-37C6018E5B4B"
},
{
"vulnerable": true,
"criteria": "cpe:2.3:o:tesla:model_s_firmware:*:*:*:*:*:*:*:*",
"versionEndIncluding": "2022-03-26",
"matchCriteriaId": "FD68704D-C711-491F-B278-B02C6866738C"
},
{
"vulnerable": true,
"criteria": "cpe:2.3:o:tesla:model_x_firmware:*:*:*:*:*:*:*:*",
"versionEndIncluding": "2022-03-26",
"matchCriteriaId": "C3517683-8493-4D0D-9792-5C9034B1F0B3"
}
]
},
{
"operator": "OR",
"negate": false,
"cpeMatch": [
{
"vulnerable": false,
"criteria": "cpe:2.3:h:tesla:model_3:-:*:*:*:*:*:*:*",
"matchCriteriaId": "825A79FD-C872-4564-9782-83BEEADDF5D9"
},
{
"vulnerable": false,
"criteria": "cpe:2.3:h:tesla:model_s:-:*:*:*:*:*:*:*",
"matchCriteriaId": "8D28E699-B843-4641-9BA6-406D88231E7C"
},
{
"vulnerable": false,
"criteria": "cpe:2.3:h:tesla:model_x:-:*:*:*:*:*:*:*",
"matchCriteriaId": "C550FF8A-58ED-4265-B33F-10AFDEA95519"
}
]
}
]
}
],
Here there is one nodes
again, however this time there are also two cpeMatch
es inside it.
Note how in the Simple Relationships pattern all CPE key values were wrapped in square brackets ([]
). Each CPE inside a cpeMatch
is wrapped in square brackets.
So in this example I get pattern that will look like;
"pattern": "[ (software.cpe = 'A') OR (software.cpe = 'B') OR (software.cpe = 'N') ] AND [ (software.cpe = '1') OR (software.cpe = '2') OR (software.cpe = '0') ]"
Note how the AND
joins the two square brackets, that’s because the top level operator
in the CVE response shown above is an AND
. The CPE statements are joined by OR
as this is the top level operator
in the API response (of course, in many cases this can be an AND
).
However, I must also check the matchCriteriaId
before constructing the pattern to ensure it contains all possible CPEs. Let me use 86619D7A-ACB6-489C-9C29-37C6018E5B4B
as an example;
GET https://services.nvd.nist.gov/rest/json/cpematch/2.0?matchCriteriaId=86619D7A-ACB6-489C-9C29-37C6018E5B4B
"matchStrings": [
{
"matchString": {
"matchCriteriaId": "86619D7A-ACB6-489C-9C29-37C6018E5B4B",
"criteria": "cpe:2.3:o:tesla:model_3_firmware:*:*:*:*:*:*:*:*",
"versionEndIncluding": "2022-03-26",
"lastModified": "2022-10-05T14:00:34.840",
"cpeLastModified": "2022-10-05T14:00:34.840",
"created": "2022-04-04T12:37:32.813",
"status": "Active",
"matches": [
{
"cpeName": "cpe:2.3:o:tesla:model_3_firmware:-:*:*:*:*:*:*:*",
"cpeNameId": "979F9EB6-C9F6-49EE-9FED-2ED17E400E86"
},
{
"cpeName": "cpe:2.3:o:tesla:model_3_firmware:11.0:*:*:*:*:*:*:*",
"cpeNameId": "62DCA7AD-A796-486F-8FB6-DEACC078D402"
},
{
"cpeName": "cpe:2.3:o:tesla:model_3_firmware:2022-03-26:*:*:*:*:*:*:*",
"cpeNameId": "F010C8B7-83E9-45FB-A5D4-26EDF34EC312"
}
]
}
}
]
Note, this returns 3 CPEs for the first CPE ID (match criteria) shown in the NVD response. Essentially what this is saying is cpe:2.3:o:tesla:model_3_firmware:*:*:*:*:*:*:*:*
(86619D7A-ACB6-489C-9C29-37C6018E5B4B
) actually contains 3 CPEs; cpe:2.3:o:tesla:model_3_firmware:-:*:*:*:*:*:*:*
, or cpe:2.3:o:tesla:model_3_firmware:11.0:*:*:*:*:*:*:*
or cpe:2.3:o:tesla:model_3_firmware:2022-03-26:*:*:*:*:*:*:*
. Note, when multiple values are returned in the match criteria response, they are always joined with an OR
inside the pattern
.
Some of the other match criteria IDs also return more than one response. After querying all the match criteria APIs, a pattern as follows results;
"pattern": "( [ (software.cpe = 'cpe:2.3:o:tesla:model_3_firmware:-:*:*:*:*:*:*:*' OR software.cpe = 'cpe:2.3:o:tesla:model_3_firmware:11.0:*:*:*:*:*:*:*' OR software.cpe = 'cpe:2.3:o:tesla:model_3_firmware:2022-03-26:*:*:*:*:*:*:*') OR (software.cpe = 'cpe:2.3:o:tesla:model_s_firmware:-:*:*:*:*:*:*:*' OR software.cpe = 'cpe:2.3:o:tesla:model_s_firmware:2022-03-26:*:*:*:*:*:*:*') OR (software.cpe = 'cpe:2.3:o:tesla:model_x_firmware:-:*:*:*:*:*:*:*' OR software.cpe = 'cpe:2.3:o:tesla:model_x_firmware:2020-11-23:*:*:*:*:*:*:*' OR software.cpe = 'cpe:2.3:o:tesla:model_x_firmware:2022-03-26:*:*:*:*:*:*:*') ] AND [ (software.cpe = 'cpe:2.3:h:tesla:model_3:-:*:*:*:*:*:*:*') OR (software.cpe = 'cpe:2.3:h:tesla:model_s:-:*:*:*:*:*:*:*') OR (software.cpe = 'cpe:2.3:h:tesla:model_x:-:*:*:*:*:*:*:*') ] )",
Advanced Relationships
I will use CVE-2019-18939 to demonstrate another more complex configuration
.
GET https://services.nvd.nist.gov/rest/json/cves/2.0?cveId=CVE-2019-18939
"configurations": [
{
"nodes": [
{
"operator": "AND",
"negate": false,
"cpeMatch": [
{
"vulnerable": true,
"criteria": "cpe:2.3:a:hm-print_project:hm-print:1.2a:*:*:*:*:*:*:*",
"matchCriteriaId": "286DA904-5631-4AAF-86DE-97C23982D2C5"
},
{
"vulnerable": false,
"criteria": "cpe:2.3:h:eq-3:homematic_ccu2:-:*:*:*:*:*:*:*",
"matchCriteriaId": "9C2CF19C-7EDE-4E3C-A736-E6736FF03FDC"
},
{
"vulnerable": true,
"criteria": "cpe:2.3:o:eq-3:homematic_ccu2_firmware:2.47.20:*:*:*:*:*:*:*",
"matchCriteriaId": "38BE17DA-7C5E-427E-B824-151EB27CFF26"
}
]
}
]
},
{
"nodes": [
{
"operator": "AND",
"negate": false,
"cpeMatch": [
{
"vulnerable": true,
"criteria": "cpe:2.3:a:hm-print_project:hm-print:1.2:*:*:*:*:*:*:*",
"matchCriteriaId": "F5D8290F-3541-4452-99CB-0766CDC59073"
},
{
"vulnerable": false,
"criteria": "cpe:2.3:h:eq-3:homematic_ccu3:-:*:*:*:*:*:*:*",
"matchCriteriaId": "33113AD0-F378-49B2-BCFC-C57B52FD3A04"
},
{
"vulnerable": true,
"criteria": "cpe:2.3:o:eq-3:homematic_ccu3_firmware:3.47.18:*:*:*:*:*:*:*",
"matchCriteriaId": "285F4E29-E299-4F83-9F7E-BB19933AD654"
}
]
}
]
},
{
"nodes": [
{
"operator": "AND",
"negate": false,
"cpeMatch": [
{
"vulnerable": true,
"criteria": "cpe:2.3:a:hm-print_project:hm-print:1.2a:*:*:*:*:*:*:*",
"matchCriteriaId": "286DA904-5631-4AAF-86DE-97C23982D2C5"
},
{
"vulnerable": false,
"criteria": "cpe:2.3:h:eq-3:homematic_ccu3:-:*:*:*:*:*:*:*",
"matchCriteriaId": "33113AD0-F378-49B2-BCFC-C57B52FD3A04"
},
{
"vulnerable": true,
"criteria": "cpe:2.3:o:eq-3:homematic_ccu3_firmware:3.47.18:*:*:*:*:*:*:*",
"matchCriteriaId": "285F4E29-E299-4F83-9F7E-BB19933AD654"
}
]
}
]
},
{
"nodes": [
{
"operator": "AND",
"negate": false,
"cpeMatch": [
{
"vulnerable": true,
"criteria": "cpe:2.3:a:hm-print_project:hm-print:1.2:*:*:*:*:*:*:*",
"matchCriteriaId": "F5D8290F-3541-4452-99CB-0766CDC59073"
},
{
"vulnerable": false,
"criteria": "cpe:2.3:h:eq-3:homematic_ccu2:-:*:*:*:*:*:*:*",
"matchCriteriaId": "9C2CF19C-7EDE-4E3C-A736-E6736FF03FDC"
},
{
"vulnerable": true,
"criteria": "cpe:2.3:o:eq-3:homematic_ccu2_firmware:2.47.20:*:*:*:*:*:*:*",
"matchCriteriaId": "38BE17DA-7C5E-427E-B824-151EB27CFF26"
}
]
}
]
}
],
This gives four patterns (note, all the match criteria IDs return just one result)…
Pattern one;
"pattern": "[ (software.cpe = 'cpe:2.3:a:hm-print_project:hm-print:1.2a:*:*:*:*:*:*:*') AND (software.cpe = 'cpe:2.3:h:eq-3:homematic_ccu2:-:*:*:*:*:*:*:*') AND (software.cpe = 'cpe:2.3:o:eq-3:homematic_ccu2_firmware:2.47.20:*:*:*:*:*:*:*') ]"
Pattern two;
"pattern": "[ (software.cpe = 'cpe:2.3:a:hm-print_project:hm-print:1.2:*:*:*:*:*:*:*') AND (software.cpe = 'cpe:2.3:h:eq-3:homematic_ccu3:-:*:*:*:*:*:*:*') AND (software.cpe = 'cpe:2.3:o:eq-3:homematic_ccu3_firmware:3.47.18:*:*:*:*:*:*:*') ]"
Pattern three;
"pattern": "[ (software.cpe = 'cpe:2.3:a:hm-print_project:hm-print:1.2a:*:*:*:*:*:*:*') AND (software.cpe = 'cpe:2.3:h:eq-3:homematic_ccu3:-:*:*:*:*:*:*:*') AND (software.cpe = 'cpe:2.3:o:eq-3:homematic_ccu3_firmware:3.47.18:*:*:*:*:*:*:*') ]"
Pattern four;
"pattern": "[ (software.cpe = 'cpe:2.3:a:hm-print_project:hm-print:1.2:*:*:*:*:*:*:*') AND (software.cpe = 'cpe:2.3:h:eq-3:homematic_ccu2:-:*:*:*:*:*:*:*') AND (software.cpe = 'cpe:2.3:o:eq-3:homematic_ccu2_firmware:2.47.20:*:*:*:*:*:*:*') ]"
Which form a single pattern inside the Indicator SDO as follows (each above pattern is joined with OR
because these is no top level operator);
"pattern": "( [ (software.cpe = 'cpe:2.3:a:hm-print_project:hm-print:1.2a:*:*:*:*:*:*:*') AND (software.cpe = 'cpe:2.3:h:eq-3:homematic_ccu2:-:*:*:*:*:*:*:*') AND (software.cpe = 'cpe:2.3:o:eq-3:homematic_ccu2_firmware:2.47.20:*:*:*:*:*:*:*') ] ) OR ( [ (software.cpe = 'cpe:2.3:a:hm-print_project:hm-print:1.2:*:*:*:*:*:*:*') AND (software.cpe = 'cpe:2.3:h:eq-3:homematic_ccu3:-:*:*:*:*:*:*:*') AND (software.cpe = 'cpe:2.3:o:eq-3:homematic_ccu3_firmware:3.47.18:*:*:*:*:*:*:*') ] ) OR ( [ (software.cpe = 'cpe:2.3:a:hm-print_project:hm-print:1.2a:*:*:*:*:*:*:*') AND (software.cpe = 'cpe:2.3:h:eq-3:homematic_ccu3:-:*:*:*:*:*:*:*') AND (software.cpe = 'cpe:2.3:o:eq-3:homematic_ccu3_firmware:3.47.18:*:*:*:*:*:*:*') ] ) OR ( [ (software.cpe = 'cpe:2.3:a:hm-print_project:hm-print:1.2:*:*:*:*:*:*:*') AND (software.cpe = 'cpe:2.3:h:eq-3:homematic_ccu2:-:*:*:*:*:*:*:*') AND (software.cpe = 'cpe:2.3:o:eq-3:homematic_ccu2_firmware:2.47.20:*:*:*:*:*:*:*') ] )",
(More) Advanced Relationships
As another example of an advance relationship, I’ll use CVE-2020-3543.
GET https://services.nvd.nist.gov/rest/json/cves/2.0?cveId=CVE-2020-3543
"configurations": [
{
"operator": "AND",
"nodes": [
{
"operator": "OR",
"negate": false,
"cpeMatch": [
{
"vulnerable": true,
"criteria": "cpe:2.3:o:cisco:8000p_ip_camera_firmware:1.0.9-4:*:*:*:*:*:*:*",
"matchCriteriaId": "955AED3C-3ED2-4467-AAA5-510521CD56E7"
}
]
},
{
"operator": "OR",
"negate": false,
"cpeMatch": [
{
"vulnerable": false,
"criteria": "cpe:2.3:h:cisco:8000p_ip_camera:-:*:*:*:*:*:*:*",
"matchCriteriaId": "EC586459-C532-4A89-8C43-58DA17181A38"
}
]
}
]
},
{
"operator": "AND",
"nodes": [
{
"operator": "OR",
"negate": false,
"cpeMatch": [
{
"vulnerable": true,
"criteria": "cpe:2.3:o:cisco:8020_ip_camera_firmware:1.0.9-4:*:*:*:*:*:*:*",
"matchCriteriaId": "0C59F1EE-2E1C-4001-A9A7-73B92F9827AB"
}
]
},
{
"operator": "OR",
"negate": false,
"cpeMatch": [
{
"vulnerable": false,
"criteria": "cpe:2.3:h:cisco:8020_ip_camera:-:*:*:*:*:*:*:*",
"matchCriteriaId": "B783A438-0D5A-4BA7-97E0-0FA917045B37"
}
]
}
]
},
{
"operator": "AND",
"nodes": [
{
"operator": "OR",
"negate": false,
"cpeMatch": [
{
"vulnerable": true,
"criteria": "cpe:2.3:o:cisco:8030_ip_camera_firmware:1.0.9-4:*:*:*:*:*:*:*",
"matchCriteriaId": "DD32F59C-A08D-4692-9F79-5F8F419B5B18"
}
]
},
{
"operator": "OR",
"negate": false,
"cpeMatch": [
{
"vulnerable": false,
"criteria": "cpe:2.3:h:cisco:8030_ip_camera:-:*:*:*:*:*:*:*",
"matchCriteriaId": "42E1CC6F-8A71-4012-ABF8-F0DF96B23949"
}
]
}
]
},
{
"operator": "AND",
"nodes": [
{
"operator": "OR",
"negate": false,
"cpeMatch": [
{
"vulnerable": true,
"criteria": "cpe:2.3:o:cisco:8070_ip_camera_firmware:1.0.9-4:*:*:*:*:*:*:*",
"matchCriteriaId": "934836A7-DBBD-44CF-8CE5-28C2FC7AC754"
}
]
},
{
"operator": "OR",
"negate": false,
"cpeMatch": [
{
"vulnerable": false,
"criteria": "cpe:2.3:h:cisco:8070_ip_camera:-:*:*:*:*:*:*:*",
"matchCriteriaId": "BD2510BB-580C-4826-BE9D-4879F2B8BDA5"
}
]
}
]
},
{
"operator": "AND",
"nodes": [
{
"operator": "OR",
"negate": false,
"cpeMatch": [
{
"vulnerable": true,
"criteria": "cpe:2.3:o:cisco:8400_ip_camera_firmware:1.0.9-4:*:*:*:*:*:*:*",
"matchCriteriaId": "4E28EB73-9705-4BED-9969-50DE456F8B5F"
}
]
},
{
"operator": "OR",
"negate": false,
"cpeMatch": [
{
"vulnerable": false,
"criteria": "cpe:2.3:h:cisco:8400_ip_camera:-:*:*:*:*:*:*:*",
"matchCriteriaId": "12067AE1-9A55-43BE-8C75-849E060AF41A"
}
]
}
]
},
{
"operator": "AND",
"nodes": [
{
"operator": "OR",
"negate": false,
"cpeMatch": [
{
"vulnerable": true,
"criteria": "cpe:2.3:o:cisco:8620_ip_camera_firmware:1.0.9-4:*:*:*:*:*:*:*",
"matchCriteriaId": "D84B5451-961F-4118-B288-C94CDEC6D40A"
}
]
},
{
"operator": "OR",
"negate": false,
"cpeMatch": [
{
"vulnerable": false,
"criteria": "cpe:2.3:h:cisco:8620_ip_camera:-:*:*:*:*:*:*:*",
"matchCriteriaId": "AA06EF29-7996-4916-90E1-6A569EB95C6B"
}
]
}
]
},
{
"operator": "AND",
"nodes": [
{
"operator": "OR",
"negate": false,
"cpeMatch": [
{
"vulnerable": true,
"criteria": "cpe:2.3:o:cisco:8630_ip_camera_firmware:1.0.9-4:*:*:*:*:*:*:*",
"matchCriteriaId": "D1397782-897F-44FB-A42D-5BAEF0CDAB77"
}
]
},
{
"operator": "OR",
"negate": false,
"cpeMatch": [
{
"vulnerable": false,
"criteria": "cpe:2.3:h:cisco:8630_ip_camera:-:*:*:*:*:*:*:*",
"matchCriteriaId": "3214D558-A6FF-4B03-947B-40AD12355235"
}
]
}
]
},
{
"operator": "AND",
"nodes": [
{
"operator": "OR",
"negate": false,
"cpeMatch": [
{
"vulnerable": true,
"criteria": "cpe:2.3:o:cisco:8930_speed_dome_ip_camera_firmware:1.0.9-4:*:*:*:*:*:*:*",
"matchCriteriaId": "37D529B4-C32B-4DFE-A216-C7A18228DA15"
}
]
},
{
"operator": "OR",
"negate": false,
"cpeMatch": [
{
"vulnerable": false,
"criteria": "cpe:2.3:h:cisco:8930_speed_dome_ip_camera:-:*:*:*:*:*:*:*",
"matchCriteriaId": "39E0E98A-F382-4AA8-B940-78A78C99736A"
}
]
}
]
}
],
Here the cpematch operators (always OR
) are redundant, because these is only ever one cpematch object. This time there is a top level operator
for each node, because there is more than one cpeMatch
in each node. In this case the operator
is always AND
.
The matchCriteriaId
in all nodes only return one CPE, so I get the following STIX patterns for each node;
Pattern one;
"pattern": "[ (software.cpe = 'cpe:2.3:o:cisco:8000p_ip_camera_firmware:1.0.9-4:*:*:*:*:*:*:*') AND (software.cpe = 'cpe:2.3:h:cisco:8000p_ip_camera:-:*:*:*:*:*:*:*') ]"
Pattern two;
"pattern": "[ (software.cpe = 'cpe:2.3:o:cisco:8020_ip_camera_firmware:1.0.9-4:*:*:*:*:*:*:*') AND (software.cpe = 'cpe:2.3:h:cisco:8020_ip_camera:-:*:*:*:*:*:*:*') ]"
Pattern three;
"pattern": "[ (software.cpe = 'cpe:2.3:o:cisco:8030_ip_camera_firmware:1.0.9-4:*:*:*:*:*:*:*') AND (software.cpe = 'cpe:2.3:h:cisco:8030_ip_camera:-:*:*:*:*:*:*:*') ]"
Pattern four;
"pattern": "[ (software.cpe = 'cpe:2.3:o:cisco:8070_ip_camera_firmware:1.0.9-4:*:*:*:*:*:*:*') AND (software.cpe = 'cpe:2.3:h:cisco:8070_ip_camera:-:*:*:*:*:*:*:*') ]"
Pattern five;
"pattern": "[ (software.cpe = 'cpe:2.3:o:cisco:8400_ip_camera_firmware:1.0.9-4:*:*:*:*:*:*:*') AND (software.cpe = 'cpe:2.3:h:cisco:8400_ip_camera:-:*:*:*:*:*:*:*') ]"
Pattern six;
"pattern": "[ (software.cpe = 'cpe:2.3:o:cisco:8620_ip_camera_firmware:1.0.9-4:*:*:*:*:*:*:*') AND (software.cpe = 'cpe:2.3:h:cisco:8620_ip_camera:-:*:*:*:*:*:*:*') ]"
Pattern seven;
"pattern": "[ (software.cpe = 'cpe:2.3:o:cisco:8630_ip_camera_firmware:1.0.9-4:*:*:*:*:*:*:*') AND (software.cpe = 'cpe:2.3:h:cisco:8630_ip_camera:-:*:*:*:*:*:*:*') ]"
Pattern eight;
"pattern": "[ (software.cpe = 'cpe:2.3:o:cisco:8930_speed_dome_ip_camera_firmware:1.0.9-4:*:*:*:*:*:*:*') AND (software.cpe = 'cpe:2.3:h:cisco:8930_speed_dome_ip_camera:-:*:*:*:*:*:*:*') ]"
This will create a final pattern with all 8 patterns, joined with an AND
statement, as this is the top level operator. Here is what it would look like
"pattern": "( [ (software.cpe = 'cpe:2.3:o:cisco:8000p_ip_camera_firmware:1.0.9-4:*:*:*:*:*:*:*') OR (software.cpe = 'cpe:2.3:h:cisco:8000p_ip_camera:-:*:*:*:*:*:*:*') ] ) AND ( [ (software.cpe = 'cpe:2.3:o:cisco:8020_ip_camera_firmware:1.0.9-4:*:*:*:*:*:*:*') OR (software.cpe = 'cpe:2.3:h:cisco:8020_ip_camera:-:*:*:*:*:*:*:*') ] ) AND ( [ (software.cpe = 'cpe:2.3:o:cisco:8030_ip_camera_firmware:1.0.9-4:*:*:*:*:*:*:*') OR (software.cpe = 'cpe:2.3:h:cisco:8030_ip_camera:-:*:*:*:*:*:*:*') ] ) AND ( [ (software.cpe = 'cpe:2.3:o:cisco:8070_ip_camera_firmware:1.0.9-4:*:*:*:*:*:*:*') OR (software.cpe = 'cpe:2.3:h:cisco:8070_ip_camera:-:*:*:*:*:*:*:*') ] ) AND ( [ (software.cpe = 'cpe:2.3:o:cisco:8400_ip_camera_firmware:1.0.9-4:*:*:*:*:*:*:*') OR (software.cpe = 'cpe:2.3:h:cisco:8400_ip_camera:-:*:*:*:*:*:*:*') ] ) AND ( [ (software.cpe = 'cpe:2.3:o:cisco:8620_ip_camera_firmware:1.0.9-4:*:*:*:*:*:*:*') OR (software.cpe = 'cpe:2.3:h:cisco:8620_ip_camera:-:*:*:*:*:*:*:*') ] ) AND ( [ (software.cpe = 'cpe:2.3:o:cisco:8630_ip_camera_firmware:1.0.9-4:*:*:*:*:*:*:*') OR (software.cpe = 'cpe:2.3:h:cisco:8630_ip_camera:-:*:*:*:*:*:*:*') ] ) AND ( [ (software.cpe = 'cpe:2.3:o:cisco:8930_speed_dome_ip_camera_firmware:1.0.9-4:*:*:*:*:*:*:*') OR (software.cpe = 'cpe:2.3:h:cisco:8930_speed_dome_ip_camera:-:*:*:*:*:*:*:*') ] )",
The problem with this approach
Whilst these patterns will match software in various configorations, the STIX pattern won’t tell you which product is actually vulnerable.
As such, you will also need to capture a list of vulnerable CPEs in the pattern alongside the rule so that when a detection is made it is possible to determine which product is vulnerable.
Our solution to this is to store this information in a custom property x_cpes.vulnerable
in the Indicator objects, in addition to the pattern
property.
Our full implementation
If you’re interested to see this implemented in real code, check out cve2stix. cve2stix converts CVEs published by the NVD into STIX objects, including Indicators with STIX pattern generated as I have described above.
Vulmatch
Straightforward vulnerability management. Know when software you use is vulnerable, how it is being exploited, and how to detect an attack.
Discuss this post
Head on over to the DOGESEC community to discuss this post.
Never miss an update
Sign up to receive new articles in your inbox as they published.