#39678 [BC-Critical] Bypass certificate signing validation by double counting signatures due to capitalization

Submitted on Feb 4th 2025 at 18:37:25 UTC by @Blockian for Audit Comp | Shardeum: Core III

  • Report ID: #39678

  • Report Type: Blockchain/DLT

  • Report severity: Critical

  • Target: https://github.com/shardeum/shardus-core/tree/bugbounty

  • Impacts:

    • Bypassing Staking Requirements

    • Network not being able to confirm new transactions (total network shutdown)

Description

Impact

  1. Bypass stake certificate validation, allowing for non-staking nodes and network take-over

  2. Bypass nodes removal validation, allowing to remove nodes from the network

  • Note: same impact as reports 33222 and 34252 but a different root cause.

Root Cause

The function validateClosestActiveNodeSignatures counts unique signatures, but double counts duplicate signatures with different capitalization.

Attack Flow

Staking

  • Malicious node generates a fake JoinRequest with a fake StakingCertificate

    • It brute-forces StakingCertificate fields to make sure its one of the closest nodes to the hash of the staking certificates. This is easy, as only 1 node is needed to be close.

  • It creates the full JoinRequest, with multiple copies of its signature, instead of signatures from many other nodes, changing only the capitalization of the signatures.

  • It calls gossip-join-request

  • Other nodes receive the join request, and validate it using validateClosestActiveNodeSignatures.

  • The validation bypasses, as the signatures are valid because capitalization is ignored.

  • The new node joins the network without staking.

Kicking a node

  • Malicious node generates a fake RemoveCertificate.

  • It fills it with multiple copies of its signature, instead of signatures from many other nodes, changing only the capitalization of the signatures.

  • It calls remove-by-app gossip route.

  • Other nodes receive the certificate, and validate it using validateClosestActiveNodeSignatures.

  • The validation bypasses, as the signatures are valid because capitalization is ignored.

  • The victim node is kicked from the network.

Deep Dive

The function validateClosestActiveNodeSignatures uses Crypto.verify which uses lib-crypto-utils' verifyObj which calls verify which calls ensureBuffer on the signature which runs

on the signatures, which ignore capitalization.

Suggested Fix

I suggest to do two think:

  1. Ensure lowercase on any payload on any gossip and http endpoint.

  2. Count signers and not signatures.

Severity

This allows to take over the network (by kicking nodes / adding nodes) and so it critical. In addition, this is the same as 33222 and 34252 which were treated as critical.

Message to the project

I feel like my time was spent roughly 20% on researching, and 80% on trying to create POCs that match your standard or to answer question you give on the reported bugs. I believe there are more bugs to be found in the project, and that the current approach is the reason that bugs keep being found. I suggest you do an invite only competition, without defaultly requesting a POC, and only requesting one if you truly believe there is no bug. This would allow whitehats to actually uncover bugs.

Proof of Concept

POC

Note: this strongly relies on infosec_us_team's POC for 33222 so thanks to them :)

  1. Both shardeum and core should be on the bugbounty branch

  2. Apply debug-10-nodes as stated in the docs

  3. Apply the following patch on core:

  1. Apply the following patch on shardeum (obviously the logs are just for convenience)

  1. Runhttp://NODE_EXTERNAL_IP:NODE_EXTERNAL_PORT/blockian_gossipRemoveNode/?pk=PUBLIC_KEY_OF_ACTIVE_NODE_WITHIN_YOUR_SHARD_TO_KICK

Was this helpful?