hacktricks/binary-exploitation/stack-overflow/uninitialized-variables.md

9.1 KiB
Raw Blame History

Uninitialized Variables

{% hint style="success" %} Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Support HackTricks
{% endhint %}

Basic Information

Основна ідея полягає в тому, щоб зрозуміти, що відбувається з нініціалізованими змінними, оскільки вони матимуть значення, яке вже було в пам'яті, призначеній їм. Приклад:

  • Функція 1: initializeVariable: Ми оголошуємо змінну x і присвоюємо їй значення, скажімо, 0x1234. Ця дія подібна до резервування місця в пам'яті та вставлення в нього конкретного значення.
  • Функція 2: useUninitializedVariable: Тут ми оголошуємо іншу змінну y, але не присвоюємо їй жодного значення. У C нініціалізовані змінні не автоматично встановлюються в нуль. Натомість вони зберігають те, яке значення було останнім збережено в їхньому місці пам'яті.

Коли ми запускаємо ці дві функції послідовно:

  1. У initializeVariable змінній x присвоюється значення (0x1234), яке займає конкретну адресу пам'яті.
  2. У useUninitializedVariable змінна y оголошується, але їй не присвоюється значення, тому вона займає місце в пам'яті безпосередньо після x. Через те, що y не ініціалізована, вона в кінцевому підсумку "успадковує" значення з того ж місця пам'яті, яке використовувалося x, оскільки це останнє значення, яке там було.

Ця поведінка ілюструє ключове поняття в низькорівневому програмуванні: Управління пам'яттю є критично важливим, і нініціалізовані змінні можуть призвести до непередбачуваної поведінки або вразливостей безпеки, оскільки вони можуть ненавмисно містити чутливі дані, залишені в пам'яті.

Нініціалізовані стекові змінні можуть становити кілька ризиків безпеки, таких як:

  • Витік даних: Чутлива інформація, така як паролі, ключі шифрування або особисті дані, може бути розкрита, якщо зберігається в нініціалізованих змінних, що дозволяє зловмисникам потенційно читати ці дані.
  • Розкриття інформації: Вміст нініціалізованих змінних може розкрити деталі про структуру пам'яті програми або внутрішні операції, що допомагає зловмисникам розробляти цілеспрямовані експлойти.
  • Збої та нестабільність: Операції, що стосуються нініціалізованих змінних, можуть призвести до невизначеної поведінки, що викликає збої програми або непередбачувані результати.
  • Виконання довільного коду: У певних сценаріях зловмисники можуть експлуатувати ці вразливості, щоб змінити потік виконання програми, що дозволяє їм виконувати довільний код, що може включати загрози віддаленого виконання коду.

Example

#include <stdio.h>

// 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 викликає обидві вищезгадані функції послідовно, демонструючи контраст між ініціалізованою змінною та неініціалізованою.

ARM64 Приклад

Це зовсім не змінюється в ARM64, оскільки локальні змінні також управляються в стеку, ви можете перевірити цей приклад, де це показано.

{% hint style="success" %} Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Підтримати HackTricks
{% endhint %}