Somnia Disclosed Report

Audit report Somnia Audit Contest

Somnia - Peer Impersonation Attack via Challenge Replay

Company
Created date
Sep 10 2025

Target

https://github.com/hackenproof-public/somnia

Vulnerability Details

Somnia - Peer Impersonation Attack via Challenge Replay

Description

A vulnerability exists in the peer-to-peer handshake implementation that allows an attacker to impersonate legitimate nodes during connection establishment. This attack exploits the bidirectional nature of the handshake protocol to replay challenges between different connection sessions, enabling successful spoofing of node identities at the transport layer.

Technical Analysis

Normal Handshake Flow

The peer-to-peer handshake protocol looks something like this (simplified):

  1. Node A initiates a connection to Node B
  2. Both nodes generate and exchange random challenges
  3. Each node signs the received challenge with their private key
  4. Both nodes verify the received signatures to authenticate their peer
  5. Upon successful verification, the connection is established with confirmed peer identity

Vulnerability Root Cause

The security of this handshake relies on the assumption that challenges are unpredictable and cannot be known in advance. However, the protocol's bidirectional nature creates a vulnerability window where:

  • Challenges are generated and sent before signature verification is complete
  • An attacker can obtain a legitimate challenge from one node and replay it to another
  • The protocol lacks binding between the challenge and the specific connection context

Attack Methodology

The exploitation leverages the timing gap between challenge exchange and signature verification to perform a challenge replay attack:

