mcpField
S
smart-contract-vulnerabilities

smart-contract-vulnerabilities

github.com/yaklangセキュリティ2.6k3.6k 回インストール6 週間前に更新
リポジトリ

smart-contract-vulnerabilities について

SolidityやDeFiシステムを調査する監査担当者向けのスマートコントラクトセキュリティ応用スキルです。リエントランシー、アクセス制御、MEV、署名リプレイ、CREATE2などの攻撃パターンと対策、分析ツールをまとめています。

主な機能

  1. 01リエントランシーと算術欠陥のパターン
  2. 02アクセス制御とdelegatecallのリスク
  3. 03乱数、MEV、フラッシュローン攻撃
  4. 04署名リプレイとCREATE2の事例
  5. 05緩和策と監査ツール

活用シーン

  1. 01コントラクトコードのリエントランシーとアクセス制御の確認
  2. 02プロキシのストレージ配置とセレクター衝突の評価
  3. 03トランザクション順序操作と署名リプレイの検証
  4. 04静的解析、ファジング、形式検証の計画

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/yaklang/hack-skills --skill smart-contract-vulnerabilities

インストール後、Claude Code で/smart-contract-vulnerabilitiesを入力して読み込まれたか確認します。

同梱ファイルSOLIDITY_VULN_PATTERNS.md

詳細

SKILL:スマートコントラクトの脆弱性 — エキスパート向け攻撃プレイブック

AI LOAD INSTRUCTION:スマートコントラクト監査の高度な手法です。再入(単一関数、関数間、コントラクト間、読み取り専用)、整数オーバーフロー、アクセス制御、delegatecall、乱数操作、フラッシュローン、署名リプレイ、フロントランニング/MEV、CREATE2 の悪用を扱います。ベースモデルでは、微妙なコントラクト間再入や、プロキシパターンにおけるストレージレイアウトの衝突を見落とします。

0. 関連するルーティング

  • defi-attack-patterns:脆弱性が DeFi プロトコルのエクスプロイトの一部である場合(フラッシュローン、オラクル操作、ガバナンス攻撃)
  • deserialization-insecure:対象がブロックチェーンデータをデシリアライズするオフチェーンインフラストラクチャである場合
高度なリファレンス

次の内容が必要な場合は、SOLIDITY_VULN_PATTERNS.md も読み込んでください。

  • 各脆弱性クラスの脆弱なコードパターンと修正済みコードパターンの比較
  • 脆弱性を引き起こすガス最適化の落とし穴
  • スロット計算を含む、プロキシパターンのストレージ衝突の例

1. 再入

スマートコントラクトで最もよく知られた脆弱性です。外部呼び出しによって実行制御が移り、呼び出し前に状態が更新されていない場合、呼び出し先が再入できます。

1.1 古典的な再入(単一関数)
Victim.withdraw()
  ├── checks balance[msg.sender] > 0          ✓
  ├── msg.sender.call{value: balance}("")     ← external call
  │   └── Attacker.receive()
  │       └── Victim.withdraw()               ← re-enters before state update
  │           ├── checks balance[msg.sender]   ← still > 0!
  │           └── sends ETH again
  └── balance[msg.sender] = 0                 ← too late
1.2 関数間再入

2 つの関数が状態を共有している場合、攻撃者はコールバック中に別の関数へ再入します。

手順実行状態
1withdraw() を呼び出す → 外部呼び出し残高はまだ正の値
2攻撃者のフォールバック関数が transfer(attacker2) を呼び出す残高はリセット前に使用される
3transfer が古い残高を読み取る → 資金を移動するattacker2 がトークンを受け取る
4元の withdraw が完了し、残高をゼロにする被害が発生
1.3 コントラクト間再入

コントラクト A がコントラクト B を呼び出し、B がコントラクト A(または A の古い状態を読み取るコントラクト C)を呼び戻します。複数のコントラクトで状態を共有する DeFi プロトコルでは、特に危険です。

1.4 読み取り専用再入

再入された関数は view 関数であり、第三者コントラクトが価格計算に使用します。被害を受けるコントラクトの状態は変更されませんが、更新前の中間状態が読み取り側を誤解させます。

実例:remove_liquidity() のコールバック中に Curve プールの get_virtual_price() を読み取る → 価格が水増しされる → 依存するレンディングプロトコルで利益を得る。

緩和策
パターン保護レベル
Checks-Effects-Interactions(CEI)中核となる防御策。外部呼び出しの前に状態を更新する
ReentrancyGuard(OpenZeppelin)ミューテックスロック。同一トランザクション内の再入を防ぐ
プル決済パターン状態変更関数での外部呼び出しをなくす
すべての公開関数に CEI とガードを適用関数間再入に対する多層防御

