Sui's latest vulnerability "hamster wheel" technical details and in-depth analysis

Previously, the CertiK team discovered a series of denial-of-service vulnerabilities in the Sui blockchain. Among these vulnerabilities, a new and high-impact vulnerability stands out. This vulnerability can cause Sui network nodes to be unable to process new transactions, and the effect is equivalent to a complete shutdown of the entire network.

Just last Monday, CertiK received a $500,000 bug bounty from SUI for discovering this major security vulnerability. CoinDesk, an authoritative media in the U.S. industry, reported on the event, and then major media also released related news following its report.

This security vulnerability is vividly called "Hamster Wheel": its unique attack method is different from the currently known attacks. The attacker only needs to submit a payload of about 100 bytes to trigger an infinite loop in the Sui verification node. , making it unresponsive to new transactions.

In addition, the damage caused by the attack can continue after the network is restarted, and can be automatically propagated in the Sui network, making all nodes unable to process new transactions like hamsters running endlessly on the wheel. We therefore refer to this unique type of attack as a "hamster wheel" attack.

After discovering the bug, CertiK reported it to Sui through Sui's bug bounty program. Sui also responded effectively at the first time, confirmed the seriousness of the vulnerability, and actively took corresponding measures to repair the problem before the mainnet launch. In addition to fixing this particular vulnerability, Sui also implemented preventative mitigations to reduce the potential damage this vulnerability could cause.

To thank the CertiK team for their responsible disclosure, Sui awarded the CertiK team a $500,000 bounty.

The details of this critical vulnerability will be disclosed at the technical level below, and the root cause and potential impact of the vulnerability will be clarified.

Vulnerability Explanation

The key role of validators in Sui

For block chains based on the Move language such as Sui and Aptos, the protection mechanism for preventing malicious payload attacks is mainly static verification technology. Through static verification technology, Sui can check the validity of the payload submitted by the user before the contract is issued or upgraded. The validator provides a series of checkers to ensure the correctness of the structure and semantics. Only after passing the check verification, the contract will enter the Move virtual machine to be executed.

Malicious Payload Threats on the Move Chain

The Sui chain provides a new set of storage models and interfaces on top of the original Move virtual machine, so Sui has a customized version of the Move virtual machine. In order to support new storage primitives, Sui further introduces a series of additional and customized inspection methods for security verification of untrusted payloads, such as object security and global storage access functions. These custom checks fit Sui's unique features, so we call these custom checks Sui validators.

Sui's order of checking loads

As shown in the figure above, most of the checks in the verifier perform structural security verification against the CompiledModule (representing the execution of the user-supplied contract payload). For example, use the "Duplicate Checker" to ensure that there are no duplicate entries in the runtime payload; use the "Limit Checker" to ensure that the length of each field in the runtime payload is within the maximum allowed entry limit.

In addition to the structural checks, the static checks of the verifier still require more complex analysis methods to ensure the robustness of untrusted payloads at the semantic level.

Learn about Move's abstract interpreter:

Linear and Iterative Analysis

The abstract interpreter provided by Move is a framework specially designed for performing complex security analysis on bytecode through abstract interpretation. This mechanism makes the verification process more granular and accurate, and each validator is allowed to define their unique abstract state for analysis.

At start-up, the abstract interpreter builds a control flow graph (CFG) from compiled modules. Each basic block in these CFGs maintains a set of states, a "pre-order state" and a "post-order state". The "pre-order state" provides a snapshot of the program state before the execution of the basic block, while the "post-order state" provides a description of the program state after the execution of the basic block.

When the abstract interpreter does not encounter a jumpback (or loop) in the control flow graph, it follows a simple linear execution principle: each basic block is analyzed in turn, and the previous instruction is calculated according to the semantics of each instruction in the block. Sequential state and post-sequential state. The result is an accurate snapshot of the state of each basic block during the execution of a program, helping to verify the security properties of the program.

Workflow of the Move abstract interpreter

However, the process becomes more complicated when there are loops in the control flow. The appearance of a cycle means that the control flow graph contains a jump-back edge. The source of the jump-back edge corresponds to the subsequent state of the current basic block, and the target basic block (loop head) of the jump-back edge is a previously analyzed Therefore, the abstract interpreter needs to carefully merge the states of the two basic blocks related to the jumpback.

If the merged state is found to be different from the existing preorder state of the loop head basic block, the abstract interpreter updates the state of the loop head basic block and restarts the analysis starting from this basic block. This iterative analysis process will continue until the loop pre-state stabilizes. In other words, this process is repeated until the preorder state of the loop head basic block no longer changes between iterations. Reaching a fixed point indicates that the cycle analysis is complete.

Sui IDLeak Validator:

Customized Abstract Interpretation Analysis

Unlike the original Move design, Sui's blockchain platform introduces a unique "goal"-centric global storage model. A notable feature of this model is: any data structure with a key attribute (stored on the chain as an index) must have the ID type as the first field of the structure. The ID field is immutable and cannot be transferred to other objects, since each object must have a globally unique ID. To ensure these properties, Sui built a set of custom analysis logic on top of the abstract interpreter.

