CVE-2023-28465 - Exploiting Directory Traversal in HL7 FHIR Core Libraries’ Package-Decompression Feature

In the world of healthcare IT, software like HL7 FHIR Core Libraries are essential for handling medical data in a secure and standardized way. Unfortunately, just like any other software, vulnerabilities can creep in. A recent example is CVE-2023-28465, which targets the package-decompression feature of HL7 FHIR Core Libraries (before version 5.6.106). In this detailed post, we break down what this vulnerability is, how it can be exploited, provide code examples, and link you to the most important original resources.

What is HL7 FHIR Core Libraries?

The Health Level 7 (HL7) Fast Healthcare Interoperability Resources (FHIR) standards are the backbone of many modern healthcare systems worldwide. The FHIR Core Libraries help developers manage and parse FHIR data in their apps.

Affected Versions: HL7 FHIR Core Libraries before version 5.6.106.

- Danger: Attackers can copy arbitrary files to directories they shouldn’t, leading to potential code execution, data loss, or further compromise.
- Root Cause: The patch for an earlier vulnerability (CVE-2023-24057) was incomplete, which left this new hole open.

Technical Details: How the Exploit Works

The main issue is with how the library handles allowed directory names while decompressing package files. If a directory path controlled by an attacker *contains* an allowed directory name (even as a substring), the checks can be bypassed, allowing directory traversal.

Example

- Allowed directories: allowed/path
- Malicious directory: allowed/path_malicious/../../../../etc/

Because allowed/path is a substring of allowed/path_malicious, the code sees it as permitted, but the attacker can climb (../) outside the permitted folder and write files anywhere.

Here's a simplified version of how the affected code might look, with comments for clarity

// Incorrect Path Validation in Older HL7 FHIR Code

String targetFolder = "allowed/path";
String destination = userSuppliedPath; // e.g., "allowed/path_malicious/../../../../etc/passwd"

// BAD: Just checking if allowed directory is a substring
if (destination.startsWith(targetFolder)) {
    // Proceed to write file, assuming it's safe
    FileOutputStream out = new FileOutputStream(destination);
    // ... write contents ...
}

What’s Wrong?

- This check passes if destination starts with allowed/path, *even if* what comes next actually breaks free from the intended directory due to traversal (../../).

Here’s a minimal Python example to simulate the problem (NOTE: Do not use maliciously)

import os

def vulnerable_extract(file_path, allowed_dir):
    # Simulate extracting a file from an archive
    if file_path.startswith(allowed_dir):
        with open(file_path, 'w') as f:
            f.write("This could overwrite system files!")
        print("Extracted:", file_path)
    else:
        print("Skipped:", file_path)

# Try to extract a file with directory traversal
vulnerable_extract('allowed/path_malicious/../../../../tmp/evil.txt', 'allowed/path')

Output

Extracted: allowed/path_malicious/../../../../tmp/evil.txt

If the application runs as a privileged user, the attacker’s file lands outside the safe directory.

How Can an Attacker Use This?

1. Send a malicious archive (such as a module package) with paths engineered to escape the allowed folder.

Trigger decompression on a vulnerable server or service.

3. Depending on permissions, overwrite important files, plant backdoors, or even escalate privilege.

Exploit Details

- Precondition: App using FHIR core packages, decompressing/unpacking modules from an untrusted or mixed source.

Fix & Mitigation

HL7 fixed this bug in Core Libraries version 5.6.106 by making directory checks stricter. Instead of substring matching, the fixed code resolves and normalizes actual file system paths before comparing, blocking attempts to traverse above the allowed folder.

Fixed Example in Java

import java.nio.file.*;

Path targetFolder = Paths.get("allowed/path").toAbsolutePath().normalize();
Path destination = Paths.get(userSuppliedPath).toAbsolutePath().normalize();

if (destination.startsWith(targetFolder)) {
    // safe to write file
}

If the extracted destination doesn't truly reside within the allowed path after normalization, it is rejected.

Never decompress untrusted files without proper validation and sandboxing.

- Use file system APIs to resolve absolute/normalized paths before checking allowed directories.

References

- Official NVD Entry for CVE-2023-28465
- HL7 FHIR Core Libraries GitHub Repository
- Previous Issue CVE-2023-24057

Conclusion

CVE-2023-28465 is a clear example of why substring-based path validation is risky. In systems as sensitive as healthcare IT, a seemingly small bug can have wide-ranging and dangerous impacts. Always be careful with package decompression and path validation, and keep up to date with security advisories in your tech stack.

If you maintain healthcare software, upgrade now and double-check your file path handling!

*Written exclusively for this channel. If you found this useful, share with your development and DevSecOps teams!*

Timeline

Published on: 12/12/2023 17:15:07 UTC
Last modified on: 12/15/2023 16:35:16 UTC