2. 整数オーバーフロー/アンダーフロー

Solidity 0.8 より前

算術演算は黙ってラップアラウンドします:uint8(255) + 1 == 0、uint8(0) - 1 == 255。

攻撃例
残高アンダーフロー残高より大きい amount で balances[attacker] -= amount を実行 → 巨大な残高になる
供給量オーバーフローtotalSupply + mintAmount がラップアラウンドする → 上限チェックを回避する
タイムロック回避lockTime[msg.sender] + extend が過去の時刻にラップアラウンドする → 早期解除
Solidity 0.8 以降

デフォルトのチェック付き算術演算では、オーバーフロー時にリバートします。ただし、unchecked{} ブロックを使うとリスクが再発します。

unchecked {
    // "gas optimization" — but if i can be influenced by user input, overflow returns
    for (uint i = start; i < end; i++) { ... }
}
SafeMath の回避シナリオ
  • 型変換:SafeMath によるチェックの前に uint256 から uint128 へ変換して切り詰める
  • アセンブリブロック:mstore/add によって Solidity レベルのチェックを回避する
  • 除算前の中間乗算でのオーバーフロー:a * b がオーバーフローする (a * b) / c

3. アクセス制御

tx.origin と msg.sender
プロパティmsg.sendertx.origin
値直接の呼び出し元トランザクションを開始した EOA
認証に安全かはいいいえ — フィッシングコントラクトが tx.origin を引き継げる

攻撃:所有者をだまして攻撃者のコントラクトを呼び出させる → 攻撃者のコントラクトが、所有者の tx.origin を使って被害を受けるコントラクトを呼び出す。

よくあるパターン
問題影響
重要な関数に onlyOwner がない誰でも管理者関数を呼び出せます
selfdestruct が保護されていない誰でもコントラクトを破棄し、ETH を強制送金できます
delegatecall が保護されていない攻撃者が被害者のコンテキストで任意のコードを実行します
可視性の指定がない(0.6.0 より前)関数の可視性はデフォルトで public になります
ゼロアドレスのチェックがない所有権が address(0) に移転されます

4. 乱数の操作

オンチェーンの乱数ソースは、マイナー/バリデーターに予測される可能性があります。

ソース予測可能性
block.timestampマイナーには操作できる時間が約15秒あります
blockhash(block.number - 1)実行時には誰もが知っています
blockhash(block.number)現在のブロックハッシュは不明なため、常に0を返します
block.difficulty / block.prevrandaoマージ後は、ビーコンチェーンの値が既知になります

コミット・リビールの回避:リビールフェーズにタイムアウトや担保の要件がない場合、攻撃者は不利な結果になったときにリビールしないことを選べます(選択的中断攻撃)。


5. DELEGATECALL の脆弱性

delegatecall は、呼び出し先のコードを呼び出し元のストレージコンテキストで実行します。ストレージスロットの配置は完全に一致している必要があります。

ストレージ配置の衝突
Proxy (storage):         Implementation (code):
slot 0: owner            slot 0: someVariable
slot 1: implementation   slot 1: anotherVariable

実装が someVariable(スロット0)に書き込むと、プロキシの owner が上書きされます。攻撃者がスロット0に書き込む実装関数を呼び出すと、プロキシの所有者になります。

関数セレクターの衝突

4バイトの関数セレクターは衝突することがあります。プロキシの admin() のセレクターが実装の transfer() と衝突すると、プロキシで admin() を呼び出した際に transfer() のロジックが実行されます。

ツール:cast selectors <bytecode>(Foundry)を使うと、セレクターを列挙できます。


6. フロントランニング/MEV

トランザクション順序の操作
Victim submits DEX swap tx (visible in mempool)
├── Front-runner: buy token before victim (raise price)
├── Victim tx executes at worse price
└── Back-runner: sell token after victim (profit from spread)
= Sandwich attack
保護パターン
防御策仕組み
コミット・リビールリビールまでトランザクションの意図を隠します
Flashbots/プライベートメンプールブロックビルダーに tx を直接送信します
スリッページ保護minAmountOut を設定し、MEV による抽出を制限します
タイムロック実行を遅らせ、予測可能性を低減します

7. 署名のリプレイ

ノンスの欠落

有効な署名を再利用して、同じ操作(例:送金)を複数回実行します。

クロスチェーンリプレイ

同じアドレスで同じコントラクトが複数のチェーンにデプロイされていると、署名はすべてのチェーンで有効になります。署名メッセージに block.chainid を含める必要があります。

