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

6 KiB
Raw Permalink Blame History

未初始化变量

{% hint style="success" %} 学习与实践 AWS 黑客技术:HackTricks 培训 AWS 红队专家 (ARTE)
学习与实践 GCP 黑客技术:HackTricks 培训 GCP 红队专家 (GRTE)

支持 HackTricks
{% endhint %}

基本信息

这里的核心思想是理解 未初始化变量的行为,因为它们将具有分配给它们的内存中已经存在的值。 示例:

  • 函数 1: initializeVariable:我们声明一个变量 x 并赋值,例如 0x1234。这个操作类似于在内存中保留一个位置并放入一个特定的值。
  • 函数 2: useUninitializedVariable:在这里,我们声明另一个变量 y,但没有给它赋值。在 C 语言中,未初始化的变量不会自动设置为零。相反,它们保留最后存储在其内存位置的值。

当我们 顺序 运行这两个函数时:

  1. initializeVariable 中,x 被赋值 (0x1234),占用了一个特定的内存地址。
  2. useUninitializedVariable 中,y 被声明但未赋值,因此它占据了紧接着 x 的内存位置。由于没有初始化 y,它最终“继承”了 x 使用的同一内存位置的值,因为那是最后一个在那里存在的值。

这种行为说明了低级编程中的一个关键概念:内存管理至关重要,未初始化的变量可能导致不可预测的行为或安全漏洞,因为它们可能无意中保留了留在内存中的敏感数据。

未初始化的栈变量可能带来几种安全风险,例如:

  • 数据泄露:如果敏感信息如密码、加密密钥或个人详细信息存储在未初始化的变量中,可能会被暴露,允许攻击者潜在地读取这些数据。
  • 信息泄露:未初始化变量的内容可能揭示程序的内存布局或内部操作的细节,帮助攻击者开发针对性的利用。
  • 崩溃和不稳定:涉及未初始化变量的操作可能导致未定义的行为,从而导致程序崩溃或不可预测的结果。
  • 任意代码执行:在某些情况下,攻击者可能利用这些漏洞来改变程序的执行流程,使他们能够执行任意代码,这可能包括远程代码执行威胁。

示例

#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" %} 学习与实践 AWS 黑客技术:HackTricks 培训 AWS 红队专家 (ARTE)
学习与实践 GCP 黑客技术:HackTricks 培训 GCP 红队专家 (GRTE)

支持 HackTricks
{% endhint %}