blockchain-security について
blockchain-security は、ブロックチェーン CTF のコントラクトを分析・攻略するためのスキルです。コントラクトの調査、ストレージとアクセス制御の分析、一般的な攻撃手法、勝利条件の確認を扱います。
主な機能
- 01コントラクトの逆コンパイルとストレージ解析
- 02特権操作とアクセス制御の確認
- 03delegatecall と CREATE アドレス攻撃
- 04リエントランシーと署名の脆弱性確認
- 05攻撃コントラクトのデプロイと勝利条件の検証
活用シーン
- 01ソースまたはバイトコードから CTF コントラクトを分析
- 02ストレージ配置や delegatecall の攻撃を検証
- 03署名、入力検証、アクセス制御の欠陥を確認
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ transilienceai/ communitytools --skill blockchain-securityインストール後、Claude Code で/blockchain-securityを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
reference/create-address-prediction.mddelegatecall-attacks.mdstorage-layout.md詳細
ブロックチェーンセキュリティ
クイックスタート
- コントラクト(ソースコードまたはバイトコード)をダウンロードして逆コンパイルします
- ストレージレイアウトをマッピングし、特権操作を特定します
- delegatecall、CREATE アドレス予測、リエントランシー、アクセス制御を確認します
- web3.py または cast/forge を使ってエクスプロイトコントラクトをデプロイします
- 勝利条件(isSolved/flag endpoint)を確認します
ブロックチェーン CTF のチャレンジパターン
# Get connection info
curl http://$HOST:$PORT/connection_info # -> PrivateKey, Address, TargetAddress, setupAddress
# RPC endpoint
RPC_URL="http://$HOST:$PORT/rpc"
# Win condition: Setup.isSolved() must return true
主な攻撃ベクトル
1. Delegatecall によるストレージ操作
コントラクト A がコントラクト B に delegatecall すると、B のコードは A のストレージを使って実行されます。
- A のストレージレイアウトを模倣したエクスプロイトコントラクトをデプロイします
- エクスプロイトコントラクトは delegatecall を通じて A のストレージスロットに書き込みます
- 重要:ストレージレイアウトは完全に一致している必要があります(同じスロット順序)
- reference/delegatecall-attacks.md を参照してください
2. CREATE アドレス予測(Nonce 操作)
CREATE によるコントラクトアドレスは決定論的です:keccak256(rlp([sender, nonce]))[12:]
- どの nonce が目標アドレスを生成するかを見つけるため、総当たりします
- ダミートランザクション(自身への送金)を送信して nonce を増やします
- 目標アドレスになる正確な nonce でエクスプロイトコントラクトをデプロイします
- reference/create-address-prediction.md を参照してください
3. ストレージレイアウトとスロット計算
- マッピング:
keccak256(h(key) || uint256(slot_number))- 値型:
h(k) = abi.encode(k)(32 バイトになるよう左側をパディングします) - String/bytes:
h(k) = keccak256(k)
- 値型:
eth_getStorageAtを使ってプライベート変数を読み取ります- reference/storage-layout.md を参照してください
4. 空配列/長さゼロの入力によるバイパス
関数がユーザー指定の配列をループして項目(署名、承認、投票)を検証する場合、空配列を渡すとループ全体がスキップされます。最小長チェックがなければ、検証をバイパスできます。
- 確認箇所:
require(arr.length >= N)がないfor (uint i = 0; i < arr.length; i++) - エクスプロイト:関数に
[]を渡して、すべての検証をスキップします
5. ECDSA 署名の可鍛性
生の ecrecover は (v, r, s) と (v', r, N-s)(N = secp256k1 の位数、v は 27↔28 に反転)の両方を受け入れます。コントラクトが生のバイト列のハッシュで署名を重複排除している場合、可鍛な形式は異なるハッシュを持ちながら、同じ署名者に復元されます。
- 確認箇所:
s <= N/2の適用なしでecrecoverが使用されている(OpenZeppelin の ECDSA.sol ではこれが適用されています) - エクスプロイト:既知の有効な署名を使い、
new_s = N - sを計算してvを反転し、「新しい」署名として送信します
6. よくある脆弱性の種類
| 脆弱性 | 確認事項 |
|---|---|
| リエントランシー | 状態更新前の外部呼び出し |
| アクセス制御 | onlyOwner / msg.sender チェックの欠如 |
| 整数オーバーフロー | SafeMath を使用していない Solidity < 0.8.0 |
| Delegatecall インジェクション | ユーザーが制御する delegatecall の宛先 |
| tx.origin による認証 | msg.sender ではなく tx.origin を使用 |
| Selfdestruct | ETH の強制送金、コントラクト nonce のリセット |
| 弱い乱数 | エントロピー源としての blockhash/timestamp |
| 空配列によるバイパス | 最小長チェックのないループ検証 |
| 署名の可鍛性 | s の正規化を行わない生の ecrecover |
ツール
# web3.py essentials
from web3 import Web3
w3 = Web3(Web3.HTTPProvider(RPC_URL))
acct = w3.eth.account.from_key(PRIVATE_KEY)
# Read private storage
w3.eth.get_storage_at(contract_addr, slot)
# Deploy contract
from solcx import compile_source, install_solc
install_solc("0.8.13")
compiled = compile_source(source, output_values=["abi", "bin"], solc_version="0.8.13")
# Send raw bytecode deployment
tx = {'data': bytecode, 'gas': 3000000, 'gasPrice': w3.eth.gas_price, 'nonce': nonce, 'chainId': chain_id}
signed = acct.sign_transaction(tx)
w3.eth.send_raw_transaction(signed.raw_transaction)
参考資料
重要なルール
- 攻撃の前に必ずストレージを読み取ります(プライベート変数はオンチェーンで読み取り可能です)
- delegatecall を悪用する際は、ストレージレイアウトを正確に模倣します
- CREATE nonce の総当たりでは、nonce 0~100000 以上を体系的に確認します
- CTF のインスタンスは短時間で消失することが多いため、速度を上げるために攻撃全体をスクリプト化します
コメント
Markdown 対応