# Solidityコンパイラの脆弱性解析と対策コンパイラーは現代のコンピュータシステムの基本的な構成要素の一つです。これは、人間が理解しやすく、記述しやすい高水準プログラミング言語のソースコードを、コンピュータの低レベルCPUやバイトコード仮想マシンが実行可能な命令コードに変換する機能を持つコンピュータプログラムです。ほとんどの開発者やセキュリティ専門家は、通常アプリケーションコードの安全性に関心を持っていますが、コンパイラ自体の安全性を見落とす可能性があります。実際、コンパイラもコンピュータプログラムとして安全な脆弱性を持つ可能性があり、コンパイラによって引き起こされる安全脆弱性は、場合によっては深刻な安全リスクをもたらすことがあります。例えば、ブラウザがJavascriptのフロントエンドコードをコンパイルし解析して実行する過程で、Javascript解析エンジンの脆弱性により、ユーザーが悪意のあるウェブページにアクセスした際に攻撃者がその脆弱性を利用してリモートコード実行を実現し、最終的には犠牲者のブラウザやオペレーティングシステムを制御することがあります。研究によれば、Clang C++コンパイラのバグもリモートコード実行などの深刻な結果を引き起こす可能性があります。Solidityコンパイラも例外ではなく、Solidity開発チームのセキュリティ警告によると、複数の異なるバージョンのSolidityコンパイラに安全上の脆弱性が存在します。## Solidityコンパイラの脆弱性Solidityコンパイラの役割は、開発者が記述したスマートコントラクトコードをEthereum仮想マシン(EVM)命令コードに変換することです。これらのEVM命令コードは、取引を通じてパッケージ化され、Ethereumにアップロードされ、最終的にEVMによって解析と実行が行われます。Solidityコンパイラの脆弱性とEVM自体の脆弱性を区別する必要があります。EVMの脆弱性は、仮想マシンが命令を実行する際に生じるセキュリティの脆弱性を指します。攻撃者が任意のコードをEthereumにアップロードできるため、これらのコードは最終的に各Ethereum P2Pクライアントプログラムで実行されます。EVMにセキュリティの脆弱性が存在すると、Ethereumネットワーク全体に影響を与え、ネットワーク全体がサービス拒否(DoS)に陥る可能性があり、最終的には攻撃者によってネットワーク全体が完全に制御される可能性もあります。しかし、EVM自体の設計は比較的シンプルであり、コアコードは頻繁に更新されないため、上記の問題が発生する確率は比較的低いです。Solidityコンパイラの脆弱性とは、コンパイラがSolidityをEVMコードに変換する際に存在する脆弱性を指します。ブラウザなどがユーザーのクライアントコンピュータ上でJavascriptをコンパイルして実行するシナリオとは異なり、Solidityのコンパイルプロセスはスマートコントラクト開発者のコンピュータ上でのみ行われ、イーサリアム上では実行されません。したがって、Solidityコンパイラの脆弱性はイーサリアムネットワーク自体に直接影響を及ぼすことはありません。Solidityコンパイラの脆弱性の主な危害は、生成されたEVMコードがスマートコントラクト開発者の期待と一致しない可能性があることです。イーサリアム上のスマートコントラクトは通常、ユーザーの暗号通貨資産を含むため、コンパイラが引き起こすスマートコントラクトにおけるいかなるバグもユーザー資産の損失を引き起こし、深刻な結果をもたらす可能性があります。開発者や契約監査者は、契約コードのロジック実装の問題や、再入可能性、整数オーバーフローなどのSolidityレベルのセキュリティ問題に重点を置く可能性があります。しかし、Solidityコンパイラの脆弱性については、契約ソースコードのロジックの監査だけでは発見が難しいです。特定のコンパイラバージョンと特定のコードパターンを組み合わせて分析する必要があり、それによってスマートコントラクトがコンパイラの脆弱性の影響を受けるかどうかが確定できます。! 【Solidityコンパイラの脆弱性解析と対策】(https://img-cdn.gateio.im/social/moments-7d1e882c0b106528437910218bf21f82)## Solidityコンパイラの脆弱性の例以下のいくつかの実際のSolidityコンパイラの脆弱性の事例を通じて、Solidityコンパイラの脆弱性の具体的な形、原因、及び危害を示します。### SOL-2016-9 ハイオーダーバイトクリーンストレージこの脆弱性は、初期のSolidityコンパイラバージョンに存在します(>=0.1.6 <0.4.4)。次のコードを考えてください:ソリディティコントラクトC { uint32 a = 0x12345678; uint16 b = 0x1234; 関数 f() public { a = a + 1; } パブリック ビュー run()関数は (uint16) { を返します。 bを返す; }}その中で、storage変数bは何の変更も受けていないため、run()関数はデフォルト値0を返すべきです。しかし、実際には脆弱性のあるコンパイラバージョンで生成されたコードでは、run()は1を返します。そのコンパイラの脆弱性を理解していない場合、通常の開発者は単純なコードレビューによって上記のコードに存在するバグを見つけるのが難しいです。上記のコードは単純な例に過ぎないため、特に深刻な危害を引き起こすことはありません。しかし、b変数が権限検証や資産の記録などに使用される場合、予期しない不一致は非常に深刻な結果を招く可能性があります。上記の異常現象の原因は、EVMがスタック型バーチャルマシンを使用しているためで、スタックの各要素は32バイトの大きさ(、すなわちuint256変数の大きさ)です。一方、基盤ストレージstorageの各スロットも32バイトの大きさです。しかし、Solidity言語のレベルではuint32など、32バイト未満のデータ型をサポートしており、コンパイラはこの種の変数を処理する際に、その上位ビットを適切にクリアする操作(clean up)を行う必要があります。上述の状況では、加算によって整数オーバーフローが発生した場合、コンパイラは結果の上位ビットを正しくclean upせず、オーバーフロー後の上位の1ビットがstorageに書き込まれ、最終的にa変数の後のb変数を上書きし、b変数の値が1に変更されてしまいました。### SOL-2022-4 インラインアセンブリメモリ副作用この脆弱性は>=0.8.13 <0.8.15バージョンのコンパイラに存在します。Solidityコンパイラは、Solidity言語をEVMコードに変換する過程で、単なる翻訳ではありません。制御フローやデータ分析を深く行い、さまざまなコンパイル最適化プロセスを実現し、生成されるコードのサイズを縮小し、実行プロセス中のガス消費を最適化します。この種の最適化操作はさまざまな高級言語のコンパイラで一般的ですが、考慮すべき状況が非常に複雑であるため、バグやセキュリティ脆弱性が発生しやすいです。次のコードを考慮してください:ソリディティコントラクトC { function f() public pure 戻り値 (uint256) { アセンブリ { mstore(0, 0x42) } uint256 x; アセンブリ { x := mload(0) } xを返す; }}上記のコードの脆弱性は、コンパイル最適化操作に起因しています。特定の状況下では、関数内にメモリの0オフセットにあるデータを変更するコードが存在しても、その後そのデータが使用されない場合、メモリの0を変更するコードは直接削除され、ガスを節約でき、後続のプログラムロジックには影響を与えません。この最適化戦略自体には問題はありませんが、具体的なSolidityコンパイラコードの実装において、この種の最適化は単一のassemblyブロック内にのみ適用されます。上記の例のコードでは、メモリ0への書き込みとアクセスが2つの異なるassemblyブロックに存在しており、コンパイラは単独のassemblyブロックに対してのみ分析最適化を行いました。最初のassemblyブロックでメモリ0に書き込んだ後に読み取り操作がないため、その書き込み命令は冗長であると判断され、その命令は削除され、バグが発生します。脆弱性のあるバージョンでは、f(関数は値0を返しますが、実際には上記のコードは正しい値0x42を返すべきです。) SOL-2022-6 AbiReencodingHeadOverflowWithStaticArrayCleanupこの脆弱性は、バージョン >= 0.5.8 および < 0.8.16 のコンパイラに影響します。次のコードを考えてください:ソリディティコントラクトC { 関数 f###bytes calldata data( external pure は )bytes memory( { を返します。 bytes4)メモリ a = [bytes4[1]data(]; abi.encode)a(を返します。 }}通常、上記のコードはa変数が"aaaa"を返すべきです。しかし、脆弱性のあるバージョンでは空の文字列""が返されます。この脆弱性の原因は、Solidityがcalldataタイプの配列に対してabi.encode操作を行う際に、誤っていくつかのデータをクリーンアップし、隣接する他のデータを変更したため、エンコードおよびデコード後のデータが不一致になったことです。注意すべきは、Solidityがexternal callやemit eventを行う際に、パラメータをabi.encodeで暗黙的にエンコードするため、上記の脆弱性コードが発生する確率は直感的に感じるよりも高いということです。この脆弱性は、著名なセキュリティコンペティション0ctf 2022のブロックチェーンの問題として改編され、実際の開発シーンにおけるコンパイラの脆弱性がスマートコントラクトに与える影響を示しました。! 【Solidityコンパイラの脆弱性解析と対策】)https://img-cdn.gateio.im/social/moments-c97428f89ed62d5ad8551cdb2ba30867(## セキュリティの推奨事項Solidityコンパイラの脆弱性に対する脅威と対策について、以下の提案を示すことができます:開発者向け:- より新しいバージョンのSolidityコンパイラを使用してください。新しいバージョンは新しいセキュリティ問題を引き起こす可能性がありますが、既知のセキュリティ問題は通常、古いバージョンよりも少なくなります。- ユニットテストケースを充実させる。ほとんどのコンパイラレベルのバグは、コードの実行結果が予想と一致しない原因となる。このような問題はコードレビューでは発見しにくいが、テスト段階で容易に露見する。そのため、コードカバレッジを向上させることで、このような問題を最大限に回避することができる。- インラインアセンブリ、マルチディメンショナル配列や複雑な構造体のABIエンコード/デコードなどの複雑な操作の使用をできるだけ避け、明確な要求がない場合は言語の新機能や実験的機能を盲目的に使用しないようにしてください。ほとんどの脆弱性はインラインアセンブリやABIエンコーダーなどの操作に関連しています。コンパイラーは複雑な言語機能を処理する際にバグが発生しやすくなります。一方で、開発者が新機能を使用する際にも誤解が生じやすく、安全上の問題を引き起こす可能性があります。セキュリティ担当者向け:- Solidityコードのセキュリティ監査を行う際、Solidityコンパイラが引き起こす可能性のあるセキュリティリスクを無視しないでください。Smart Contract Weakness Classification)SWC(に対応するチェック項目はSWC-102: 古いコンパイラバージョンです。- 内部セキュリティ開発プロセスでは、開発チームにSolidityコンパイラのバージョンをアップグレードするよう促し、CI/CDプロセスにコンパイラバージョンの自動チェックを導入することを検討してください。- しかし、コンパイラの脆弱性について過度に心配する必要はありません。ほとんどのコンパイラの脆弱性は特定のコードパターンでのみ発生します。脆弱性のあるバージョンのコンパイラでコンパイルされた契約が必ずしも安全リスクを伴うわけではなく、具体的なプロジェクトの状況に基づいて実際の安全影響を評価する必要があります。いくつかの実用的なリソース:- Solidityチームが定期的に発表するセキュリティ警告: - Solidity公式リポジトリで定期的に更新されるバグリスト: - 各バージョンのコンパイラバグリスト: Codeページの右上隅にある三角形の感嘆符マークは、現在のバージョンのコンパイラに存在するセキュリティホールを示しています。## まとめこの記事では、Solidityコンパイラの脆弱性の概念を紹介し、それがEthereum開発環境で引き起こす可能性のあるセキュリティリスクを分析し、開発者やセキュリティ担当者に実際のセキュリティアドバイスを提供しています。コンパイラの脆弱性は一般的ではありませんが、その影響は非常に深刻な場合があり、開発者やセキュリティ担当者が重視する価値があります。! 【Solidityコンパイラの脆弱性解析と対策】)https://img-cdn.gateio.im/social/moments-84f5083d8748f2aab71fd92671d999a7(
Solidity Compiler 脆弱性解析: 影響・事例・対策
Solidityコンパイラの脆弱性解析と対策
コンパイラーは現代のコンピュータシステムの基本的な構成要素の一つです。これは、人間が理解しやすく、記述しやすい高水準プログラミング言語のソースコードを、コンピュータの低レベルCPUやバイトコード仮想マシンが実行可能な命令コードに変換する機能を持つコンピュータプログラムです。
ほとんどの開発者やセキュリティ専門家は、通常アプリケーションコードの安全性に関心を持っていますが、コンパイラ自体の安全性を見落とす可能性があります。実際、コンパイラもコンピュータプログラムとして安全な脆弱性を持つ可能性があり、コンパイラによって引き起こされる安全脆弱性は、場合によっては深刻な安全リスクをもたらすことがあります。例えば、ブラウザがJavascriptのフロントエンドコードをコンパイルし解析して実行する過程で、Javascript解析エンジンの脆弱性により、ユーザーが悪意のあるウェブページにアクセスした際に攻撃者がその脆弱性を利用してリモートコード実行を実現し、最終的には犠牲者のブラウザやオペレーティングシステムを制御することがあります。研究によれば、Clang C++コンパイラのバグもリモートコード実行などの深刻な結果を引き起こす可能性があります。
Solidityコンパイラも例外ではなく、Solidity開発チームのセキュリティ警告によると、複数の異なるバージョンのSolidityコンパイラに安全上の脆弱性が存在します。
Solidityコンパイラの脆弱性
Solidityコンパイラの役割は、開発者が記述したスマートコントラクトコードをEthereum仮想マシン(EVM)命令コードに変換することです。これらのEVM命令コードは、取引を通じてパッケージ化され、Ethereumにアップロードされ、最終的にEVMによって解析と実行が行われます。
Solidityコンパイラの脆弱性とEVM自体の脆弱性を区別する必要があります。EVMの脆弱性は、仮想マシンが命令を実行する際に生じるセキュリティの脆弱性を指します。攻撃者が任意のコードをEthereumにアップロードできるため、これらのコードは最終的に各Ethereum P2Pクライアントプログラムで実行されます。EVMにセキュリティの脆弱性が存在すると、Ethereumネットワーク全体に影響を与え、ネットワーク全体がサービス拒否(DoS)に陥る可能性があり、最終的には攻撃者によってネットワーク全体が完全に制御される可能性もあります。しかし、EVM自体の設計は比較的シンプルであり、コアコードは頻繁に更新されないため、上記の問題が発生する確率は比較的低いです。
Solidityコンパイラの脆弱性とは、コンパイラがSolidityをEVMコードに変換する際に存在する脆弱性を指します。ブラウザなどがユーザーのクライアントコンピュータ上でJavascriptをコンパイルして実行するシナリオとは異なり、Solidityのコンパイルプロセスはスマートコントラクト開発者のコンピュータ上でのみ行われ、イーサリアム上では実行されません。したがって、Solidityコンパイラの脆弱性はイーサリアムネットワーク自体に直接影響を及ぼすことはありません。
Solidityコンパイラの脆弱性の主な危害は、生成されたEVMコードがスマートコントラクト開発者の期待と一致しない可能性があることです。イーサリアム上のスマートコントラクトは通常、ユーザーの暗号通貨資産を含むため、コンパイラが引き起こすスマートコントラクトにおけるいかなるバグもユーザー資産の損失を引き起こし、深刻な結果をもたらす可能性があります。
開発者や契約監査者は、契約コードのロジック実装の問題や、再入可能性、整数オーバーフローなどのSolidityレベルのセキュリティ問題に重点を置く可能性があります。しかし、Solidityコンパイラの脆弱性については、契約ソースコードのロジックの監査だけでは発見が難しいです。特定のコンパイラバージョンと特定のコードパターンを組み合わせて分析する必要があり、それによってスマートコントラクトがコンパイラの脆弱性の影響を受けるかどうかが確定できます。
! 【Solidityコンパイラの脆弱性解析と対策】(https://img-cdn.gateio.im/webp-social/moments-7d1e882c0b106528437910218bf21f82.webp)
Solidityコンパイラの脆弱性の例
以下のいくつかの実際のSolidityコンパイラの脆弱性の事例を通じて、Solidityコンパイラの脆弱性の具体的な形、原因、及び危害を示します。
SOL-2016-9 ハイオーダーバイトクリーンストレージ
この脆弱性は、初期のSolidityコンパイラバージョンに存在します(>=0.1.6 <0.4.4)。
次のコードを考えてください:
ソリディティ コントラクトC { uint32 a = 0x12345678; uint16 b = 0x1234;
関数 f() public { a = a + 1; }
パブリック ビュー run()関数は (uint16) { を返します。 bを返す; } }
その中で、storage変数bは何の変更も受けていないため、run()関数はデフォルト値0を返すべきです。しかし、実際には脆弱性のあるコンパイラバージョンで生成されたコードでは、run()は1を返します。
そのコンパイラの脆弱性を理解していない場合、通常の開発者は単純なコードレビューによって上記のコードに存在するバグを見つけるのが難しいです。上記のコードは単純な例に過ぎないため、特に深刻な危害を引き起こすことはありません。しかし、b変数が権限検証や資産の記録などに使用される場合、予期しない不一致は非常に深刻な結果を招く可能性があります。
上記の異常現象の原因は、EVMがスタック型バーチャルマシンを使用しているためで、スタックの各要素は32バイトの大きさ(、すなわちuint256変数の大きさ)です。一方、基盤ストレージstorageの各スロットも32バイトの大きさです。しかし、Solidity言語のレベルではuint32など、32バイト未満のデータ型をサポートしており、コンパイラはこの種の変数を処理する際に、その上位ビットを適切にクリアする操作(clean up)を行う必要があります。上述の状況では、加算によって整数オーバーフローが発生した場合、コンパイラは結果の上位ビットを正しくclean upせず、オーバーフロー後の上位の1ビットがstorageに書き込まれ、最終的にa変数の後のb変数を上書きし、b変数の値が1に変更されてしまいました。
SOL-2022-4 インラインアセンブリメモリ副作用
この脆弱性は>=0.8.13 <0.8.15バージョンのコンパイラに存在します。Solidityコンパイラは、Solidity言語をEVMコードに変換する過程で、単なる翻訳ではありません。制御フローやデータ分析を深く行い、さまざまなコンパイル最適化プロセスを実現し、生成されるコードのサイズを縮小し、実行プロセス中のガス消費を最適化します。この種の最適化操作はさまざまな高級言語のコンパイラで一般的ですが、考慮すべき状況が非常に複雑であるため、バグやセキュリティ脆弱性が発生しやすいです。
次のコードを考慮してください:
ソリディティ コントラクトC { function f() public pure 戻り値 (uint256) { アセンブリ { mstore(0, 0x42) } uint256 x; アセンブリ { x := mload(0) } xを返す; } }
上記のコードの脆弱性は、コンパイル最適化操作に起因しています。特定の状況下では、関数内にメモリの0オフセットにあるデータを変更するコードが存在しても、その後そのデータが使用されない場合、メモリの0を変更するコードは直接削除され、ガスを節約でき、後続のプログラムロジックには影響を与えません。
この最適化戦略自体には問題はありませんが、具体的なSolidityコンパイラコードの実装において、この種の最適化は単一のassemblyブロック内にのみ適用されます。上記の例のコードでは、メモリ0への書き込みとアクセスが2つの異なるassemblyブロックに存在しており、コンパイラは単独のassemblyブロックに対してのみ分析最適化を行いました。最初のassemblyブロックでメモリ0に書き込んだ後に読み取り操作がないため、その書き込み命令は冗長であると判断され、その命令は削除され、バグが発生します。脆弱性のあるバージョンでは、f(関数は値0を返しますが、実際には上記のコードは正しい値0x42を返すべきです。
) SOL-2022-6 AbiReencodingHeadOverflowWithStaticArrayCleanup
この脆弱性は、バージョン >= 0.5.8 および < 0.8.16 のコンパイラに影響します。次のコードを考えてください:
ソリディティ コントラクトC { 関数 f###bytes calldata data( external pure は )bytes memory( { を返します。 bytes4)メモリ a = [bytes4[1]data(]; abi.encode)a(を返します。 } }
通常、上記のコードはa変数が"aaaa"を返すべきです。しかし、脆弱性のあるバージョンでは空の文字列""が返されます。
この脆弱性の原因は、Solidityがcalldataタイプの配列に対してabi.encode操作を行う際に、誤っていくつかのデータをクリーンアップし、隣接する他のデータを変更したため、エンコードおよびデコード後のデータが不一致になったことです。
注意すべきは、Solidityがexternal callやemit eventを行う際に、パラメータをabi.encodeで暗黙的にエンコードするため、上記の脆弱性コードが発生する確率は直感的に感じるよりも高いということです。
この脆弱性は、著名なセキュリティコンペティション0ctf 2022のブロックチェーンの問題として改編され、実際の開発シーンにおけるコンパイラの脆弱性がスマートコントラクトに与える影響を示しました。
! 【Solidityコンパイラの脆弱性解析と対策】)https://img-cdn.gateio.im/webp-social/moments-c97428f89ed62d5ad8551cdb2ba30867.webp(
セキュリティの推奨事項
Solidityコンパイラの脆弱性に対する脅威と対策について、以下の提案を示すことができます:
開発者向け:
より新しいバージョンのSolidityコンパイラを使用してください。新しいバージョンは新しいセキュリティ問題を引き起こす可能性がありますが、既知のセキュリティ問題は通常、古いバージョンよりも少なくなります。
ユニットテストケースを充実させる。ほとんどのコンパイラレベルのバグは、コードの実行結果が予想と一致しない原因となる。このような問題はコードレビューでは発見しにくいが、テスト段階で容易に露見する。そのため、コードカバレッジを向上させることで、このような問題を最大限に回避することができる。
インラインアセンブリ、マルチディメンショナル配列や複雑な構造体のABIエンコード/デコードなどの複雑な操作の使用をできるだけ避け、明確な要求がない場合は言語の新機能や実験的機能を盲目的に使用しないようにしてください。ほとんどの脆弱性はインラインアセンブリやABIエンコーダーなどの操作に関連しています。コンパイラーは複雑な言語機能を処理する際にバグが発生しやすくなります。一方で、開発者が新機能を使用する際にも誤解が生じやすく、安全上の問題を引き起こす可能性があります。
セキュリティ担当者向け:
Solidityコードのセキュリティ監査を行う際、Solidityコンパイラが引き起こす可能性のあるセキュリティリスクを無視しないでください。Smart Contract Weakness Classification)SWC(に対応するチェック項目はSWC-102: 古いコンパイラバージョンです。
内部セキュリティ開発プロセスでは、開発チームにSolidityコンパイラのバージョンをアップグレードするよう促し、CI/CDプロセスにコンパイラバージョンの自動チェックを導入することを検討してください。
しかし、コンパイラの脆弱性について過度に心配する必要はありません。ほとんどのコンパイラの脆弱性は特定のコードパターンでのみ発生します。脆弱性のあるバージョンのコンパイラでコンパイルされた契約が必ずしも安全リスクを伴うわけではなく、具体的なプロジェクトの状況に基づいて実際の安全影響を評価する必要があります。
いくつかの実用的なリソース:
Solidityチームが定期的に発表するセキュリティ警告:
Solidity公式リポジトリで定期的に更新されるバグリスト:
各バージョンのコンパイラバグリスト:
Codeページの右上隅にある三角形の感嘆符マークは、現在のバージョンのコンパイラに存在するセキュリティホールを示しています。
まとめ
この記事では、Solidityコンパイラの脆弱性の概念を紹介し、それがEthereum開発環境で引き起こす可能性のあるセキュリティリスクを分析し、開発者やセキュリティ担当者に実際のセキュリティアドバイスを提供しています。コンパイラの脆弱性は一般的ではありませんが、その影響は非常に深刻な場合があり、開発者やセキュリティ担当者が重視する価値があります。
! 【Solidityコンパイラの脆弱性解析と対策】)https://img-cdn.gateio.im/webp-social/moments-84f5083d8748f2aab71fd92671d999a7.webp(