The IDLeak verifier, also known as id_leak_verifier, works in conjunction with the abstract interpreter for analysis. It has its own unique AbstractDomain, called AbstractState. Each AbstractState consists of AbstractValue corresponding to multiple local variables. The state of each local variable is monitored by AbstractValue to track whether an ID variable is brand new.

In the process of structure packing, IDLeak validator only allows packing a brand new ID into a structure. By abstracting interpretation analysis, IDLeak validators can exhaustively track local data flow state to ensure that no existing IDs are transferred to other struct objects.

Sui IDLeak validator state maintenance inconsistency issue

The IDLeak validator is integrated with the Move abstract interpreter by implementing the AbstractState::join function. This function plays an integral role in state management, especially in merging and updating state values.

Examine these functions in detail to understand their operation:

In AbstractState::join, the function takes another AbstractState as input and attempts to merge its local state with the current object's local state. For each local variable in the input state, it compares that variable's value to its current value in the local state (defaults to AbstractValue::Other if not found). If the two values are not equal, it will set a "changed" flag as the basis for whether the final state merge result has changed, and update the local variable value in the local state by calling AbstractValue::join.

In AbstractValue::join, the function compares its value with another AbstractValue. If they are equal, it will return the value passed in. If not equal, returns AbstractValue::Other.

However, this state maintenance logic contains a hidden inconsistency problem. Although AbstractState::join will return a result indicating that the merged state has changed (JoinResult::Changed) based on the difference between the new and old values, the merged updated state value may still remain unchanged.

This inconsistency problem is caused by the order of operations: the decision to change the state in AbstractState::join occurs before the state update (AbstractValue::join), and this decision does not reflect the real state update result.

In addition, in AbstractValue::join, AbstractValue::Other plays a decisive role in the result of the merge. For example, if the old value is AbstractValue::Other and the new value is AbstractValue::Fresh, the updated state value is still AbstractValue::Other, even if the old and new values are different, the state itself remains unchanged after the update.

Example: Incoherence of Stateful Connections

This introduces an inconsistency: the result of merging the state of a basic block is judged to be "changed", but the merged state value itself has not changed. In the process of abstract interpretation analysis, such inconsistencies may have serious consequences. We review the behavior of an abstract interpreter when a cycle occurs in a control flow graph (CFG):

When a loop is encountered, the abstract interpreter employs an iterative analysis method to merge the state of the jump-back target basic block and the current basic block. If the merged state changes, the abstract interpreter will re-analyze starting from the jump target.

However, if the merging operation of the abstract interpretation analysis erroneously marks the state merging result as "change", when in fact the value of the internal variable of the state has not changed, it will lead to endless re-analysis, resulting in an infinite loop.

Further Exploitation of Inconsistencies

Triggers infinite loop in Sui IDLeak validator

Exploiting this inconsistency, an attacker can construct a malicious control flow graph that tricks IDLeak validators into an infinite loop. This carefully constructed control flow graph consists of three basic blocks: BB1 and BB2, BB3. It is worth noting that we intentionally introduced a back jump edge from BB3 to BB2 to construct a loop.

Malicious CFG+ status can lead to an internal infinite loop in IDLeak validator

The process starts with BB2, where the AbstractValue of a particular local variable is set to ::Other. After executing BB2, the flow transfers to BB3 where the same variable is set to ::Fresh. At the end of BB3, there is a back jump edge, jumping to BB2.

The aforementioned inconsistencies play a key role in the abstract interpretation of this example. When the back jump edge is processed, the abstract interpreter attempts to connect the postorder state of BB3 (with variable "::Fresh") with the preorder state of BB2 (with variable "::Other"). The AbstractState::join function notices the difference between the old and new values and sets the "change" flag to indicate that BB2 needs to be reanalyzed.

However, the dominant behavior of "::Other" in AbstractValue::join means that after the AbstractValue is merged, the actual value of the BB2 state variable is still "::Other", and the result of the state merge has not changed.

So once this cyclical process starts, i.e. as validators continue to reanalyze BB2 and all its successor basic block nodes (BB3 in this case), it continues indefinitely. The infinite loop consumes all available CPU cycles, making it unable to process and respond to new transactions, which persists across validator restarts.

By exploiting this vulnerability, validating nodes run endlessly like hamsters on a wheel in an infinite loop, unable to process new transactions. We therefore refer to this unique type of attack as a "hamster wheel" attack.

The “hamster wheel” attack can effectively bring Sui validators to a standstill, which in turn can bring down the entire Sui network.

After understanding the cause of the vulnerability and the triggering process, we built a concrete example by using the following Move bytecode simulation and successfully triggered the vulnerability in the simulation in the real environment:

This example shows how to trigger the vulnerability in a real environment through carefully constructed bytecode. Specifically, an attacker could trigger an infinite loop in the IDLeak validator, consuming all of the CPU cycles of a Sui node with a payload of only about 100 bytes, effectively preventing new transaction processing and causing a denial of service on the Sui network.

The "Hamster Wheel" attack continues to harm the Sui network

