Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SECURITY] Uncontrolled Memory Allocation in RLPx Frame Handling Leading to Denial of Service #1148

Open
pventuzelo opened this issue Nov 12, 2024 · 0 comments

Comments

@pventuzelo
Copy link

Our team (@FuzzingLabs) discovered a potential Denial of Service (DoS) vulnerability in the P2P protocol, specifically within the RLPx frame handling. This vulnerability can result in high memory allocation due to repeated dynamic allocations triggered by a malicious node, potentially causing a slowdown or crash in affected nodes.

Vulnerability details

  • Severity: Medium
  • Affected components : read function in frame.rs (lambda_ethereum_rust/crates/networking/p2p/rlpx/frame.rs)

Steps to Reproduce

To theoretically exploit this vulnerability, an attacker could create a malicious node programmed to send multiple requests in quick succession, leveraging multi-threading to maximize request volume. By carefully crafting these requests to set the frame_size to its maximum value, the node would trigger the allocation of a large buffer size repeatedly in a single-threaded Tokio context, ultimately resulting in memory exhaustion or race conditions within the read function.

The following approach explains how a theoretical attack could work:

  1. Deploy a Malicious Node: Set up a node that bypasses memory or size validation checks in its frame.rs implementation.
  2. Send Repeated Requests: Program the malicious node to send multiple concurrent requests with a frame_size set to the maximum possible value (e.g., [0, 0, 255, 255, 255, 255]). This value maximizes the padded_size, leading to significant memory allocation in each request.
  3. Trigger a Race Condition: By sending these requests in parallel with multi-threading, an attacker may exhaust memory or processing resources due to rapid reallocation within the single-threaded Tokio runtime context. Because the vector (frame_data) is dynamically allocated and only cleaned up after processing, this approach can exhaust system resources.

Root cause

The vulnerability resides in the read function in frame.rs, specifically in how it handles frame_size:

let frame_size: usize = u32::from_be_bytes([0, header_text[0], header_text[1], header_text[2]])
        .try_into()
        .map_err(|_| RLPxError::CryptographyError("Invalid frame size".to_owned()))?;
let padded_size = frame_size.next_multiple_of(16);
let mut frame_data = vec![0; padded_size + 16];
stream.read_exact(&mut frame_data).await.unwrap();

The frame_size parameter is derived from the message header and directly controls the allocation of frame_data. Without any upper-bound validation on frame_size, a large value (e.g., 0xffffff) can lead to significant memory allocation. This may exhaust system resources, causing instability or a crash.

Impact

This vulnerability can cause affected nodes to experience severe slowdowns, unresponsiveness, or even crashes. The impact extends to other nodes on the network, which could be isolated if a significant number of nodes are affected by this issue simultaneously.

Recommendations

Implement Frame Size Limits: Add validation for frame_size within the read function, ensuring that the value does not exceed a reasonable threshold to prevent excessive memory allocation. Additionally, consider implementing asynchronous request limits or load balancing in the read function to mitigate potential race conditions and high memory usage in the single-threaded Tokio context.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: No status
Development

No branches or pull requests

1 participant