Full Report
The Financial Non-Fungible Token (FNFT) of Revest has vaults that allow the transferring of access to these vaults. This works by a user sending some asset, such as wETH to the contract. Then, using the funds from that asset, FNFTs are generated with an identifier. A user can divide up the FNFTs as they like. Once the vault is unlocked, then the FNFTs can be burned to receive funds from the underlying asset, such as wETH. The entry contract has three interfaces to mint FNFTs by locking previous assets. mintTimeLock locks the asset for a set period of time, mintValueLock will unlock only when the asset goes above or below a certain value and mintAddressLock will unlock assets when a specific account opens it. All of these paths call the same set of additional contracts for unlocking and locking contracts. An additional piece of functionality called depositAdditionalToFNFT is used to lock more underlying assets to an existing lock. When this happens, it assumes that the amount can be evenly distributing among the existing NFT owner. If it is not, then a new lock is placed on the ID and burns some quantity of the old FNFT tokens and mints the new quantity. This is done by adding up the old quantity with the new quantity to get a total quantity. So, what's the vulnerability then? Well, there is two. The simpler bug (and one discovered by the authors of the post) is a logic issue. When handling multiple deposits on the same call, the depositAmount for a given FNFT is put BOTH into the old lock and the new lock! This means we can use our funds twice, which is a recipe for disaster. Instead, it should destroy the original lock and put the funds into the new one only. The original vulnerability comes from a re-entrancy attack. When creating or updating the FNFT, the id gets updated. By creating an FNFT, the id should be increased. However, prior to incrementing the counter the variable fnftId, ERC-1155 standard's callback mechanism can be triggered. Since the id has not been incremented in the state yet, shenanigans can be pulled. Remember how the update will either add the funds to a new FNFT (and increment the ID) or use the current one? By reentering the contract with the fnftId in the wrong state, we can create a update the previous FNFT (increment by 1) to update the depositAmount of a token. Why is this bad? This state update is catastrophic because it will update the funds in the contract but not the amount of tokens minted. As a result, an attacker can create a large amount of tokens with zero value (token 2) and update the value of token 1 to really update the value of token 2! By doing this, the cost of token 2 is not zero but there are a ton of tokens we can withdraw for a high value. That last re-entrancy vulnerability is insanely complex and I cannot believe somebody truly figured that out. The diagrams in the blog post are amazing for explaining this, as there are many steps to make this work.
Analysis Summary
# Vulnerability: Multiple Logic Flaws in Revest Finance FNFT Handling
## CVE Details
- **CVE ID:** Not explicitly listed in the article (Common for DeFi-specific protocol exploits; often tracked via audit reports or insect/post-mortem IDs).
- **CVSS Score:** Estimated 9.8 - 10.0 (Critical)
- **CWE:** CWE-667 (Improper Locking), CWE-841 (Improper Enforcement of Behavioral Workflow), CWE-1073 (Non-Atomic Refactor)
## Affected Systems
- **Products:** Revest Finance (DeFi Staking Platform)
- **Versions:** Deployments active prior to March 27, 2022.
- **Configurations:** Smart contracts utilizing the `depositAdditionalToFNFT` function and ERC-1155 standard callbacks within the Revest ecosystem on Ethereum.
## Vulnerability Description
Revest Finance suffered from two distinct vulnerabilities within its Financial Non-Fungible Token (FNFT) logic:
1. **Re-entrancy via ERC-1155 Callback:** When creating a new FNFT, the contract fails to follow the Checks-Effects-Interactions pattern. The `fnftId` counter is not incremented until *after* the minting process. Because ERC-1155 includes a receiver callback mechanism, an attacker can re-enter the contract while the `fnftId` is in an inconsistent state. This allows an attacker to manipulate the `depositAmount` of a new token by referencing an outdated ID, effectively inflating the value of worthless tokens.
2. **Logic Flaw in `depositAdditionalToFNFT`:** This "zero-day" discovered by BlockSec involves how assets are distributed during additional deposits. When multiple deposits occur in a single call, the function erroneously attributes the `depositAmount` to both the original FNFT lock and the newly generated lock. This "double-counting" allows funds to be utilized twice within the internal accounting of the vault.
## Exploitation
- **Status:** Exploited in the wild (March 27, 2022). Approximately $2M in assets (BLOCKS, ECO, LYXe, RENA) were stolen.
- **Complexity:** High (Re-entrancy); Low (Logic flaw).
- **Attack Vector:** Network (Smart Contract Interaction via Ethereum).
## Impact
- **Confidentiality:** None
- **Integrity:** Critical (Manipulation of financial records and token values).
- **Availability:** High (Loss of TVL and underlying collateralized assets).
## Remediation
### Patches
- The Revest Finance team updated their smart contracts to ensure `fnftId` is incremented before external calls and corrected the asset distribution logic in the `TokenVault` contract.
### Workarounds
- At the time of discovery, the team implemented a workaround (typically pausing the contract or disabling the vulnerable `depositAdditionalToFNFT` interface) until new logic could be deployed.
## Detection
- **Indicators of Compromise:** Multiple minting events within a single transaction originating from a contract (rather than an EOA); calls to `onERC1155Received` that trigger subsequent calls back into the Revest entry contract.
- **Detection Methods and Tools:** DeFi security monitors (e.g., Forta, Tenderly) can be configured to alert on re-entrant calls or inconsistent state updates between the `FNFTHandler` and `TokenVault` contracts.
## References
- Revest Finance Post-Mortem: [https://blocksecteam.medium.com/revest-finance-vulnerabilities-more-than-re-entrancy-1609957b742f]
- Revest Entry Contract (Ethereum): [https://etherscan.io/address/0x2320a28f52334d62622cc2eafa15de55f9987ed9]
- BlockSec Twitter Analysis: [https://twitter.com/BlockSecTeam]