# 未初期化変数 {{#include ../../banners/hacktricks-training.md}} ## 基本情報 ここでの核心的なアイデアは、**未初期化変数が、割り当てられたメモリに既にあった値を持つことが何を意味するかを理解することです。** 例: - **関数 1: `initializeVariable`**: 変数 `x` を宣言し、値を割り当てます。例えば `0x1234` とします。このアクションは、メモリ内にスポットを予約し、特定の値をそこに置くことに似ています。 - **関数 2: `useUninitializedVariable`**: ここでは、別の変数 `y` を宣言しますが、値は割り当てません。C言語では、未初期化変数は自動的にゼロに設定されることはありません。代わりに、最後にそのメモリ位置に保存されていた値を保持します。 これらの二つの関数を**順次**実行すると: 1. `initializeVariable` では、`x` に値 (`0x1234`) が割り当てられ、特定のメモリアドレスを占有します。 2. `useUninitializedVariable` では、`y` が宣言されますが、値は割り当てられないため、`x` の直後のメモリスポットを取ります。`y` を初期化しなかったため、`x` が使用していた同じメモリ位置から値を「継承」することになります。なぜなら、それがそこにあった最後の値だからです。 この動作は、低レベルプログラミングにおける重要な概念を示しています: **メモリ管理は重要であり**、未初期化変数は予測不可能な動作やセキュリティの脆弱性を引き起こす可能性があります。なぜなら、意図せずにメモリに残された機密データを保持することがあるからです。 未初期化のスタック変数は、以下のような複数のセキュリティリスクを引き起こす可能性があります: - **データ漏洩**: パスワード、暗号鍵、または個人情報などの機密情報が未初期化変数に保存されると、攻撃者がこのデータを読み取る可能性があります。 - **情報漏洩**: 未初期化変数の内容は、プログラムのメモリレイアウトや内部操作に関する詳細を明らかにし、攻撃者がターゲットを絞ったエクスプロイトを開発するのを助ける可能性があります。 - **クラッシュと不安定性**: 未初期化変数を含む操作は未定義の動作を引き起こし、プログラムのクラッシュや予測不可能な結果をもたらすことがあります。 - **任意のコード実行**: 特定のシナリオでは、攻撃者がこれらの脆弱性を利用してプログラムの実行フローを変更し、任意のコードを実行できるようになる可能性があります。これにはリモートコード実行の脅威が含まれるかもしれません。 ### 例 ```c #include // Function to initialize and print a variable void initializeAndPrint() { int initializedVar = 100; // Initialize the variable printf("Initialized Variable:\n"); printf("Address: %p, Value: %d\n\n", (void*)&initializedVar, initializedVar); } // Function to demonstrate the behavior of an uninitialized variable void demonstrateUninitializedVar() { int uninitializedVar; // Declare but do not initialize printf("Uninitialized Variable:\n"); printf("Address: %p, Value: %d\n\n", (void*)&uninitializedVar, uninitializedVar); } int main() { printf("Demonstrating Initialized vs. Uninitialized Variables in C\n\n"); // First, call the function that initializes its variable initializeAndPrint(); // Then, call the function that has an uninitialized variable demonstrateUninitializedVar(); return 0; } ``` #### これがどのように機能するか: - **`initializeAndPrint` 関数**: この関数は整数変数 `initializedVar` を宣言し、値 `100` を割り当て、その後、変数のメモリアドレスと値の両方を印刷します。このステップは簡単で、初期化された変数がどのように動作するかを示しています。 - **`demonstrateUninitializedVar` 関数**: この関数では、初期化せずに整数変数 `uninitializedVar` を宣言します。その値を印刷しようとすると、出力にはランダムな数が表示されることがあります。この数は、そのメモリ位置に以前存在していたデータを表します。環境やコンパイラによって、実際の出力は異なる場合があり、安全のために、一部のコンパイラは変数を自動的にゼロに初期化することがありますが、これは信頼すべきではありません。 - **`main` 関数**: `main` 関数は、上記の2つの関数を順番に呼び出し、初期化された変数と初期化されていない変数の対比を示します。 ## ARM64の例 ARM64では、ローカル変数もスタックで管理されるため、全く変わりません。ここで示されている[**この例**](https://8ksec.io/arm64-reversing-and-exploitation-part-6-exploiting-an-uninitialized-stack-variable-vulnerability/)を確認できます。 {{#include ../../banners/hacktricks-training.md}}