Sui's bug bounty program has strict regulations on the assessment of vulnerability levels, mainly based on the degree of harm to the entire network. Vulnerabilities that meet the "critical" rating must shut down the entire network and effectively prevent new transaction confirmations, and require a hard fork to fix the problem; (medium)” or “high risk (high)” vulnerabilities.

The "hamster wheel" vulnerability discovered by the CertiK Skyfall team can shut down the entire Sui network, and requires an official release of a new version for upgrade and repair. Sui ultimately rated the vulnerability as "Critical" based on its criticality. In order to further understand the serious impact caused by the "hamster wheel" attack, it is necessary for us to understand the complex architecture of Sui's backend system, especially the entire process of publishing or upgrading transactions on the chain.

Overview of interactions for submitting transactions in Sui

Initially, user transactions are submitted via front-end RPC and passed to back-end services after basic verification. The Sui backend service is responsible for further validating incoming transaction payloads. After successfully verifying the user's signature, the transaction is converted into a transaction certificate (containing transaction information and Sui's signature).

These transaction certificates are a fundamental part of the operation of the Sui network and can be disseminated among various verification nodes in the network. For contract creation/upgrade transactions, before they can be uploaded to the chain, the verification node will call the Sui verifier to check and verify the validity of the contract structure/semantics of these certificates. It is during this critical verification stage that the "infinite loop" vulnerability can be triggered and exploited.

When the vulnerability was triggered, it caused the verification process to be interrupted indefinitely, effectively hindering the system's ability to process new transactions and causing the network to shut down entirely. To add insult to injury, the situation persisted after node restarts, which meant that traditional mitigations were far from adequate. Once the vulnerability is triggered, there will be "continuous damage" and leave a lasting impact on the entire Sui network.

Sui's solution

After feedback from CertiK, Sui confirmed the vulnerability in a timely manner and released a fix to address the critical flaw. The fix ensures consistency between state changes and after-change flags, removing the critical effect of the "hamster wheel" attack.

To remove the aforementioned inconsistency, Sui's fix includes a small but critical tweak to the AbstractState::join function. This patch removes the logic of determining the result of state merging before executing AbstractValue::join. Instead, execute the AbstractValue::join function for state merging first, and set the merge by comparing the final update result with the original state value (old_value) A flag for changes.

In this way, the result of state merging will be consistent with the result of the real update, and an infinite loop will not occur during the analysis process.

In addition to fixing this specific vulnerability, Sui also deployed mitigations to reduce the impact of future validator vulnerabilities. According to Sui's response in the bug report, the mitigation involves a feature called Denylist.

"However, validators have a node configuration file that allows them to temporarily reject certain classes of transactions. This configuration can be used to temporarily disable processing of releases and package upgrades. Due to this bug is running Sui before signing a release or package upgrade tx validators, while the denylist will stop the validator from running and drop the malicious tx, temporarily denylisting these tx types is a 100% effective mitigation (although it will temporarily disrupt service for people trying to release or upgrade code ).

Incidentally, we've had this TX deny list configuration file for a while now, but we've also added a similar mechanism for certificates as a follow-up mitigation to your previously reported "validator loop" vulnerability. With this mechanism, we will have more flexibility against this attack: we will use certificate deny list configuration to make validators forget about bad certificates (breaking the infinite loop), and TX deny list configuration to prohibit publishing/upgrades , thereby preventing the creation of new malicious attack transactions. Thanks for making us think about this!

A validator has a limited number of "ticks" (different from gas) for bytecode verification before signing a transaction, and if all the bytecode issued in a transaction cannot be verified in this many ticks, the validator will refuse to sign the transaction , preventing it from executing on the network. Previously, metering only applied to a selected set of complex validator passes. To combat this, we extend metering to each validator to guarantee a constraint on the work that a validator performs during the validation process of each tick. We also fixed a potential infinite loop bug in the ID leak validator. "

--Explanation from Sui developers about bug fixes

All in all, Denylist enables validators to temporarily avoid exploiting vulnerabilities in validators and effectively prevent potential damage caused by some malicious transactions by disabling the release or upgrade process. When Denylist's mitigation measures take effect, nodes ensure that they can continue to work by sacrificing their own publishing/updating contract functions.

Summarize

In this article, we share the technical details of the "Hamster Wheel" attack discovered by the CertiK Skyfall team, explaining how this new type of attack exploits key vulnerabilities to cause a complete shutdown of the Sui network. In addition, we also carefully studied Sui's timely response to fix this critical issue, and shared the vulnerability fix and subsequent mitigation methods for similar vulnerabilities.

View Original
This page may contain third-party content, which is provided for information purposes only (not representations/warranties) and should not be considered as an endorsement of its views by Gate, nor as financial or professional advice. See Disclaimer for details.
  • Reward
  • Comment
  • Share
Comment
0/400
No comments
Trade Crypto Anywhere Anytime
qrCode
Scan to download Gate app
Community
English
  • 简体中文
  • English
  • Tiếng Việt
  • 繁體中文
  • Español
  • Русский
  • Français (Afrique)
  • Português (Portugal)
  • Bahasa Indonesia
  • 日本語
  • بالعربية
  • Українська
  • Português (Brasil)