EIP-712 の実装エラー
エラー結果
chainId を含む DOMAIN_SEPARATOR がないクロスチェーンリプレイ
デプロイ時にドメインセパレーターをキャッシュするchainId が変わるハードフォーク後に機能しなくなります
構造体ハッシュにノンスがない署名のリプレイ
無効な署名に対して ecrecover が address(0) を返す== address(0) の所有者チェックを通過します

8. SELF-DESTRUCT と ETH の強制送金

selfdestruct(recipient) は、すべてのコントラクト ETH を recipient に強制送金します。receive() と fallback() を回避し、拒否できません。

ロジックで address(this).balance に依存するコントラクト(例:require(balance == expected))が破綻します。

EIP-6780(Dencun)以降、selfdestruct は ETH を送金するだけです。コード/ストレージが削除されるのは、作成と同じ tx 内で呼び出された場合に限られます。


9. CREATE2 と決定論的アドレスの悪用

CREATE2 のアドレス = keccak256(0xff ++ deployer ++ salt ++ keccak256(initCode))。

攻撃手法
事前入金の悪用アドレスを予測 → デプロイ前にトークン/ETH を送信 → selfdestruct → 同じアドレスに異なるコードを再デプロイ
事前承認の悪用予測したアドレスにトークンの承認を設定 → 悪意のあるコントラクトをデプロイ → 承認済みトークンを流出させる
メタモルフィックコントラクトCREATE2 → selfdestruct → 同じ salt で異なる initCode を使って CREATE2(EIP-6780 より前)

10. フラッシュローン攻撃パターン

Single transaction:
├── Borrow large amount (no collateral)
├── Manipulate state (price oracle, governance, etc.)
├── Extract profit from manipulated state
├── Repay loan + fee
└── Keep profit

要点:シーケンス全体がアトミックに成功する必要があります。そうでなければ、tx 全体が取り消されます。


11. ショートアドレス攻撃

EVM は ABI エンコードされた calldata の不足バイトをゼロで埋めます。19 バイトのアドレスで transfer(address, uint256) を呼び出すと、uint256 の amount が 8 ビット左にずれ、256 倍になります。

緩和策:calldata の長さを検証します。最新の Solidity コンパイラーではチェックが追加されています。


12. ツール

ツール目的使用方法
Slither静的解析、脆弱性の検出プロジェクトのルートで slither .
Mythrilシンボリック実行、パス探索myth analyze contract.sol
Echidnaプロパティベースのファジング不変条件を定義し、違反がないかファジング
Foundry (Forge)テストフレームワーク、ファジング、ガス分析forge test --fuzz-runs 10000
Hardhat開発、テスト、デプロイnpx hardhat test
Certora形式検証仕様を記述し、プロパティを証明または反証
4naly3erガス最適化と脆弱性レポートの自動生成CI との統合

13. 決定木

Auditing a smart contract?
├── Is it a proxy pattern?
│   ├── Yes → Check storage layout collision (Section 5)
│   │   ├── Compare slot assignments between proxy and implementation
│   │   ├── Check for function selector collision
│   │   └── Verify initializer cannot be called twice
│   └── No → Continue
├── Does it make external calls?
│   ├── Yes → Check reentrancy (Section 1)
│   │   ├── State updated before call? → CEI pattern OK
│   │   ├── ReentrancyGuard present? → Check all entry points
│   │   ├── Cross-function state sharing? → Cross-function reentrancy risk
│   │   └── View functions read during callback? → Read-only reentrancy
│   └── No → Continue
├── Does it handle tokens/ETH?
│   ├── Yes → Check integer overflow (Section 2)
│   │   ├── Solidity < 0.8? → All arithmetic suspect
│   │   ├── unchecked{} blocks? → Verify no user-influenced values
│   │   └── Casting between uint sizes? → Truncation risk
│   └── Also check self-destruct force-send (Section 8)
├── Does it use signatures?
│   ├── Yes → Check replay (Section 7)
│   │   ├── Nonce included? → Verify incremented
│   │   ├── ChainId included? → Cross-chain safe
│   │   └── ecrecover result checked for address(0)? → OK
│   └── No → Continue
├── Does it use on-chain randomness?
│   ├── Yes → Predictable (Section 4)
│   │   └── Recommend Chainlink VRF or commit-reveal with bond
│   └── No → Continue
├── Does it interact with DeFi protocols?
│   ├── Yes → Load [defi-attack-patterns](../defi-attack-patterns/SKILL.md)
│   │   ├── Flash loan vectors
│   │   ├── Oracle manipulation
│   │   └── MEV exposure
│   └── No → Continue
├── Does it use CREATE2?
│   ├── Yes → Check deterministic address exploitation (Section 9)
│   └── No → Continue
└── Run automated tools (Section 12)
    ├── Slither for static analysis
    ├── Mythril for symbolic execution
    └── Echidna for fuzzing invariants

コメント