Full Report
Crow is an async C++ HTTP/WebSocket library for creating flash web services. The framework implemented pipelining, which is async HTTP. This allows for different workers to get multiple HTTP requests at once, speeding up the service. However, the server was not built to handle this. All of the variables were global and were meant to handle one request at a time down a connection. Changes were made to fix this but not everything was found. The function check_destroy is used to delete the connection object once both the read and write flags are cleared. These flags are modified regardless of how many open requests there are. As a result, after the first write occurs, the connection will be destroyed, even though there is another call in the queue. Interesting cause of a vulnerability and difficult to simply stumble across. A good fuzzer which truly hit all functionality probably would have found this though.
Analysis Summary
# Vulnerability: Crow HTTP Framework Use-After-Free due to Pipelining Mismanagement
## CVE Details
- CVE ID: CVE-2022-38667
- CVSS Score: 9.8 (Critical) - Based on NIST/NVD rating (Original report rated 8.1 High)
- CWE: CWE-416 (Use After Free)
## Affected Systems
- Products: Crow HTTP/WebSocket framework
- Versions: Version 1.0+4 and older (both maintained fork `CrowCpp/Crow` and original repository `ipkn/crow` are implied as affected by this vulnerability if they share the logic).
- Configurations: Specifically affected when leveraging asynchronous HTTP processing (like pipelining) where the server logic was not designed to handle multiple concurrent requests on a single connection.
## Vulnerability Description
The vulnerability stems from an architectural mismatch in the Crow framework's asynchronous HTTP handling, specifically related to HTTP pipelining. While the HTTP parser supported pipelining (allowing multiple requests in a single connection stream), the server logic was fundamentally designed to handle only one request at a time using global variables for state management.
The flaw manifests in the `check_destroy` function, which clears read/write flags and safely deletes the connection object when both flags are cleared. However, these flags are modified based on individual HTTP operations (like a network write finishing) regardless of how many requests are queued via pipelining. Consequently, after the first write operation completes for one request in a pipeline, the connection object can be destroyed via `check_destroy()`, while another request processed by a different worker is still queued or attempting to continue using that now-deleted connection object, leading to a Use-After-Free (UAF).
Additionally, the report highlights three other code paths (in `do_write_static`, `do_write_general`, and `do_write_sync` completion lambda) where `check_destroy()` is called, and subsequent code continues to operate on the connection object, creating potential UAFs even if pipelining isn't the direct trigger.
## Exploitation
- Status: Not exploited in the wild (as of the article publication); exploitability for RCE was noted as potentially achievable but highly complex. Denial of Service (DoS) is easily achievable.
- Complexity: High (for achieving arbitrary code execution/RCE). Low (for triggering DoS).
- Attack Vector: Network
## Impact
- Confidentiality: High (If an attacker can control UAF state to read memory).
- Integrity: High (If an attacker can control UAF state to execute arbitrary code or corrupt state).
- Availability: High (Easily triggered to cause a crash/DoS by invalidating connection objects).
## Remediation
### Patches
- The linked article indicates a public fix was merged around August 22, 2022. The primary fix involves blocking HTTP pipelining altogether to prevent the race condition where connection destruction conflicts with ongoing pipeline processing.
* **Action:** Update to the patched version provided by the Crow maintainers (CrowCpp/Crow).
### Workarounds
- **Disable Pipelining:** The suggested fix involves ensuring that if evidence of multiple HTTP requests within a single parser feed call exists, the connection is dropped after the first reply, preventing processing of extra requests in the pipeline. Implementations should ensure their deployment environment or application logic prevents pipelined requests if patching is not immediately possible.
- **Refactoring Warning:** Developers are advised to review the three additional code paths identified where `check_destroy` execution is immediately followed by continued use of the object, potentially by modifying `check_destroy` to return a status indicating if destruction occurred.
## Detection
- **Indicators of Compromise (IOCs):** Unexplained application crashes, segmentation faults, or assertion failures occurring during network request processing or connection teardown, specifically under high load or rapid sequencing of HTTP operations.
- **Detection Methods and Tools:** Debugging tools focusing on memory corruption (like AddressSanitizer or Valgrind) tracing object lifetimes in the asynchronous I/O layer (Asio callbacks) when handling closing connections. Static analysis targeting call paths involving object destruction followed immediately by continued execution is recommended.
## References
- Vendor Advisories: Information is derived from the blog entry detailing the discovery and fix, referencing the commit history of the Crow project.
- Relevant links - defanged:
- `hXXps://gynvael.coldwind.pl/?id=753` (Original disclosure post)
- `hXXps://github.com/0xhebi/CVEs/blob/main/Crow/CVE-2022-38667.md` (Original report reference)