
静的解析の活用で汚染データから組込みアプリケーションを保護
組込みシステムに対する悪意ある攻撃の手口はますます巧妙化し、頻度を増しています。攻撃の対象にされる脆弱性は、敵対的ユーザーがシステムにアクセスするために悪用され、システムの利用を妨害します。この悪用は通常、敵対的ユーザー が入力チャネルを介してデータを送信したときにトリガーされます。
プログラマーは、入力データを潜在的に危険なもの(汚染されたもの)として扱い、使用前にデータの妥当性を注意深くチェックすることで、脆弱性となるこれらの弱点や欠陥から身を守ることができます。しかし、プログラム内のデータフロー を手作業でトレースする必要があるため、このような場所を見つけるのはは容易ではありませんです 。このコラムでは、開発者がこれらの危険な脆弱性をより効果的に特定・排除できるようにするため、潜在的に危険な入力がプログラム内をどのように「流れ」「コードのセンシティブな部分に到達するか」を見つけるのに使用できる静的解析の「テイント解析」手法について説明します。
1. 背景
組込みアプリケーションの多機能化とともに、セキュリティ脆弱性のリスクも増大しています。例えば、自動車は攻撃者にとって格好の標的 とされており、その中でも自動車の電子システムは特に危険にさらされている ことが証明されています。昨今、研究者たちは、最新モデル の自動車では比較的容易にソフトウェアのセキュリティ脆弱性を見つけられると論じており、その脆弱性を悪用した遠隔操作によるドアロック解除やエンジン始動が可能なことを実証してみせました。
最近まで、物理的なアクセスを必要とする組込みシステムは、ハッカーの標的にされることはあまりありませんでした。しかし、組込みデバイスのネットワーク接続が加速するにつれ、悪意あるハッカーから新たな仮想攻撃経路として狙われるようになりました。これは、デバイスはより多くのネットワークと繋がるようになったにもかかわらず、組込み機器開発者の間では、コードの安全性やそれに付随するリスクに対する認識が依然として低いままだったためです。
セキュアプログラミングの用語では、チェックされていない入力値は汚染されている (tainted)と言われます。汚染されたデータ値は、デバイスの予期せぬ動作やシステムクラッシュを含む品質の問題をも引き起こすため、セキュリティがそれほど重要でない場合でも、汚染されたデータの脆弱性は開発者にとって常に懸念すべきものです。あらゆるタイプのセンサーから入力を読み取るソフトウェアは、センサーから送られた全ての値を潜在的に危険なものとして扱うべきです。例えば、ハードウェアの故障で範囲外の値 が渡される可能性があります。もしプログラムがその値をチェックする準備ができていなければ、後にソフトウェアのクラッシュを引き起こす原因となりえます。セキュリティの脆弱性に対処するための技術は、不正なデータ値に対しても有効です。このため、入力値を汚染されているとみなして脆弱性の検知につなげようとするテイント解析は、コードの最もリスクの高い部分を特定し、その品質を向上させるうえでも効果的な手法です。
複数のベンダーや、オープンソース、信頼できる第三者から提供された異なるソースから提供されたコードで構成されたシステムは、特にリスクが高いとされています。なぜならセキュリティの脆弱性は、コードコンポーネント間の境界において多く発生することが研究によって証明されており、その主な原因は、インターフェース仕様の解釈の違いといった無意識の食い違いに起因するケースが多いためです。
図1 汚染されたデータとは
プログラマーは、データの妥当性がチェックされるまでは、潜在的に危険なチャネルからの入力を危険なものとして扱うことで、そのような欠陥から身を守ることができます。しかし、汚染されたデータの流れをコードの構造を通して追跡する必要があるため、プログラムが汚染されたデータを適切に処理しているかどうかをプログラマー自身が全てチェックするのは困難です。これは、比較的小さなプログラムであっても面倒なことであり、現実世界 のほとんどのアプリケーションにおいて、手作業で行うことは不可能と言えます。
2. 汚染されたデータを利用したプログラミングエラーの悪用
未検証のチャネルから読み取った値を使用する最大のリスクは、攻撃者がそのチャネルを利用してセキュリティの脆弱性を発生させたり、プログラムをクラッシュさせたりすることができてしまうことです。汚染されたデータによって引き起こされる問題には、バッファオーバーラン、SQLインジェクション、コマンドインジェクション、クロスサイトスクリプティング、算術オーバーフロー、パス・トラバーサルなど、さまざまな種類の問題があります(これらの問題や他の欠陥のクラスに関する詳細については、Common Weakness Enumeration(http://cwe.mitre.org/ )をご参照ください)。過去20年間に発生した最も深刻なサイバー攻撃の多くは、バッファオーバーランによって引き起こされてきました。この脆弱性は非常に広範に存在し、テイント分析の重要性を示しているため、ここで少し詳しく掘り下げてみましょう。
バッファオーバーランを攻撃者が悪用する方法はいくつかありますが、ここでは攻撃者がプロセスを乗っ取り、任意のコードを実行させる可能性を持つ古典的なケースについて説明します。この例では、バッファがスタック上にあります。次のコードを考えてみましょう:
void config(void) { char buf(100); int count; ... strcpy(buf, getenv("CONFIG")); ... }
この例では、外部からの入力は、環境変数「CONFIG」の値を取得するgetenv関数を通じて行われます。
このコードを書いたプログラマーは、環境変数の値がバッファに収まることを予想していましたが、それを確認する処理は何もありません。
攻撃者がその環境変数の値を制御できる状況下で、その長さが100を超える値を割り当てると、バッファオーバーランが発生します。bufは自動変数であり、プロシージャ のアクティベーションレコードの一部としてスタックに配置されるため、最初の100文字以降の文字はbufの境界を超えてプログラムスタックの他の部分に書き込まれます。countという変数が上書きされる可能性もあります。(コンパイラがスタック上でスペースをどのように割り当てたかによって異なります。)もしそうなった場合、その変数の値は攻撃者の制御下に置かれます。
これだけでも十分に厄介なこと ですが、攻撃者の真の狙い は、プログラムがプロシージャ を実行し終わった後にジャンプするアドレスが含まれているスタックを手に入れることです。攻撃者は任意のリターンアドレスを埋め込んだ特別な文字列を作成し、それを変数に設定することで、 この脆弱性を悪用することができます。CPUが関数の終了部分に到達すると、関数の呼び出し元のアドレスではなく、そのアドレスに戻ります。 もし、攻撃者が環境変数の値を制御できない環境でコードが実行される場合であれば、この脆弱性を悪用するのは不可能かもしれません。それでも、コードのリスクが非常に高いのは明らかで、修正されずに放置されると問題になります。また、プログラマーは別のプログラムでこのコードを再利用しようとするかもしれませんが、その場合、安全に実行できない可能性があります。
図2 欠陥の3つの主なカテゴリー
この例では入力を環境から取得していますが、コードは他の入力元、例えばファイルシステムやネットワークチャネルから文字列を読み取っている場合でも同様にリスクがあります。最もリスクが高いのは、攻撃者が制御可能な入力チャネルです。
前述の通り、汚染された値に影響を受ける プログラムエラーを手動で見つけるのは非常に時間がかかるため、最良のアプローチは「自動化」です。
3. テイント分析の自動化
テイント分析 は静的解析の一形態です。これをどのように行うかを説明する前に、テイント分析 を実行できる静的解析ツールのクラスについて簡単に紹介します。
大まかに言うと、高度な静的解析ツールは次のように動作します。まず、プログラム全体のモデルを作成しなければなりません。これは、各入力ファイルを読み込み解析することによって行います。このモデルは、各コンパイル単位の抽象構文木、各サブプログラムの制御フローグラフ、シンボルテーブル、コールグラフ などの表現で構成されます。欠陥を見つけるチェック機能は、これらの表現に対するさまざまな種類のクエリとして実装されます。表面的なバグは、抽象構文木やシンボルテーブルでパターンマッチングを行うことによって見つけることができます。
実際に深刻なバグ – プログラムが失敗する原因となるもの、例えばヌルポインタ参照やバッファオーバーランなど – は、高度なクエリ を用いて見つける必要があります。これらのクエリは抽象的なシミュレーションと考えることができます。アナライザーはプログラムの実行をシミュレートしますが、具体的な値を使用する代わりに、プログラムの抽象的な状態をモデル化する方程式を使用します。もし異常が検出されると、警告が生成されます。 静的解析ツールは、異常な状況でのみ発生する欠陥を見つけるのが得意で、開発プロセスの非常に早い段階でそれを行えるため、有用です。コードがテストの準備が整う前でも価値を提供することができます。これらは従来のテスト手法を置き換えることを目的としていませんが、補完的なものです。
図3 バッファオーバーラン警告の例
図3は、静的解析ツールCodeSonarからのバッファオーバーラン警告レポートの一例です。このレポートは、バグを引き起こすために辿るべきコードのパスを示しています。その途中の重要なポイントがハイライトされており、オーバーランが発生する地点で何が問題になる可能性があるかが説明されています。
プログラム内で汚染されたデータの流れを追跡するのは難しい場合があります。なぜなら、それは変数から変数へと値がコピーされ、場合によってはプロシージャの境界を越え、複数のの間接的なレイヤーを追跡する必要があるためです。例えば、リスクのあるネットワークポートから文字列を読み取るプログラムを考えてみましょう。C言語では文字列は通常ポインタを通じて管理されるため、解析 は文字列の内容と、その文字列を指す可能性のあるポインタの値の両方を追跡しなければなりません。文字列自体は「汚染されている」と言われ、ポインタは「汚染を指し示している」と言われます。例えば、strcpy()を使用して文字列の内容をコピーする場合、その汚染状態は新しい文字列に転送されます。ポインタがコピーされる場合、ポインタの指す汚染状態も新しいポインタに転送されなければなりません。
もちろん、そのポインタを指すポインタも存在するかもしれませんし、さらにそのポインタを指すポインタも存在するかもしれません。そして、 解析はそれらも追跡しなければなりません。最終的には、この問題は「エイリアス解析」という一種の解析に帰着します。エイリアス解析は、どの変数が同じメモリロケーション をアクセスしているかを特定できる解析です。 エイリアス解析の説明については、下のリンクから良い入門記事を見つけることができます:https://ja.wikipedia.org/wiki/エイリアス解析
4. テイントフローを理解する
テイントは予期しない方法でプログラムを通じて流れることがありますが、自動化ツールはプログラマーがこれらの経路 を理解する手助けをする重要な役割を果たします。CodeSonarでは、テイントのソースとシンク の位置を可視化し、フローに関与するプログラムの要素を通常のコードビューの上に重ねて表示することができます。これにより、開発者は自分のコードのリスクを理解し、その脆弱性を排除するためにコードをどのように変更するべきかを判断する手助けになります。
図4 バッファオーバーランの警告。
下線部はトラントの効果を示す。
この図4は、別のバッファオーバーラン脆弱性のレポートを示しています。
この例では、まず80行目の青い下線に注目してください。これは、プロシージャ に渡された引数で指される変数の値がファイルシステムによって汚染されていることを示しています。この事実はユーザーがコードを理解するのに役立つかもしれませんが、この警告の最も興味深い部分は91行目と92行目にあります。91行目の下線は、compute_pkgdatadir()が返す値が環境によって 汚染されたデータを指すポインタであることを示しています。その後、strcpy()がそのデータをローカルバッファであるfull_file_name(84行目で宣言)にコピーします。これにより、汚染状態がそのバッファに転送されます。したがって、92行目で赤い下線が示すように、そのバッファは環境からの値によって汚染されることになります。
バッファオーバーランに関する説明としては、compute_pkgdatadir() が実際にはgetenv() 呼び出しから取得した値であることが確認できます 。これにより、攻撃者が環境変数の値を制御できる場合、セキュリティ脆弱性のリスクがあることをがわかります。
図5 汚染されたデータからの保護
CodeSonarでは、プログラム内でテイント の流れを見る別の方法として、トップダウンビュー があります。図5にその例が示されています。
この例では、ユーザーが赤色で汚染源を含むモジュールを識別しています。これはプログラムの攻撃面のおおよその近似値です。そのモジュール内のコードは右側のペインに表示され、下線はテイントを担う変数を示しています。
5. まとめ
「入力が適切に構成されており、合理的な範囲内である」と仮定するソフトウェアは、本質的にリスクが高く、失敗しやすいものであるといえます。最悪の場合、不正なデータが深刻なセキュリティ脆弱性やクラッシュを引き起こすことがあります。
テイント分析 は、プログラマーがリスクのあるデータがプログラムの一部から別の部分へどのように流れるかを理解するのを助ける技術です。高度な静的解析ツールはテイント分析 を実行し、その結果をユーザーに提示することで、プログラムの攻撃面を理解する作業を容易にし、深刻な欠陥を見つけて修正する作業を軽減します。
このコラムの著者

株式会社ユビキタスAI
エンベデッド第3事業部 担当部長
植田 宏​(うえだ ひろし)
大学卒業後Tier1メーカーへ入社、ECUソフトウェア開発を行う。その後海外で組込みソフトウェア開発エンジニアの経験を経て、帰国。1998年より車載系ソフトウェアの技術営業に従事。自身の経験を活かし、課題解決に役立つ海外のソフトウェア商材を取扱い、国内のエンジニアへ届けている。
より詳しく技術や関連製品について知りたい方へ
RED-DAとは?2025年8月に何が義務化される?
2025.04.16
印刷環境のセキュリティ強化:複合機(MFP)の脆弱性とその対策
2025.02.03
各国のIoT製品セキュリティ確保のための取り組み:米国 ―U.S. Cyber Trust Mark―
2025.01.27
各国のIoT製品セキュリティ確保のための取り組み:シンガポール ―サイバーセキュリティラベリングスキーム(CLS)
2024.11.11
各国のIoT製品セキュリティ確保のための取り組み:欧州
2024.10.23
太陽光発電と蓄電池システムの脆弱性:安全なエネルギーのためのセキュリティ対策
2024.10.08
各国のIoT製品セキュリティ確保のための取り組み:日本
2024.10.03
もう待てない、サイバーレジリエンス法対策
2024.09.17
各国のIoT製品セキュリティ確保のための取り組み: 英国
2024.04.18
ソフトウェアテストの新常識:ファジング入門
2024.04.17
JIS T 81001-5-1に準拠した医療機器のセキュリティ対策
2023.12.19
サプライチェーン攻撃と脆弱性テスト
2023.12.14
セキュリティ規格について
2023.09.01
ファジングとは?
2023.09.01
脆弱性検証―何をどこまで実施すれば良い?
2023.09.01
HEMS機器の脆弱性検証
2023.07.14
ファジングの限界
2023.07.14
- 全製品・サービス一覧
- Linux/Android高速起動
- セキュリティ
- ソフトウェア開発支援・検証
- ミドルウェア
- ネットワークマネジメント
- リアルタイムOS
- BIOS
- AI
- コンサルティング/サービス
- マルチメディア
- エミュレータ/プログラマ
- 産業一覧
Automotive
自動車
Infortainment/ADAS(先進運転支援システム)/ECU/ドライブレコーダー
Industrial
産業用機器
ファクトリーオートメーション(FA)/ビルディングオートメーション(BAS)/オフィスオートメーション(OA)/プロセスオートメーション(PA)/POS
Consumer
民生機器
Digital Camera/Digital TV/IoT家電
Medical / Healthcare
医療 / ヘルスケア機器
手術用ロボット/血糖計/輸液ポンプ/体外血液循環装置/内視鏡/治療機器
Smart Energy
スマートエネルギー
太陽光発電/照明/EV/PHV/蓄電池/燃料電池/スマートメーター
PC / Server
PC / サーバー
ノートPC / デスクトップPC/産業用PC/エンタープライズサーバー/データセンター