Step-by-Step Attack Flow

  1. Initial Connection Setup

    • Attacker establishes connection with Node A
    • Attacker sends arbitrary challenge (challenge0) to Node A
  2. Challenge Harvesting

    • Node A responds with its own challenge (challenge1)
    • Node A also provides signature for challenge0 (not needed for attack)
    • Critical vulnerability: Attacker now possesses a legitimate challenge from Node A
  3. Challenge Replay

    • Attacker initiates separate connection with Node B
    • Attacker sends the harvested challenge1 (from Node A) to Node B
    • Node B, believing this is a legitimate challenge, signs it with its private key
  4. Identity Spoofing

    • Node B returns the signature for challenge1 to the attacker
    • Attacker relays this signature back to Node A
    • Node A verifies the signature successfully (it's a valid signature for its own challenge)
    • Result: Node A believes it has completed handshake with Node B, when it actually connected to the attacker

Attack Outcome

The attacker successfully impersonates Node B in Node A's view, establishing an authenticated connection under false identity. This breaks the fundamental assumption that authenticated connections represent genuine peer identities.

Impact

Severity: High

This peer impersonation attack allows an attacker to successfully establish authenticated connections while spoofing their identity at the transport layer.

Direct Impact - Transport Layer Spoofing:

  1. Peer Discovery Manipulation: The attacker can send malicious ShareConnectedPeerMessage and RequestPeerDetailsMessage while impersonating legitimate nodes, potentially:

    • Misleading nodes about network topology
    • Redirecting peer discovery to attacker-controlled endpoints
    • Causing network partitioning or isolation attacks
  2. Mempool Transaction Attribution Bypass: The attacker can send transactions to the mempool while appearing to originate from a different peer, potentially:

    • Bypassing per-peer rate limiting mechanisms
    • Evading reputation-based filtering
    • Conducting transaction spam attacks while framing innocent nodes
  3. Network Monitoring Evasion: The attacker can evade network-level monitoring and metrics collection that relies on transport-layer sender identification.

Escalation Scenarios:

  1. Eclipse Attacks: By manipulating peer discovery, an attacker could isolate honest nodes from the network
  2. Resource Exhaustion: Bypassing rate limiting could enable more effective DoS attacks

So to summarize, an attacker could use this vulnerability to disrupt network connectivity and potentially isolate nodes, while simultaneously conducting enhanced DoS attacks by evading per-peer rate limits.

Remediation

Primary Recommendation: Connection Context Binding

Include connection-specific context in the challenge signature to prevent replay attacks:

For example, include the IP address of the peer as part of the signature data.

Validation steps

Proof of Concept

Overview

The following proof of concept demonstrates the vulnerability by implementing a controlled attack scenario where one node acts as an attacker and successfully impersonates another peer during handshake.

Implementation

Apply the diff included with this report:

Test Case Implementation

Add the following test to demonstrate the attack to the protocol_network_test.cc file:

TEST_F(ProtocolNetworkTest, ProtocolNetworkConnectionSpoofAttack) {
  std::vector<std::unique_ptr<NodeActorManager>> nodes;
  std::vector<crypto::PrivateKeys> keys;
  std::vector<ChainParameters> params;

  // Create 3 nodes: Attacker, Node A, Node B
  for (int i = 0; i < 3; i++) {
    keys.emplace_back(crypto::PrivateKeys::GenerateNonRandomKeys(1337 + i));
    params.push_back(protocol_network_chain_parameters);

    params[i].local_parameters.protocol_listen_port = 9051 + (i * 10);
    params[i].local_parameters.data_listen_port = 9101 + (i * 10);
    params[i].local_parameters.api_http_port = 9201 + (i * 10);
    params[i].local_parameters.api_websocket_port = 9301 + (i * 10);
    params[i].local_parameters.storage_database_directory =
        fmt::format("/tmp/somnia_{}_{}", keys[i].GetAddress(), RandomHash());

    nodes.emplace_back(std::make_unique<NodeActorManager>(params[i], keys[i], epoch_manager));
  }

  auto& main_network = nodes[0]->protocol_network.GetAsyncProtocolNetwork();

  // Trigger the attack by connecting the attacker to both legitimate nodes
  for (int i = 1; i < 3; i++) {
    main_network.ConnectToPeer(keys[i].GetAddress(), "127.0.0." + std::to_string(i),
                               params[i].local_parameters.protocol_listen_port);
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
  }

  // Allow sufficient time for attack execution
  std::this_thread::sleep_for(std::chrono::seconds(15));
}

Execution Instructions

bazel test --config no-avx -s //somnia/node:protocol_network_test --test_output=all --test_filter="ProtocolNetworkTest.*"

Note: The sleep timeout may need adjustment based on system performance and network conditions.

Expected Results

Upon successful execution, the test demonstrates the vulnerability through the following log evidence:

[2025-09-10 01:22:31.579] [protocol_net   ] [info] PeerNetwork successfully completed handshake with 0x95f9f0834ceeeb6beaf51955a21d61b0ed21114f and my key is 0x371b429f37d6183509d07f94fe8a1aed928353f3
[2025-09-10 01:22:31.628] [protocol_net   ] [info] PeerNetwork successfully completed handshake with 0x054a8494bea2c5251e70c3e8120138b21ab91193 and my key is 0x95f9f0834ceeeb6beaf51955a21d61b0ed21114f
[2025-09-10 01:22:31.639] [protocol_net   ] [info] PeerNetwork successfully completed handshake with 0x371b429f37d6183509d07f94fe8a1aed928353f3 and my key is 0x054a8494bea2c5251e70c3e8120138b21ab91193
[2025-09-10 01:22:31.639] [protocol_net   ] [info] PeerNetwork successfully completed handshake with 0x95f9f0834ceeeb6beaf51955a21d61b0ed21114f and my key is 0x054a8494bea2c5251e70c3e8120138b21ab91193

Attack Scenario Analysis

Node Identities:

  • Attacker: 0x054a8494bea2c5251e70c3e8120138b21ab91193
  • Node A: 0x371b429f37d6183509d07f94fe8a1aed928353f3
  • Node B: 0x95f9f0834ceeeb6beaf51955a21d61b0ed21114f

Resulting Connection State: The attack creates a false connection topology where Node A believes it has established a legitimate connection with Node B, but is actually connected to the attacker:

Connection Connected Node Perspective Reality
Node A ↔ Attacker Connected to Node B Connected to Attacker
Node B ↔ Attacker Connected to Attacker Connected to Attacker
Attacker ↔ Node A Connected to Node A Connected to Node A
Attacker ↔ Node B Connected to Node B Connected to Node B

This demonstrates successful identity spoofing where the attacker has inserted itself into the intended Node A ↔ Node B communication path while maintaining Node A's belief that it is connected to the legitimate Node B.

Important Note: In the PoC we connected to Node B just because it was simpler, but in reality, the attacker can drop the handshake with Node B and just connect to Node A without compromising it's own identity. Also, the attacker can do the same attack with Node B and connect to Node B as Node A, fooling them both.

Attachments

hidden
CommentsReport History
Comments on this report are hidden
Details
Statedisclosed
Severity
Medium
Bounty$5,127
Visibilitypartially
VulnerabilityBlockchain
Participants (2)
author
triage team