缓冲区溢出案例生成与分析

缓冲区溢出案例生成与分析

1.环境准备

  • 操作系统:Ubuntu-linux 这里我使用的是wsl虚拟机
  • 编译器:gcc
  • 调试工具:gdb

2.缓冲区漏洞案例生成

漏洞程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <stdio.h>
#include <string.h>

void vulnerable_function(char *input)
{
char buffer[64];
strcpy(buffer, input); // 这里存在缓冲区溢出漏洞
}

int main(int argc, char **argv)
{
if (argc > 1)
{
vulnerable_function(argv[1]);
} else
{
printf("Usage: %s <input>\n", argv[0]);
}
return 0;
}

存在的漏洞的原因在于它使用了不安全的函数 strcpy,并且没有对输入进行边界检查,导致有缓冲区溢出的可能性。

为什么会是危险的:如果 input 的长度超过64字节,strcpy 会继续将多余的数据写入 buffer 之外的内存区域。这会覆盖栈上的其他重要数据。

编译程序:

1
gcc -fno-stack-protector -z execstack -o vuln vuln.c
  • -fno-stack-protector: 禁用栈保护。
  • -z execstack: 允许栈执行。

(不这样做无法利用漏洞)

触发缓冲区溢出:

1
./vuln $(python -c 'print("A" * 100)')

image-20250305103238097

这样这个缓冲区溢出的漏洞就生成了

3.缓冲区溢出案例分析

使用GDB调试程序,查看崩溃时的寄存器状态。

1
gdb ./vuln

在GDB中运行程序:

1
run $(python -c 'print("A" * 100)')

image-20250305103702791

崩溃后,查看寄存器和栈:

1
2
info registers
x/20x $esp

image-20250305103837926

寄存器状态分析:

  • rbp 寄存器

    1
    rbp            0x4141414141414141  0x4141414141414141
    • rbp 是栈帧指针(Base Pointer),通常用于指向当前函数的栈帧。
    • 这里 rbp 的值被覆盖为 0x4141414141414141,其中 0x41 是字符 A 的 ASCII 码。这表明输入数据中的 A 覆盖了栈帧指针。
  • rip 寄存器

    1
    rip            0x55555555518e      0x55555555518e <vulnerable_function+37>
    • rip 是指令指针(Instruction Pointer),指向当前执行的指令。
    • 当前 rip 的值是 0x55555555518e,位于 vulnerable_function 函数中。这表明程序尚未返回,但栈帧已经被破坏。
  • 其他寄存器

    • rcxr9 等寄存器也被覆盖为 0x4141414141414141,进一步证明了输入数据溢出到了栈上的其他区域。

栈内存分析:

1
0xffffffffffffdac8:     Cannot access memory at address 0xffffffffffffdac8
  • 这是因为 $esp(栈指针)指向的地址 0xffffffffffffdac8 是一个无效地址(可能是由于栈被破坏导致的)。
  • 在 64 位系统中,地址空间非常大,而 0xffffffffffffdac8 是一个接近上限的地址,通常不会被映射到有效的内存区域。

4.如何修复这个漏洞

要修复这个漏洞,就要使用更安全的函数来替代 strcpy,并对输入进行边界检查。

  • 使用 strncpy 替代 strcpy,并指定最大复制长度:

    1
    2
    strncpy(buffer, input, sizeof(buffer) - 1);
    buffer[sizeof(buffer) - 1] = '\0'; // 确保字符串以 \0 结尾
  • 使用更安全的库函数,如 snprintf

    1
    snprintf(buffer, sizeof(buffer), "%s", input);
  • 对输入长度进行显式检查:

    1
    2
    3
    4
    if (strlen(input) >= sizeof(buffer)) {
    printf("Input too long!\n");
    return;
    }

在这里感谢deepseek对我的大力支持,寄存器分析和栈内存分析由他帮忙完成。

此为计算机思维导论作业


缓冲区溢出案例生成与分析
http://example.com/2025/03/05/缓冲区溢出案例生成与分析/
作者
yuhua
发布于
2025年3月5日
许可协议