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
Joining the data held in disparate knowledge bases, including linking MITRE ATT&CK to CVEs, creates a much richer context for intelligence. Let me show you the logic of an open-source tool we built to do just that.
Overview
If you’ve ever browsed the NVDs website, you might have seen that CVEs are often linked to weaknesses (CWEs).
We model this data in the output of cve2stix, e.g. for CVE-2024-38099, CWE-287 is referenced;
{
"type": "vulnerability",
"spec_version": "2.1",
"id": "vulnerability--86f9cc19-b695-5cc9-b8d8-f4de31d91591",
"created_by_ref": "identity--562918ee-d5da-5579-b6a1-fae50cc6bad3",
"created": "2024-07-09T17:15:46.517Z",
"modified": "2024-07-11T18:24:27.333Z",
"name": "CVE-2024-38099",
"description": "Windows Remote Desktop Licensing Service Denial of Service Vulnerability",
"external_references": [
{
"source_name": "cve",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2024-38099",
"external_id": "CVE-2024-38099"
},
{
"source_name": "cwe",
"url": "https://cwe.mitre.org/data/definitions/NVD-CWE-noinfo.html",
"external_id": "NVD-CWE-noinfo"
},
{
"source_name": "cwe",
"url": "https://cwe.mitre.org/data/definitions/CWE-287.html",
"external_id": "CWE-287"
},
{
"source_name": "[email protected]",
"description": "Patch,Vendor Advisory",
"url": "https://msrc.microsoft.com/update-guide/vulnerability/CVE-2024-38099"
}
],
"object_marking_refs": [
"marking-definition--94868c89-83c2-464b-929b-a1a8aa3c8487",
"marking-definition--562918ee-d5da-5579-b6a1-fae50cc6bad3"
],
"extensions": {
"extension-definition--2c5c13af-ee92-5246-9ba7-0b958f8cd34a": {
"extension_type": "toplevel-property-extension"
}
},
"x_epss": {
"date": "2024-08-30",
"percentile": "0.278130000",
"score": "0.000630000"
},
"x_cvss": {
"v3_1": {
"base_score": 5.9,
"base_severity": "MEDIUM",
"exploitability_score": 2.2,
"impact_score": 3.6,
"vector_string": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H"
}
}
}
Or CAPECs which often reference MITRE ATT&CK Techniques and CWE’s. Take CAPEC-11 which references CWE-430 and T1036.006;
{
"created": "2014-06-23T00:00:00.000Z",
"created_by_ref": "identity--e50ab59c-5c4f-4d40-bf6a-d58418d89bcd",
"description": "An attack of this type exploits a Web server's decision to take action based on filename or file extension. Because different file types are handled by different server processes, misclassification may force the Web server to take unexpected action, or expected actions in an unexpected sequence. This may cause the server to exhaust resources, supply debug or system data to the attacker, or bind an attacker to a remote process.",
"external_references": [
{
"external_id": "CAPEC-11",
"source_name": "capec",
"url": "https://capec.mitre.org/data/definitions/11.html"
},
{
"external_id": "CWE-430",
"source_name": "cwe",
"url": "http://cwe.mitre.org/data/definitions/430.html"
},
{
"description": "Masquerading: Space after Filename",
"external_id": "T1036.006",
"source_name": "ATTACK",
"url": "https://attack.mitre.org/wiki/Technique/T1036/006"
},
{
"description": "G. Hoglund, G. McGraw, Exploiting Software: How to Break Code, 2004--02, Addison-Wesley",
"external_id": "REF-1",
"source_name": "reference_from_CAPEC"
},
{
"description": "Orion Application Server JSP Source Disclosure Vulnerability (Bugtraq ID: 17204), SecurityFocus",
"external_id": "REF-6",
"source_name": "reference_from_CAPEC",
"url": "http://www.securityfocus.com/bid/17204/info"
}
],
"id": "attack-pattern--74a4fb36-83cb-4851-b09c-370f1a408523",
"modified": "2022-09-29T00:00:00.000Z",
"name": "Cause Web Server Misclassification",
"object_marking_refs": [
"marking-definition--17d82bb2-eeeb-4898-bda5-3ddbcd2b799d"
],
"spec_version": "2.1",
"type": "attack-pattern",
"x_capec_abstraction": "Detailed",
"x_capec_child_of_refs": [
"attack-pattern--95afb65f-ece7-4511-85a3-d7bfb9973022"
],
"x_capec_consequences": {
"Access_Control": [
"Gain Privileges"
],
"Authorization": [
"Gain Privileges"
],
"Confidentiality": [
"Read Data",
"Gain Privileges"
]
},
"x_capec_domains": [
"Software"
],
"x_capec_likelihood_of_attack": "Medium",
"x_capec_prerequisites": [
"Web server software must rely on file name or file extension for processing.",
"The attacker must be able to make HTTP requests to the web server."
],
"x_capec_resources_required": [
"None: No specialized resources are required to execute this type of attack."
],
"x_capec_skills_required": {
"Low": "To modify file name or file extension",
"Medium": "To use misclassification to force the Web server to disclose configuration information, source, or binary data"
},
"x_capec_status": "Draft",
"x_capec_typical_severity": "High",
"x_capec_version": "3.9"
}
If you didn’t know this already, it’s likely you’re now running through the network graph of objects in your mind, and how useful this graph could be.
For example, taking a CVE, finding the CWEs it is linked to, and then finding what MITRE ATT&CK Techniques are linked to that CWE. Or doing it the other way around, taking an ATT&CK ID and linking it to a CVE using the reverse path.
The problem; this data is very rarely linked together in a network graph like this.
Doing so provides additional pivot points during research.
Our team could not find any existing products that existed with such rich relationships between knowledge bases allowing us to explore these use-cases, so we set out to build it ourselves.
A bit of background to the data we use (and how to store it)
We set out with the following knowledge bases in STIX format;
- MITRE ATT&CK Enterprise
- MITRE ATT&CK ICS
- MITRE ATT&CK Mobile
- MITRE CAPEC
- MITRE CWE
- NVD CVE
- NVD CPE
If you’d like to follow along with the queries used in this post, you can use some utility scripts in stix2arango.
Once stix2arango is installed, run;
python3 utilities/arango_cti_processor/insert_archive_attack_enterprise.py \
--database blog_demo && \
python3 utilities/arango_cti_processor/insert_archive_attack_ics.py \
--database blog_demo && \
python3 utilities/arango_cti_processor/insert_archive_attack_mobile.py \
--database blog_demo && \
python3 utilities/arango_cti_processor/insert_archive_capec.py \
--database blog_demo && \
python3 utilities/arango_cti_processor/insert_archive_cwe.py \
--database blog_demo && \
python3 utilities/arango_cti_processor/insert_archive_cve.py \
--database blog_demo && \
python3 utilities/arango_cti_processor/insert_archive_cpe.py \
--database blog_demo && \
This will store all current and historic versions of the knowledgebases in an ArangoDB database called; blog_demo_database
, to the following Collections;
- MITRE ATT&CK Enterprise (
mitre_attack_enterprise_vertex_collection
/mitre_attack_enterprise_edge_collection
) - MITRE ATT&CK ICS (
mitre_attack_ics_vertex_collection
/mitre_attack_ics_edge_collection
) - MITRE ATT&CK Mobile (
mitre_attack_mobile_vertex_collection
/mitre_attack_mobile_edge_collection
) - MITRE CAPEC (
mitre_capec_vertex_collection
/mitre_capec_edge_collection
) - MITRE CWE (
mitre_cwe_vertex_collection
/mitre_cwe_edge_collection
) - NVD CVE (
nvd_cve_vertex_collection
/nvd_cve_edge_collection
) - NVD CPE (
nvd_cpe_vertex_collection
/nvd_cpe_edge_collection
)
Note, the *_edge
collections hold STIX Relationship objects from the knowledge-base bundles (in addition to the ones created by stix2arango, as described in this post), and the *_vertex
collections hold all the other STIX objects present in the bundles.
Examining the joins
stix2arango will import the data to ArangoDB, but each knowledge base is still unique. They are not joined together on the graph.
As shown earlier, we know the STIX objects contain references between the knowledge bases.
In summary, here is a graphical structure of what those references look like;
Here’s how these references can be uncovered and joined to the referenced object using ArangoDB searches on the imported data…
1. CAPEC -> ATT&CK
Firstly, lets look at all CAPEC objects in v3.9 (latest version at time of writing);
LET results = (
FOR doc IN mitre_capec_vertex_collection
FILTER doc._stix2arango_note == "v3.9"
AND doc.revoked != true
COLLECT type = doc.type WITH COUNT INTO typeCount
RETURN { type, typeCount }
)
LET totalSum = SUM(FOR result IN results RETURN result.typeCount)
RETURN APPEND(results, [{ type: "Total", typeCount: totalSum }])
[
[
{
"type": "attack-pattern",
"typeCount": 615
},
{
"type": "course-of-action",
"typeCount": 877
},
{
"type": "identity",
"typeCount": 1
},
{
"type": "marking-definition",
"typeCount": 1
},
{
"type": "Total",
"typeCount": 1494
}
]
]
Lets now filter the results to only Objects with ATTACK references;
RETURN (
FOR doc IN mitre_capec_vertex_collection
FILTER doc._stix2arango_note == "v3.9"
AND doc.revoked != true
LET capecId = (
FOR reference IN (IS_ARRAY(doc.external_references) ? doc.external_references : [])
FILTER reference.source_name == 'capec'
RETURN reference.external_id
)
LET attackIds = (
FOR reference IN (IS_ARRAY(doc.external_references) ? doc.external_references : [])
FILTER reference.source_name == 'ATTACK'
RETURN reference.external_id
)
FILTER LENGTH(attackIds) > 0 AND LENGTH(capecId) > 0
RETURN {
stixObjectId: doc.id,
capecId: capecId[0],
attackIds: CONCAT_SEPARATOR(",", attackIds)
}
)
[
[
{
"stixObjectId": "attack-pattern--92cdcd3d-d734-4442-afc3-4599f261498b",
"capecId": "CAPEC-1",
"attackIds": "T1574.010"
},
{
"stixObjectId": "attack-pattern--74a4fb36-83cb-4851-b09c-370f1a408523",
"capecId": "CAPEC-11",
"attackIds": "T1036.006"
},
{
"stixObjectId": "attack-pattern--7b423196-9de6-400f-91de-a1f26b3f19f1",
"capecId": "CAPEC-112",
"attackIds": "T1110"
},
This should return 177 results of CAPEC objects, some having multiple attackIds
referenced.
One thing I now know is the CAPEC objects only link to ATT&CK Techniques and Sub-Techniques.
This gives us a base search for the ATT&CK knowledge base as follows;
FOR doc IN UNION(
(FOR d IN mitre_attack_enterprise_vertex_collection RETURN d),
(FOR d IN mitre_attack_ics_vertex_collection RETURN d),
(FOR d IN mitre_attack_mobile_vertex_collection RETURN d)
)
FILTER doc._stix2arango_note == "v14.1"
AND doc.x_mitre_deprecated != true
AND doc.revoked != true
AND doc.type == "attack-pattern"
RETURN [doc]
Should return 820 STIX objects.
Now I can use the ATT&CK IDs in these objects, returned by the CAPEC search to find the STIX ID of the ATT&CK object and create the joins;
RETURN (
FOR doc IN mitre_capec_vertex_collection
FILTER doc._stix2arango_note == "v3.9"
AND doc.revoked != true
AND IS_ARRAY(doc.external_references)
LET capecId = FIRST(
FOR reference IN doc.external_references
FILTER reference.source_name == 'capec'
RETURN reference.external_id
)
LET attackIds = (
FOR reference IN doc.external_references
FILTER reference.source_name == 'ATTACK'
RETURN reference.external_id
)
FILTER LENGTH(attackIds) > 0 AND capecId != null
LET attackIdToDocIdMap = (
FOR attackId IN attackIds
LET attackDocs = (
FOR attackDoc IN UNION(
FOR d IN mitre_attack_enterprise_vertex_collection
FILTER d._stix2arango_note == "v14.1"
AND d.x_mitre_deprecated != true
AND d.revoked != true
AND d.type == "attack-pattern"
AND POSITION(d.external_references[*].external_id, attackId)
RETURN { id: d.id, collection: "mitre_attack_enterprise_vertex_collection" },
FOR d IN mitre_attack_ics_vertex_collection
FILTER d._stix2arango_note == "v14.1"
AND d.x_mitre_deprecated != true
AND d.revoked != true
AND d.type == "attack-pattern"
AND POSITION(d.external_references[*].external_id, attackId)
RETURN { id: d.id, collection: "mitre_attack_ics_vertex_collection" },
FOR d IN mitre_attack_mobile_vertex_collection
FILTER d._stix2arango_note == "v14.1"
AND d.x_mitre_deprecated != true
AND d.revoked != true
AND d.type == "attack-pattern"
AND POSITION(d.external_references[*].external_id, attackId)
RETURN { id: d.id, collection: "mitre_attack_mobile_vertex_collection" }
)
RETURN attackDoc
)
RETURN {
attackId: attackId,
attackDocs: attackDocs
}
)
RETURN {
stixObjectId: doc.id,
capecId: capecId,
attackIdToDocIdMap
}
)
[
[
{
"stixObjectId": "attack-pattern--92cdcd3d-d734-4442-afc3-4599f261498b",
"capecId": "CAPEC-1",
"attackIdToDocIdMap": [
{
"attackId": "T1574.010",
"attackDocs": [
{
"id": "attack-pattern--9e8b28c9-35fe-48ac-a14d-e6cc032dcbcd",
"collection": "mitre_attack_enterprise_vertex_collection"
}
]
}
]
},
{
"stixObjectId": "attack-pattern--74a4fb36-83cb-4851-b09c-370f1a408523",
"capecId": "CAPEC-11",
"attackIdToDocIdMap": [
{
"attackId": "T1036.006",
"attackDocs": [
{
"id": "attack-pattern--e51137a5-1cdc-499e-911a-abaedaa5ac86",
"collection": "mitre_attack_enterprise_vertex_collection"
}
]
}
]
},
{
"stixObjectId": "attack-pattern--7b423196-9de6-400f-91de-a1f26b3f19f1",
"capecId": "CAPEC-112",
"attackIdToDocIdMap": [
{
"attackId": "T1110",
"attackDocs": [
{
"id": "attack-pattern--a93494bb-4b80-4ea1-8695-3236a49916fd",
"collection": "mitre_attack_enterprise_vertex_collection"
}
]
}
]
},
{
"stixObjectId": "attack-pattern--2e2ed1f8-f736-4fc9-83bc-308595fc6e03",
"capecId": "CAPEC-114",
"attackIdToDocIdMap": [
{
"attackId": "T1548",
"attackDocs": [
{
"id": "attack-pattern--67720091-eee3-4d2d-ae16-8264567f6f5b",
"collection": "mitre_attack_enterprise_vertex_collection"
}
]
}
]
},
Above you can see CAPEC-1 (attack-pattern--92cdcd3d-d734-4442-afc3-4599f261498b
) is linked to T1574.010 (attack-pattern--9e8b28c9-35fe-48ac-a14d-e6cc032dcbcd
) in the Enterprise collection.
A summary of the relationships created;
LET capecDocs = (
FOR doc IN mitre_capec_vertex_collection
FILTER doc._stix2arango_note == "v3.9"
AND doc.revoked != true
AND IS_ARRAY(doc.external_references)
LET attackIds = (
FOR reference IN doc.external_references
FILTER reference.source_name == 'ATTACK'
RETURN reference.external_id
)
FILTER LENGTH(attackIds) > 0
RETURN attackIds
)
LET attackIdCountInEnterprise = LENGTH(
FOR attackId IN FLATTEN(capecDocs)
FOR d IN mitre_attack_enterprise_vertex_collection
FILTER d._stix2arango_note == "v14.1"
AND d.x_mitre_deprecated != true
AND d.revoked != true
AND d.type == "attack-pattern"
AND POSITION(d.external_references[*].external_id, attackId)
RETURN 1
)
LET attackIdCountInICS = LENGTH(
FOR attackId IN FLATTEN(capecDocs)
FOR d IN mitre_attack_ics_vertex_collection
FILTER d._stix2arango_note == "v14.1"
AND d.x_mitre_deprecated != true
AND d.revoked != true
AND d.type == "attack-pattern"
AND POSITION(d.external_references[*].external_id, attackId)
RETURN 1
)
LET attackIdCountInMobile = LENGTH(
FOR attackId IN FLATTEN(capecDocs)
FOR d IN mitre_attack_mobile_vertex_collection
FILTER d._stix2arango_note == "v14.1"
AND d.x_mitre_deprecated != true
AND d.revoked != true
AND d.type == "attack-pattern"
AND POSITION(d.external_references[*].external_id, attackId)
RETURN 1
)
RETURN {
"mitre_attack_enterprise_vertex_collection": attackIdCountInEnterprise,
"mitre_attack_ics_vertex_collection": attackIdCountInICS,
"mitre_attack_mobile_vertex_collection": attackIdCountInMobile
}
[
{
"mitre_attack_enterprise_vertex_collection": 271,
"mitre_attack_ics_vertex_collection": 0,
"mitre_attack_mobile_vertex_collection": 1
}
]
In summary, 272 joins will be made between CAPEC objects and MITRE ATT&CK object.
If you’re wondering about the 1 CAPEC that links to the Mobile ATT&CK matrix, here it is;
{
"stixObjectId": "attack-pattern--140142cc-28cb-4506-bce6-b44128b7b9a7",
"capecId": "CAPEC-648",
"attackIdToDocIdMap": [
{
"attackId": "T1113",
"attackDocs": [
{
"id": "attack-pattern--0259baeb-9f63-4c69-bf10-eb038c390688",
"collection": "mitre_attack_enterprise_vertex_collection"
}
]
},
{
"attackId": "T1513",
"attackDocs": [
{
"id": "attack-pattern--73c26732-6422-4081-8b63-6d0ae93d449e",
"collection": "mitre_attack_mobile_vertex_collection"
}
]
}
]
},
2. CAPEC -> CWE
OK, now you know the logic to create these types of joins, I can jump straight into the final searches.
For CAPEC to CWEs;
RETURN (
FOR doc IN mitre_capec_vertex_collection
FILTER doc._stix2arango_note == "v3.9"
AND IS_ARRAY(doc.external_references)
LET capecId = FIRST(
FOR reference IN doc.external_references
FILTER reference.source_name == 'capec'
RETURN reference.external_id
)
LET cweIds = (
FOR reference IN doc.external_references
FILTER reference.source_name == 'cwe'
RETURN reference.external_id
)
FILTER LENGTH(cweIds) > 0 AND capecId != null
LET cweIdToDocIdMap = (
FOR cweId IN cweIds
LET cweDocs = (
FOR cweDoc IN mitre_cwe_vertex_collection
FILTER cweDoc._stix2arango_note == "v4.14"
AND POSITION(cweDoc.external_references[*].external_id, cweId)
RETURN { id: cweDoc.id, collection: "mitre_cwe_vertex_collection" }
)
RETURN {
cweId: cweId,
cweDocs: cweDocs
}
)
RETURN {
stixObjectId: doc.id,
capecId: capecId,
cweIdToDocIdMap
}
)
[
[
{
"stixObjectId": "attack-pattern--92cdcd3d-d734-4442-afc3-4599f261498b",
"capecId": "CAPEC-1",
"cweIdToDocIdMap": [
{
"cweId": "CWE-276",
"cweDocs": [
{
"id": "weakness--bfa2f40d-b5f0-505e-9ac5-92adfe0b6bd8",
"collection": "mitre_cwe_vertex_collection"
}
]
},
{
"cweId": "CWE-285",
"cweDocs": [
{
"id": "weakness--ff910cf7-7172-51b4-9948-874740d20ea0",
"collection": "mitre_cwe_vertex_collection"
}
]
},
{
"cweId": "CWE-434",
"cweDocs": [
{
"id": "weakness--4898a006-e26e-582f-a3fe-fd921b8c4fc5",
"collection": "mitre_cwe_vertex_collection"
}
]
},
{
"cweId": "CWE-693",
"cweDocs": [
{
"id": "weakness--414d8009-5140-58ad-97f6-a575c1bb84d1",
"collection": "mitre_cwe_vertex_collection"
}
]
},
{
"cweId": "CWE-732",
"cweDocs": [
{
"id": "weakness--6d8788cb-39fa-5219-8e45-b1aa3eb91083",
"collection": "mitre_cwe_vertex_collection"
}
]
},
{
"cweId": "CWE-1191",
"cweDocs": [
{
"id": "weakness--ce0c11b1-d560-5b9b-be5b-e372bf53bf0e",
"collection": "mitre_cwe_vertex_collection"
}
]
},
{
"cweId": "CWE-1193",
"cweDocs": [
{
"id": "weakness--66b6bbd6-4c6f-561d-ba62-3b083a4154aa",
"collection": "mitre_cwe_vertex_collection"
}
]
},
{
"cweId": "CWE-1220",
"cweDocs": [
{
"id": "weakness--c64c9776-e449-5b79-bc68-ee1bb120452e",
"collection": "mitre_cwe_vertex_collection"
}
]
},
{
"cweId": "CWE-1297",
"cweDocs": [
{
"id": "weakness--b0e4fec3-d07d-5c19-bf36-3c0c4393e241",
"collection": "mitre_cwe_vertex_collection"
}
]
},
{
"cweId": "CWE-1311",
"cweDocs": [
{
"id": "weakness--4ab9926e-306b-5e13-b6ae-c823b97f1608",
"collection": "mitre_cwe_vertex_collection"
}
]
},
{
"cweId": "CWE-1314",
"cweDocs": [
{
"id": "weakness--b4f6d188-3eeb-59cd-addc-0983b2f39c71",
"collection": "mitre_cwe_vertex_collection"
}
]
},
{
"cweId": "CWE-1315",
"cweDocs": [
{
"id": "weakness--a4d26132-f22e-5a6c-a023-a8ad49a442e1",
"collection": "mitre_cwe_vertex_collection"
}
]
},
{
"cweId": "CWE-1318",
"cweDocs": [
{
"id": "weakness--1d2542ed-b3cb-53c1-978f-8467ec99bb42",
"collection": "mitre_cwe_vertex_collection"
}
]
},
{
"cweId": "CWE-1320",
"cweDocs": [
{
"id": "weakness--8e461d75-a066-5915-aa43-92eac5d38736",
"collection": "mitre_cwe_vertex_collection"
}
]
},
{
"cweId": "CWE-1321",
"cweDocs": [
{
"id": "weakness--2dfc4cda-189f-51e3-a942-0647acd058bb",
"collection": "mitre_cwe_vertex_collection"
}
]
},
{
"cweId": "CWE-1327",
"cweDocs": [
{
"id": "weakness--f167a7af-9907-5610-862d-b4e2819ad32f",
"collection": "mitre_cwe_vertex_collection"
}
]
}
]
},
{
"stixObjectId": "attack-pattern--4a29d66d-8617-4382-b456-578ecdb1609e",
"capecId": "CAPEC-10",
"cweIdToDocIdMap": [
{
"cweId": "CWE-120",
"cweDocs": [
{
"id": "weakness--7d83b5bf-4791-5ddf-9cfc-b90977b45bc2",
"collection": "mitre_cwe_vertex_collection"
}
]
},
In total 1214 relationships are identified.
3. CWE -> CAPEC
For CWEs to CAPECs;
RETURN (
FOR doc IN mitre_cwe_vertex_collection
FILTER doc._stix2arango_note == "v4.14"
AND IS_ARRAY(doc.external_references)
LET cweId = FIRST(
FOR reference IN doc.external_references
FILTER reference.source_name == 'cwe'
RETURN reference.external_id
)
LET capecIds = (
FOR reference IN doc.external_references
FILTER reference.source_name == 'capec'
RETURN reference.external_id
)
FILTER LENGTH(capecIds) > 0 AND cweId != null
LET capecIdToDocIdMap = (
FOR capecId IN capecIds
LET capecDocs = (
FOR capecDoc IN mitre_capec_vertex_collection
FILTER capecDoc._stix2arango_note == "v3.9"
AND POSITION(capecDoc.external_references[*].external_id, capecId)
RETURN { id: capecDoc.id, collection: "mitre_capec_vertex_collection" }
)
RETURN {
capecId: capecId,
capecDocs: capecDocs
}
)
RETURN {
stixObjectId: doc.id,
cweId: cweId,
capecIdToDocIdMap
}
)
[
[
{
"stixObjectId": "weakness--94110a45-2221-5fb5-aa09-322b8dfc4b6a",
"cweId": "CWE-1007",
"capecIdToDocIdMap": [
{
"capecId": "CAPEC-632",
"capecDocs": [
{
"id": "attack-pattern--c4e18b3f-0445-49e8-9bf1-d47a23082501",
"collection": "mitre_capec_vertex_collection"
}
]
}
]
},
{
"stixObjectId": "weakness--bdb3f8a8-96eb-5572-a201-84451e4d2324",
"cweId": "CWE-1021",
"capecIdToDocIdMap": [
{
"capecId": "CAPEC-103",
"capecDocs": [
{
"id": "attack-pattern--ec41b2b3-a3b6-4af0-be65-69e82907dfef",
"collection": "mitre_capec_vertex_collection"
}
]
},
{
"capecId": "CAPEC-181",
"capecDocs": [
{
"id": "attack-pattern--1ff813eb-5def-43a0-a4b2-ea00aede114a",
"collection": "mitre_capec_vertex_collection"
}
]
},
{
"capecId": "CAPEC-222",
"capecDocs": [
{
"id": "attack-pattern--b9593e93-5589-4ae9-b0e7-09fa5c3136e5",
"collection": "mitre_capec_vertex_collection"
}
]
},
{
"capecId": "CAPEC-504",
"capecDocs": [
{
"id": "attack-pattern--1995c522-a25d-46e4-b024-65172771a692",
"collection": "mitre_capec_vertex_collection"
}
]
},
{
"capecId": "CAPEC-506",
"capecDocs": [
{
"id": "attack-pattern--79309efd-dd13-41d2-81c6-ec382bced2b4",
"collection": "mitre_capec_vertex_collection"
}
]
},
In total 1212 relationships are identified.
4. CVE -> CWE
For CVEs to CWEs;
RETURN (
FOR cveDoc IN nvd_cve_vertex_collection
FILTER cveDoc.type == "vulnerability"
AND cveDoc.modified >= "2024-01-01T00:00:00.000Z"
AND cveDoc.modified <= "2024-03-31T23:59:59.999Z"
LET cweIds = (
FOR reference IN cveDoc.external_references
FILTER reference.source_name == 'cwe'
RETURN reference.external_id
)
LET cweIdToDocIdMap = (
FOR cweId IN cweIds
LET cweDocs = (
FOR cweDoc IN mitre_cwe_vertex_collection
FILTER cweDoc._stix2arango_note == "v4.14" // Replace with the correct version if necessary
AND cweId IN cweDoc.external_references[* FILTER CURRENT.source_name == 'cwe'].external_id
RETURN { id: cweDoc.id, collection: "mitre_cwe_vertex_collection" }
)
RETURN {
cweId: cweId,
cweDocs: cweDocs
}
)
RETURN {
stixObjectId: cveDoc.id,
cveName: cveDoc.name,
cweIdToDocIdMap: cweIdToDocIdMap
}
)
Note, this search limits results to Q1 2024.
[
[
{
"stixObjectId": "vulnerability--7209b015-da9e-5e53-a229-09697e7771aa",
"cveName": "CVE-2023-20181",
"cweIdToDocIdMap": [
{
"cweId": "CWE-79",
"cweDocs": [
{
"id": "weakness--8b8749fa-25a0-526c-b819-63425b843e45",
"collection": "mitre_cwe_vertex_collection"
}
]
},
{
"cweId": "CWE-80",
"cweDocs": [
{
"id": "weakness--5bc313f4-7bca-5676-a905-1a219150ffed",
"collection": "mitre_cwe_vertex_collection"
}
]
}
]
},
{
"stixObjectId": "vulnerability--46090dd5-ae49-5c31-ba3d-4642ad61adef",
"cveName": "CVE-2023-30774",
"cweIdToDocIdMap": [
{
"cweId": "CWE-787",
"cweDocs": [
{
"id": "weakness--5d0a9fae-053c-5312-a13f-64c6d6fa763d",
"collection": "mitre_cwe_vertex_collection"
}
]
},
{
"cweId": "CWE-119",
"cweDocs": [
{
"id": "weakness--327274c3-4c72-5eb1-a34c-52f8d88867d3",
"collection": "mitre_cwe_vertex_collection"
}
]
}
]
},
{
"stixObjectId": "vulnerability--d7b3fbf5-7a0c-5f53-a0db-5202cb1080e8",
"cveName": "CVE-2024-22027",
"cweIdToDocIdMap": [
{
"cweId": "CWE-20",
"cweDocs": [
{
"id": "weakness--dff2e3ee-6d33-5bb7-bbb0-37b5697a6c2f",
"collection": "mitre_cwe_vertex_collection"
}
]
}
]
},
5. CVE -> CPE
CVE to CPE relationships are slightly different. cve2stix creates Indicator STIX objects to represent the software impacted by a reported CVE like so;
{
"type": "indicator",
"spec_version": "2.1",
"id": "indicator--b6b29369-8e19-526c-95de-6b444d84d9b7",
"created_by_ref": "identity--562918ee-d5da-5579-b6a1-fae50cc6bad3",
"created": "2024-01-22T20:15:47.267Z",
"modified": "2024-03-07T17:15:11.373Z",
"name": "CVE-2023-47747",
"description": "IBM DB2 for Linux, UNIX and Windows (includes Db2 Connect Server) 10.1, 10.5, and 11.1 could allow an authenticated user with CONNECT privileges to cause a denial of service using a specially crafted query. IBM X-Force ID: 272646.",
"indicator_types": [
"compromised"
],
"pattern": "([software:cpe='cpe:2.3:a:ibm:db2:*:*:*:*:*:*:*:*' OR software:cpe='cpe:2.3:a:ibm:db2:*:*:*:*:*:*:*:*' OR software:cpe='cpe:2.3:a:ibm:db2:*:*:*:*:*:*:*:*'] AND [software:cpe='cpe:2.3:o:hp:hp-ux:-:*:*:*:*:*:*:*' OR software:cpe='cpe:2.3:o:ibm:aix:-:*:*:*:*:*:*:*' OR software:cpe='cpe:2.3:o:ibm:linux_on_ibm_z:-:*:*:*:*:*:*:*' OR software:cpe='cpe:2.3:o:linux:linux_kernel:-:*:*:*:*:*:*:*' OR software:cpe='cpe:2.3:o:microsoft:windows:-:*:*:*:*:*:*:*' OR software:cpe='cpe:2.3:o:oracle:solaris:-:*:*:*:*:*:*:*'])",
"pattern_type": "stix",
"pattern_version": "2.1",
"valid_from": "2024-01-22T20:15:47.267Z",
"external_references": [
{
"source_name": "cve",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2023-47747",
"external_id": "CVE-2023-47747"
}
],
"object_marking_refs": [
"marking-definition--94868c89-83c2-464b-929b-a1a8aa3c8487",
"marking-definition--562918ee-d5da-5579-b6a1-fae50cc6bad3"
],
"extensions": {
"extension-definition--ad995824-2901-5f6e-890b-561130a239d4": {
"extension_type": "toplevel-property-extension"
}
},
"x_cpes": {
"not_vulnerable": [
{
"criteria": "cpe:2.3:o:hp:hp-ux:-:*:*:*:*:*:*:*",
"matchCriteriaId": "F480AA32-841A-4E68-9343-B2E7548B0A0C"
},
{
"criteria": "cpe:2.3:o:ibm:aix:-:*:*:*:*:*:*:*",
"matchCriteriaId": "E492C463-D76E-49B7-A4D4-3B499E422D89"
},
{
"criteria": "cpe:2.3:o:ibm:linux_on_ibm_z:-:*:*:*:*:*:*:*",
"matchCriteriaId": "B955E472-47E3-4C32-847B-F6BB05594BA3"
},
{
"criteria": "cpe:2.3:o:linux:linux_kernel:-:*:*:*:*:*:*:*",
"matchCriteriaId": "703AF700-7A70-47E2-BC3A-7FD03B3CA9C1"
},
{
"criteria": "cpe:2.3:o:microsoft:windows:-:*:*:*:*:*:*:*",
"matchCriteriaId": "A2572D17-1DE6-457B-99CC-64AFD54487EA"
},
{
"criteria": "cpe:2.3:o:oracle:solaris:-:*:*:*:*:*:*:*",
"matchCriteriaId": "91F372EA-3A78-4703-A457-751B2C98D796"
}
],
"vulnerable": [
{
"criteria": "cpe:2.3:a:ibm:db2:*:*:*:*:*:*:*:*",
"matchCriteriaId": "C23E4D44-3305-407B-92C5-8190434A59DC"
},
{
"criteria": "cpe:2.3:a:ibm:db2:*:*:*:*:*:*:*:*",
"matchCriteriaId": "FE8F88DC-637C-4F04-AE84-1BD0343FD8F4"
},
{
"criteria": "cpe:2.3:a:ibm:db2:*:*:*:*:*:*:*:*",
"matchCriteriaId": "760B31B3-509C-49E4-BB2C-B48E33782141"
}
]
}
},
The x_cpes
reports the not_vulnerable
and vulnerable
CPEs found in the pattern.
For each CPE a matchCriteriaId
is also shown.
Using the NVD CPE Match Criteria API allows you to see all CPEs that resolve to the matchCriteriaId
.
e.g.
GET https://services.nvd.nist.gov/rest/json/cpematch/2.0?matchCriteriaId=F480AA32-841A-4E68-9343-B2E7548B0A0C
{
"resultsPerPage": 1,
"startIndex": 0,
"totalResults": 1,
"format": "NVD_CPEMatchString",
"version": "2.0",
"timestamp": "2024-09-09T09:32:01.393",
"matchStrings": [
{
"matchString": {
"matchCriteriaId": "F480AA32-841A-4E68-9343-B2E7548B0A0C",
"criteria": "cpe:2.3:o:hp:hp-ux:-:*:*:*:*:*:*:*",
"lastModified": "2022-09-15T13:24:58.473",
"cpeLastModified": "2019-07-22T16:37:38.133",
"created": "2019-06-17T09:16:33.960",
"status": "Active",
"matches": [
{
"cpeName": "cpe:2.3:o:hp:hp-ux:-:*:*:*:*:*:*:*",
"cpeNameId": "35E65921-949D-4684-B006-72395C0BA5DF"
}
]
}
}
]
}
Returns one CPE. It is possible that one or more results are returned for a matchCriteriaId
(sometimes hundreds).
Using the cpeName
, you can then lookup the value in the CPE ArangoDB collection.
e.g.
FOR doc IN nvd_cpe_vertex_collection
FILTER doc.type == "software"
AND doc.cpe == "cpe:2.3:o:hp:hp-ux:-:*:*:*:*:*:*:*"
RETURN doc.id
[
"software--8acbbd02-328a-51b0-995e-05edd5ca88a2"
]
This search for each CPE match allows you to create relationships from the Indicator to vulnerable and not vulnerable CPEs.
A note on versioning of objects
Most knowledge-bases are versioned.
In this post you’ll see I reference specific versions in the queries, e.g.
FILTER doc._stix2arango_note == "v4.14"
Take ATT&CK as an example, you can see in the ATT&CK repository the various versions of the Enterprise Matrix.
The only exceptions to this is for the NVD CVE and CPE data, whereby the STIX Bundles are grouped (by cve2stix and cpe2stix) by the time of the last update for the CVE or CPE respectively. The reason for this is simple, the CVE and CPE dataset is HUGE. A single bundle of all CVE STIX objects would easily exceed 2GB.
To always get the latest version of MITRE ATT&CK Enterprise you can use the query:
FOR doc IN mitre_attack_enterprise_vertex_collection
FILTER _is_latest == true
RETURN [doc]
Whereas, here is how I would request a specific ATT&CK version (here 14.0);
FOR doc IN mitre_attack_enterprise_vertex_collection
FILTER doc._stix2arango_note == "v14.0"
RETURN [doc]
This logic also applies to CVEs and CPEs, where objects are versioned when updates happen.
In short, you probably always want to use the filter _is_latest == true
, unless you have a specific use-case.
Introducing Arango CTI Processor
Arango CTI Processor uses the logic described in this post to create new STIX relationship objects to represent these joins.
By linking the data in this way allows for the traversal of the knowledge graph using simpler queries than those in this post. Give it a try.
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.