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
Despite countless frameworks, best practices, blog posts… so many developers still hardcode credentials into their code.
Key Findings
- 37,439 CVEs were published between October 2023 through September 2024
- 35,346 CWEs were assigned to those CVEs (520 unique CWEs in total)
- CWE-79 Improper Neutralization of Input During Web Page Generation (‘Cross-site Scripting’) was the most reported weakness (in 6,006 of the CVEs, 17% of all CWEs)
- Basic weaknesses like, CWE-532: Insertion of Sensitive Information into Log File (247 CVEs, 0.7%), CWE-798: Use of Hard-coded Credentials (213 CVEs, 0.6%), and CWE-306: Missing Authentication for Critical Function (208 CVEs, 0.6%) were also high up the list.
Overview
Many of those on the vendor side of cyber-security will often joke that insecure software keeps the majority of the industry in business.
There is some truth in that statement. We couldn’t expect perfect software and there needs to be checks in place by the industry (including responsible disclosure).
In a previous post I looked at some interesting data points about CVEs over the course of the last 25 years. This time around I wanted to take a look at some of the common weakness categories for published vulnerabilities over the last year (October 2023 through September 2024).
Follow along
If you’d like to follow along with the searches used in this post, follow the instructions described in that previous post to import the data.
Once you’ve done that, there’s one final stix2arango command you need to run;
python3 utilities/arango_cti_processor/insert_archive_cwe.py \
--versions 4_15 \
--database blog_demo
Analysis
An overview of the data
RETURN LENGTH(
FOR doc IN nvd_cve_vertex_collection
FILTER doc.type == "vulnerability"
FILTER DATE_TIMESTAMP(doc.created) >= DATE_TIMESTAMP("2023-10-01T00:00:00Z")
FILTER DATE_TIMESTAMP(doc.created) <= DATE_TIMESTAMP("2024-09-30T00:00:00Z")
RETURN doc
)
[
37439
]
In total, 37,439 CVEs were published over this period.
RETURN (
FOR doc IN nvd_cve_vertex_collection
FILTER doc.type == "vulnerability"
FILTER DATE_TIMESTAMP(doc.created) >= DATE_TIMESTAMP("2023-10-01T00:00:00Z")
FILTER DATE_TIMESTAMP(doc.created) <= DATE_TIMESTAMP("2024-09-30T00:00:00Z")
COLLECT monthYear = CONCAT(DATE_YEAR(doc.created), "-",
(DATE_MONTH(doc.created) < 10 ? "0" : ""),
DATE_MONTH(doc.created)) WITH COUNT INTO count
SORT monthYear
RETURN {
monthYear: monthYear,
count: count
}
)
Most common weaknesses
When considering the following numbers keep in mind that not all CVEs have CWEs assigned. Sometimes it is because NVD are yet to analyse the CVE (and that’s a common problem given the NVDs backlog). Also some CVEs are assigned NVD-CWE-noinfo
which means the NVD had insufficient information when analysing the CVE to assign a CWE.
For those that do have CWEs assigned;
// Step 1: Build a lookup table for CWE IDs and names from `mitre_cwe_vertex_collection`
LET cwe_lookup = (
FOR cwe_doc IN mitre_cwe_vertex_collection
FILTER TO_BOOL(cwe_doc.external_references)
FOR cwe_ref IN cwe_doc.external_references
FILTER cwe_ref.source_name == "cwe"
RETURN { cwe_id: cwe_ref.external_id, name: cwe_doc.name }
)
// Step 2: Use the lookup table to map CWE names to IDs in `nvd_cve_vertex_collection`
FOR doc IN nvd_cve_vertex_collection
FILTER doc.type == "vulnerability"
FILTER DATE_TIMESTAMP(doc.created) >= DATE_TIMESTAMP("2023-10-01T00:00:00Z")
FILTER DATE_TIMESTAMP(doc.created) <= DATE_TIMESTAMP("2024-09-30T00:00:00Z")
FILTER TO_BOOL(doc.external_references)
// Extract and match CWE IDs using the lookup table
FOR ref IN doc.external_references
FILTER ref.source_name == "cwe"
LET current_cwe_id = ref.external_id
// Get the CWE name from the lookup table
LET cwe_name = FIRST(FOR cwe IN cwe_lookup FILTER cwe.cwe_id == current_cwe_id RETURN cwe.name)
COLLECT cwe_id = current_cwe_id, name = cwe_name WITH COUNT INTO count
FILTER cwe_id != "NVD-CWE-noinfo" // Exclude "NVD-CWE-noinfo"
SORT count DESC
RETURN {
cwe_id: cwe_id,
name: name,
count: count
}
A total of 35,346 CWEs were assigned to those CVEs.
Here are the top 40;
cwe_id | name | count |
---|---|---|
CWE-79 | Improper Neutralization of Input During Web Page Generation (‘Cross-site Scripting’) | 6006 |
CWE-89 | Improper Neutralization of Special Elements used in an SQL Command (‘SQL Injection’) | 2644 |
CWE-352 | Cross-Site Request Forgery (CSRF) | 1615 |
CWE-787 | Out-of-bounds Write | 1491 |
CWE-862 | Missing Authorization | 1091 |
CWE-22 | Improper Limitation of a Pathname to a Restricted Directory (‘Path Traversal’) | 1028 |
CWE-416 | Use After Free | 1013 |
CWE-125 | Out-of-bounds Read | 902 |
CWE-121 | Stack-based Buffer Overflow | 857 |
CWE-78 | Improper Neutralization of Special Elements used in an OS Command (‘OS Command Injection’) | 845 |
CWE-200 | Exposure of Sensitive Information to an Unauthorized Actor | 775 |
CWE-20 | Improper Input Validation | 768 |
CWE-434 | Unrestricted Upload of File with Dangerous Type | 719 |
CWE-284 | Improper Access Control | 660 |
CWE-120 | Buffer Copy without Checking Size of Input (‘Classic Buffer Overflow’) | 615 |
CWE-476 | NULL Pointer Dereference | 584 |
CWE-94 | Improper Control of Generation of Code (‘Code Injection’) | 569 |
CWE-269 | Improper Privilege Management | 499 |
CWE-77 | Improper Neutralization of Special Elements used in a Command (‘Command Injection’) | 494 |
CWE-400 | Uncontrolled Resource Consumption | 441 |
CWE-122 | Heap-based Buffer Overflow | 426 |
CWE-918 | Server-Side Request Forgery (SSRF) | 408 |
CWE-287 | Improper Authentication | 405 |
CWE-502 | Deserialization of Untrusted Data | 384 |
CWE-190 | Integer Overflow or Wraparound | 312 |
CWE-863 | Incorrect Authorization | 297 |
CWE-119 | Improper Restriction of Operations within the Bounds of a Memory Buffer | 283 |
CWE-639 | Authorization Bypass Through User-Controlled Key | 250 |
CWE-532 | Insertion of Sensitive Information into Log File | 247 |
CWE-798 | Use of Hard-coded Credentials | 213 |
CWE-306 | Missing Authentication for Critical Function | 208 |
CWE-601 | URL Redirection to Untrusted Site (‘Open Redirect’) | 205 |
CWE-427 | Uncontrolled Search Path Element | 198 |
CWE-770 | Allocation of Resources Without Limits or Throttling | 184 |
CWE-276 | Incorrect Default Permissions | 174 |
CWE-401 | Missing Release of Memory after Effective Lifetime | 165 |
CWE-74 | Improper Neutralization of Special Elements in Output Used by a Downstream Component (‘Injection’) | 153 |
CWE-362 | Concurrent Execution using Shared Resource with Improper Synchronization (‘Race Condition’) | 148 |
CWE-732 | Incorrect Permission Assignment for Critical Resource | 135 |
CWE-59 | Improper Link Resolution Before File Access (‘Link Following’) | 133 |
There are some basic software development errors listed here.
The top two entries, XSS (Cross-Site Scripting) (CWE-79) and SQL injection (CWE-89), are fundamental to web application security and are always covered as part of basic development best practices. Both are common attack vectors and are often included in secure development guidelines like OWASP’s top security risks.
Outside of the top 20 more basic software development exist too;
- CWE-532: Insertion of Sensitive Information into Log File (247 CVEs)
- CWE-798: Use of Hard-coded Credentials (213 CVEs)
- CWE-306: Missing Authentication for Critical Function (208 CVEs)
I can use a CWE ID to retreive the products that have shipped with these weaknesses. Here I use CWE-798
(Use of Hard-coded Credentials).
// Step 1: Collect all vulnerability IDs with CWE-798 within the specified date range
LET vulnerability_ids_with_cwe_798 = (
FOR vuln_doc IN nvd_cve_vertex_collection
FILTER vuln_doc.type == "vulnerability"
FILTER TO_BOOL(vuln_doc.external_references)
FILTER DATE_TIMESTAMP(vuln_doc.created) >= DATE_TIMESTAMP("2023-10-01T00:00:00Z")
FILTER DATE_TIMESTAMP(vuln_doc.created) <= DATE_TIMESTAMP("2024-09-30T00:00:00Z")
// Check for vulnerabilities with CWE-798
FOR ref IN vuln_doc.external_references
FILTER ref.source_name == "cwe"
FILTER ref.external_id == "CWE-798"
RETURN vuln_doc.id // Collect vulnerability ID directly
)
// Step 2: Collect unique vendor/product pairs from each indicator
LET all_unique_vulnerable_criteria = (
FOR vuln_id IN vulnerability_ids_with_cwe_798
// Replace "vulnerability--" with "indicator--" to get the corresponding indicator ID
LET indicator_id = CONCAT("indicator--", SPLIT(vuln_id, "--")[1])
// Retrieve the indicator document
FOR indicator_doc IN nvd_cve_vertex_collection
FILTER indicator_doc.id == indicator_id
// Deduplicate vendor/product pairs within each indicator
LET unique_criteria = UNIQUE(
FOR vuln IN indicator_doc.x_cpes.vulnerable
LET parts = SPLIT(vuln.criteria, ":")
RETURN {
vendor: parts[3],
product: parts[4]
}
)
// Return deduplicated vendor/product pairs for this indicator
FOR criteria IN unique_criteria
RETURN criteria
)
// Step 3: Count occurrences of each unique vendor/product pair across all indicators
FOR criteria IN all_unique_vulnerable_criteria
COLLECT vendor = criteria.vendor, product = criteria.product WITH COUNT INTO count
SORT count DESC
RETURN {
vendor: vendor,
product: product,
count: count
}
vendor | product | count of CVEs with CWE-798 |
---|---|---|
hitron_systems | dvr_hvr-4781_firmware | 6 |
boschrexroth | ctrlx_hmi_web_panel_wr2115_firmware | 4 |
ibm | security_verify_governance | 4 |
boschrexroth | ctrlx_hmi_web_panel_wr2110_firmware | 4 |
bosch | nexo-os | 4 |
boschrexroth | ctrlx_hmi_web_panel_wr2107_firmware | 4 |
hongdian | h8951-4g-esp_firmware | 3 |
sierrawireless | aleos | 3 |
autel | maxicharger_ac_elite_business_c50_firmware | 2 |
fedirtsapana | simple_http_server_plus | 2 |
enbw | senec_storage_box_firmware | 2 |
zohocorp | manageengine_ddi_central | 2 |
dell | e-lab_navigator | 2 |
skoda-auto | superb_3_firmware | 2 |
kiloview | p1_firmware | 2 |
cisco | emergency_responder | 2 |
machinesense | feverwarn_firmware | 2 |
estomed | simple_care | 2 |
ibm | merge_efilm_workstation | 2 |
csharp | cws_collaborative_development_platform | 2 |
The count shows distinct CVEs that reference CWE-798 and have the product shown as vulnerable.
The main takeaway from the above table is that this happens to big and small vendors alike (see CISCO and IBM), and also more-often in firmware (which is often harder to mitigate the issue of leaked credentials in).
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.