nataliadiak/windows-x86-shellcode-poc
GitHub: nataliadiak/windows-x86-shellcode-poc
旨在帮助初学者理解 Windows x86 环境下基于栈的缓冲区溢出漏洞利用及 Shellcode 注入原理的教学型 PoC。
Stars: 5 | Forks: 0
# 初学者的 Windows x86 缓冲区溢出 PoC
这是一个简单、独立的关于 32 位 Windows 基于栈的缓冲区溢出漏洞利用的教程。
无需外部指南——你需要的一切都在这里。
## 这个仓库是什么?
- `vulnerable.c`:一个包含不安全 `gets()` 函数的简单程序。
- `messageBox.asm`:一段会在溢出后执行的小型汇编 payload。
- `exploit.c`:演示如何触发溢出的示例。
本项目教授一个核心理念:不安全的输入读取可以让攻击者覆盖返回地址并重定向执行流。
## 漏洞:`gets()` 没有大小限制
在 `vulnerable.c` 中,程序执行了以下操作:
```
char buffer[32];
gets(buffer);
```
程序为 `buffer` 分配了 32 个字节,然后调用 `gets()` 读取输入。
问题在于:`gets()` 不检查缓冲区大小。
它会不断读取字符,直到遇到换行符。
如果用户输入了 40 或 50 个字符,多余的字符就会溢出这 32 字节的缓冲区。
## 栈上的内存布局
当 C 函数运行时,栈(内存中的一块区域)会存储:
1. 局部变量(如 `buffer`)
2. 保存的 `EBP`(来自调用函数的基址指针)
3. 保存的返回地址(函数返回时 CPU 应该跳转到的位置)
如下所示:
```
Lower addresses (top of stack as drawn)
[ buffer (32 bytes) ]
[ saved EBP (4 bytes) ]
[ return address (4 bytes) ]
Higher addresses (bottom)
```
当 `gets()` 因为输入过多而使 `buffer` 溢出时,多余的字节会覆盖保存的 `EBP`,然后覆盖返回地址。
如果我们精心构造溢出数据,在返回地址字段中填入一个特定的地址,当函数尝试返回时,CPU 就会跳转到该地址。
## 漏洞利用原理:逐步解析
1. 程序启动并在栈上分配 `buffer[32]`。
2. 它调用 `gets(buffer)` 读取一行用户输入。
3. 我们发送一个长度超过 32 字节的字符串(比如 50 字节)。
4. `gets()` 没有大小检查,因此它将所有 50 个字节写入缓冲区。
5. 多余的 18 个字节溢出 `buffer` 并覆盖保存的 `EBP` 和返回地址。
6. 我们精心构造溢出数据,使返回地址指向栈上的 shellcode。
7. 当函数返回时,CPU 读取被覆盖的返回地址。
8. CPU 跳转到 shellcode。
9. shellcode 在该程序的权限下运行。
这是通过缓冲区溢出实现代码执行的最简单形式。
## shellcode 中发生了什么:Payload
`messageBox.asm` 是一段被设计为在溢出后运行的小段代码。
它执行以下操作:
1. **加载 USER32.DLL**:使用字符串 "USER32.DLL" 调用 `LoadLibraryA`,以确保该库已加载到内存中。
2. **为 MessageBoxA 准备参数**:将四个参数压入栈中(窗口句柄、消息文本、标题、按钮类型)。
3. **调用 MessageBoxA**:调用 Windows API 函数,显示一个包含文本 "CAN I HACK THE PC?" 的消息框。
4. **干净地退出**:调用 `ExitProcess` 以安全地终止程序。
关键点是:这是一段在溢出将执行流重定向到它之后运行的可执行代码。
当消息框出现在屏幕上时,它证明了三件事:
1. 缓冲区溢出成功并改写了返回地址。
2. 执行流跳转到了栈上的 shellcode。
3. shellcode 成功运行并调用了 Windows API。
在真实的攻击中,这个 payload 可以做任何事情:窃取数据、创建用户、下载恶意软件等。
消息框只是一种直观且安全的方式,用于演示发生了任意代码执行。
这个特定的 payload 为 `MessageBoxA` (0x751D8830) 和 `ExitProcess` (0x7437ADB0) 使用了硬编码的内存地址。
这些地址是特定于某个系统的。该 payload 需要针对不同的 Windows 版本或系统进行调整。

## 如何构建和运行演示
### 步骤 1:禁用保护机制
现代 Windows 拥有多个阻止此漏洞利用的安全特性:
- **Stack Canaries** (GS flag):检测栈覆盖。
- **ASLR** (DYNAMICBASE):随机化内存地址,使硬编码的地址失效。
- **DEP/NX** (NXCOMPAT):将栈标记为不可执行,以防止在那里执行代码。
对于这个学习练习,我们禁用所有这些保护。
### 步骤 2:在 Windows 上编译
使用带有特定标志的 MSVC (Microsoft Visual C++):
```
cl /c /GS- /W3 /Zl vulnerable.c
link /SUBSYSTEM:CONSOLE /DYNAMICBASE:NO /NXCOMPAT:NO vulnerable.obj /OUT:vulnerable.exe
```
标志含义:
- `/GS-` 禁用栈缓冲区溢出保护。
- `/DYNAMICBASE:NO` 禁用地址空间布局随机化 (ASLR)。
- `/NXCOMPAT:NO` 禁用 DEP,允许在栈上执行代码。
如果你已经有了可执行文件,可以使用 `editbin` 禁用保护:
```
editbin /NXCOMPAT:NO /DYNAMICBASE:NO vulnerable.exe
```
### 步骤 3:运行它
1. 启动 `vulnerable.exe`。
2. 出现提示时,输入一个长字符串(超过 32 个字符)。
3. 如果溢出成功,保存的返回地址将被覆盖。
4. 程序可能会崩溃、跳转到随机内存,或者(在具有适当 shellcode 的真实漏洞利用中)执行 payload。
## 为什么这份 README 是完整的
本 README 解释了:
1. `gets()` 是什么以及为什么不安全(没有大小限制)。
2. 栈如何存储局部变量、保存的寄存器和返回地址。
3. 溢出如何覆盖返回地址。
4. 函数返回时 CPU 如何使用返回地址。
5. 当返回地址指向 shellcode 时,shellcode 是如何执行的。
6. 存在哪些保护机制以及我们为什么要禁用它们。
7. 如何构建和运行示例。
你现在了解了整个缓冲区溢出漏洞利用的流程。
阅读代码文件并将它们与本解释进行比较,以巩固你的理解。
## 重要安全提示
此示例仅用于学习目的。
请勿对您不拥有或未获得明确测试许可的系统使用此技术。
未经授权访问计算机系统是违法行为。
标签:Golang, Go语言工具, PoC, Shellcode注入, Web报告查看器, Windows x86, 二进制漏洞, 内存安全, 安全教程, 安全编程, 客户端加密, 快速连接, 数据展示, 旧版系统漏洞, 暴力破解, 栈溢出, 汇编语言, 漏洞分析, 端点可见性, 红队, 缓冲区溢出, 网络安全, 自定义Shellcode, 路径探测, 隐私保护