Appearance
S1C7: Delegate
1. 問題
チャレンジは delegatecall を使用して Delegate コントラクトを呼び出します。flag を取得するには、delegatecall のターゲットとパラメータを操作する必要があります。
2. 原因
delegatecall は、呼び出し元のストレージコンテキストで呼び出し先コントラクトのコードを実行します。Delegate コントラクトに重要なストレージ変数を変更する関数がある場合、攻撃者は delegatecall を通じてチャレンジコントラクトのストレージを変更できます。
3. 方案
- Delegate コントラクトのストレージレイアウトを分析し、どの関数がチャレンジコントラクトの重要な変数を変更するかを特定する
- チャレンジコントラクトの delegatecall エントリポイントを通じてその関数を呼び出す
- 2回の
cast sendで攻撃を完了する
bash
# Step 1: delegatecall を通じて重要な状態を変更
cast send $CHALLENGE "forwardCall(bytes)" <encoded_delegate_call>
# Step 2: mintFlag を呼び出す
cast send $CHALLENGE "mintFlag()"
4. 遭遇したトラップ
ストレージレイアウトの衝突: delegatecall は呼び出し元のストレージレイアウトを維持するため、同じストレージスロットの変数を使用する必要があります。
5. トラップの原因
delegatecall は msg.sender とストレージコンテキストを変更せず、呼び出し先コントラクトのコードロジックのみを借用します。変数は宣言順にスロットに格納されるため、2つのコントラクトで変数の宣言順序が異なる場合、予期しないストレージの上書きが発生します。
6. 解決方法
チャレンジコントラクトと Delegate コントラクトのストレージレイアウトを注意深く分析します。cast storage を使用して重要なスロットを読み取り、正しい関数を呼び出すことを確認します。
7. 技術ポイント
| ポイント | 説明 |
|---|---|
| delegatecall | ターゲットコントラクトのコードを借用するが、呼び出し元のストレージコンテキストと msg.sender を使用 |
| ストレージレイアウトの衝突 | コントラクトアップグレード/プロキシパターンにおける古典的な問題:ストレージスロットを揃える必要がある |
| プロキシパターン | delegatecall は UUPS/Transparent プロキシの基盤 |