
2022年3月27日、イーサリアム上のステーキングDeFiプロジェクトであるRevest Financeがハッキングされ、約200万ドルを失った。 BlockSecTeam チームはすぐに分析に介入し、分析結果をツイッターでコミュニティと共有しました。実際、分析結果をツイートを通じてコミュニティと共有したところ、Revest Finance の TokenVault 契約に重大なゼロデイ脆弱性が見つかりました。この脆弱性を利用して、攻撃者はより簡単な方法でプロトコル内の資産を盗むことができます。そこで私たちはすぐに Revest Finance プロジェクト関係者に連絡しました。脆弱性が修正されたことを確認した後、このブログをコミュニティと共有することにしました。
0. What's the Revest Finance FNFT
副題
Revest Financeは、DeFi分野でのステーキングのためのソリューションであり、ユーザーがRevest Financeを通じて参加するDeFiステーキングは、ステーキングポジションの現在および現在のステータスを表すNFT、すなわちFNFT(Finance Non-Fungible Token)を直接生成できます。将来価値。ユーザーは、Revest Finance が提供する 3 つのインターフェイスを通じてプロジェクトと対話できます。独自のデジタル資産を誓約し、対応する FNFT を発行します。
•mintTimeLock : ユーザーが誓約したデジタル資産は、一定期間が経過した後にのみロックを解除できます。
•mintValueLock : ユーザーが誓約したデジタル資産は、事前に設定された値まで評価または減価した場合にのみロックを解除できます。
•mintAddressLock : ユーザーが誓約したデジタル資産は、事前に設定されたアカウントによってのみロックを解除できます。
Rebest Financeは、次の3つのスマートコントラクトを通じてユーザーが預けたデジタル資産のロックとロック解除を完了します。
•FNFTHandler: ERC-1155 トークン (openzepplin 実装) から継承。ロック操作が実行されるたびに、fnftId はインクリメントされます (fnftId は ERC721 の tokenId に似ています)。 FNFT が作成されるとき、ユーザーはその totalSupply を指定する必要があります。ユーザーがFNFTの背後にある基礎資産を引き出したい場合は、対応する割合のFNTFを書き込む必要があります。
•LockManage:FNFTのロックを解除(アンロック)する条件を記録します。
•TokenVault: ユーザーが預けた原資産を送受信し、各 FNFT のメタデータを記録します。たとえば、fnftId = 1 で FNFT の背後に担保された資産タイプです。
この攻撃により、ハッカー攻撃のエントリ ポイントは mintAddressLock 関数であるため、この関数を例として FNFT のライフ サイクルを説明します。
•unlocker : User X ->ユーザー A が Revest の mintAddressLock 関数を呼び出します
ユーザー X のみがこのアセットのロックを解除できます。 • 受信者 : [ユーザー A 、ユーザー B 、ユーザー C] • 数量 : [50 、 25 、 25] -> ミント数量は 100 (合計 (数量)) 、ユーザー A 、ユーザー B 、ユーザーC はそれぞれ 50、25、25 枚のコインを所有しています。 •asset : WETH -> 造幣局からのFNFTはWETHを担保とします。 • depositAmount : 1e18 -> 各 FNFT の担保額は 1 WETH です (WETH の 10 進数は 18 です)
現在のシステムに他の FNFT がないと仮定すると、ユーザー A は mintAddressLock を通じてシステムと対話し、FNFTHandler = 1 によって返される fnftId
•fnftId : 1•unlocker : User X
LockManager はそれに対応するレコードを追加します
•fnftId : 1•asset : WETH•depoistAmount : 1e18
Token Vault はそれに対応するレコードを追加します
次に、Token Valut はユーザー A から 100 * 1e18 WETH を転送する必要があります。
最後に、システムはユーザー A、ユーザー B、およびユーザー C にそれぞれ 50、25、および 25 個の 01-FNFT を与えます。
これは、mintAddressLock 関数を通じて FNFT をミントすることによって行われます。
ユーザー X が 01-FNFT のロックを解除すると、ユーザー B はdrawFNFT を通じて原資産を引き出すことができます。図 2 に示すように、ユーザー B は、01-FNFT によって約束された 25 個のデジタル資産を引き出したいと考えています。
プロトコルは最初に 01-FNTF がロック解除されているかどうかを確認し、ロックが解除されている場合、プロトコルはユーザー B の 25 01-FNFT を書き込み、25*1e18 WETH をユーザー B に転送します。このとき、01-FNFT の totalSupply は 75 です。
Revest コントラクトは、ユーザーが既存の FNFT にさらに原資産を追加できるようにするために、depositAdditionalToFNFT と呼ばれる別のインターフェイスも提供します。以下に、その「通常の」使用法を 2 枚の写真で説明します。
ここには3つのケースがあります
1.quantity == 01-FNFT.totalSupply() (図 3 参照)
•quantity = 75 ->図 2 のシナリオをコンテキストとして考えると、ユーザー A は 01-FNFT の担保をさらに追加したいと考えています。
•amount = 0.5*1e18 ->75 01-FNFT の追加の誓約。
各 01-FNFT は 0.5*1e18 WETH を追加します。
したがって、ユーザー A は 37.5*1e18 WETH (75 * 0.5*1e18) を Token Vault に転送する必要があります。Token Vault はシステム アカウンティングを変更し、depositAmount を 1.5*1e18 に変更します。現在、各 01-FNFT は 1.5*1e18 WETH の資産を保持しています。
この時点で、ユーザー C は、withdrawFNFT を呼び出して、保持している 25 個の 01-FNFT を焼き切り、25*(1.5*1e18) = 37.5*1e18 WETH を奪うことができます。
したがって、この時点で01-FNFTのtotalSupplyは50となります。
2.quantity < 01-FNFT.totalSupply() (図 4 参照)
•quantity = 10 ->図 3 のシーンをコンテキストとして考えると、ユーザー A は 01-FNFT の担保を追加し続けます。
10 01-FNFT の追加誓約。 •amount = 0.5*1e18 -> 10 個の 01-FNFT のそれぞれに 0.5*1e18 WETH を追加します。< 01-FNFT.totalSupply()
量のせいで•fnftId : 2•asset : WETH•depositAmount : 2.0*1e18 (1.5*1e18 + 0.5*1e18)
したがって、ユーザー A は契約に対して 5*1e18 WETH を支払い、システムは 10 01-FNFT を書き込み、10 02-FNFT をミントし、10 01-FNFT によって運ばれる資産と、02-FNFT に注入されたユーザー A の新しく転送された資産を書き込みます。 。それで、あります
現時点では
• 01-FNFT.totalSupply : 40 01-FNFT.depositAmount : 1.5*1e18 (論理的にはそうあるべきです。以下を参照: 新しいゼロデイ脆弱性) • 02-FNFT.totalSupply : 10 02-FNFT.depositAmount : 2.0* 1e18
この場合、トランザクションは元に戻ります。
1. What't the Re-entrancy vulnerability
副題
mintAddressLock 関数と depositAdditionalToFNFT 関数の基本的なワークフローを理解した後、攻撃者が使用する再入メソッドを見てみましょう。最新の fnftId = 1 と仮定します (理解には影響しません)。
図5に示すように
最初の一歩:
•depositAmount = 0
•quantities = [2]
攻撃者は mintAddressLock 関数を呼び出します
攻撃者がdepositAmountを0に設定し、デジタル資産を移転しなかったため、Mintは2つの01-FNFTを発行しました。 01-FNFT の背後にある原資産に相当するものは 0 です。
•depositAmount = 0
ステップ 2: 攻撃者は mintAddressLock 関数を再度呼び出します
•数量 = [360000] ミント 36 個を準備します。02-FNFT デポジット金額は 0 です。
mint の最後のステップで、攻撃者は ERC-1155 コールバック メカニズムを使用して、depositAdditionalToFNFT 関数を再入力しました。 (詳細については、以下の _doSafeTransferAcceptanceCheck 関数を参照してください)
•quantity = 1
•amount = 1*1e18
•fnftId = 1
DepositAdditionalToFNFT で、攻撃者は< fntfId.totalSupply(),量のせいで
最後に、攻撃者はdrawNFNFT関数を呼び出し、360,001個の02-FNFTを書き込み、360,001*1e18 RENAを奪います。
提案された修正
2. the New Zero-day Vulnerability
副題
blockSecTeam チームが Revest Finance のコードを分析しているときに、handleMultipleDeposit 関数が私たちの注目を集めました。
ユーザーが担保を追加するためにdepositAdditionToNFT関数を呼び出すと、関数はFNFTのdepositAmountを変更します。コードから、newFNFTId != 0 の場合、この関数は fnftId に対応する FNFT の デポジット量を変更するだけでなく、newFNFTId に対応するデポジット金額も変更することがわかります。
常識によれば、newFNFTId !=0 の場合、システムは newNFTId に対応する depositAmount のみを記録する必要があります。 fnftIdに対応するdepositAmountは変更しないでください。
これは非常に深刻なロジックのバグであると考えられており、この脆弱性を悪用することで、攻撃者はシステムからデジタル資産を簡単に引き出すことができます。次の 3 つの図は、模擬攻撃の原理を説明しています。
最新の fnftId = 1 であると仮定します。
まず、攻撃者が mintAddressLock 関数を呼び出し、mint が 360,000 の 01-FNFT を生成します。攻撃者は金額を 0 に設定するため、資産を Rebest Finance プロトコルに転送する必要がありません。
ミント終了後、攻撃者は、depositAmount = 0 の 360000 01-FNFT を保有します。
•fnftId = 1
•amount = 1 * 1e18
•quantity = 1
次に、攻撃者は次のパラメータを使用して、depositAdditionalToFNFT 関数を呼び出します。
このプロトコルは、攻撃者の量 * トークンの量、つまり 1 * 1e18RENA を転送します。
このプロトコルは、攻撃者の 1 つの 01-FNFT を書き込み、それに対して 1 つの 02-FNFT を生成します (最新の fnftId = 2 と仮定)
handleMultipleDeposit 関数のロジックによれば、fnftId = 2 のアセットは、depositAmount を 1.0*1e18 に設定します。
ただし、fnftId = 1 のアセットの場合、depositAmount も 1.0*1e18 に設定され、これは 0 である必要があります。
明らかに、この方法を使用した攻撃は、実際の再入攻撃よりも簡単かつ直接的です。
文章
この脆弱性に対応して、blockSecTeam チームは対応するパッチ方法を提供しました。
副題
TokenVault と FNFTHandler の 2 つの脆弱なコントラクトには多くの主要な状態が保存されているため、短期間で再デプロイすることはできません。すぐに使用を再開するために、Revest Finance は Revest コントラクト (https://etherscan.io/address/) を正式に再デプロイしました。 0x36c2732f1b2ed69cf17133ab01f2876b614a2f27# コード)。このバージョンでは、さらなる攻撃を避けるために、ほとんどの複雑な機能がオフになります。プロジェクト当事者は将来的に状態を移行し、固定契約を再展開する予定です。
副題
DeFi プロジェクトのセキュリティを向上させるのは簡単な作業ではありません。 DeFiコミュニティをより安全にするために、コード監査に加えて、コミュニティはプロジェクトの監視や早期警告、さらには攻撃ブロックなど、より積極的な方法を採用する必要があると私たちは考えています。 (https://mp.weixin.qq.com/s/o41Da2PJtu7LEcam9eyCeQ).
参考文献
*[1]: https://blocksecteam.medium.com/revest-finance-vulnerabilities-more-than-re-entrancy-1609957b742f