简单缓冲区溢出实践
简单缓冲区溢出实践
示例
以下这段简单的C程序存在缓冲区溢出漏洞:
// 缓冲区溢出
#include <stdio.h>
#include <string.h>
#define PASSWORD "1234567"
int verify_password(char * password) {
int authenticated = 0;
char buffer[8];
authenticated = strcmp(password, PASSWORD);
strcpy(buffer, password); // 此处存在缓冲区溢出漏洞
return authenticated;
}
int main()
{
char password[1024];
int valid_flag = 0;
while (1) {
printf("Please input your password: ");
scanf("%s", password);
valid_flag = verify_password(password);
if (valid_flag == 0) {
printf("Password is correct!\n");
break;
} else {
printf("Password is incorrect!\n");
}
}
}
正确的密码是 "1234567",但是输入"87654321"或任意8个字符也会被认为是正确的密码。
原理
在调用verify_password函数时,栈帧状态如下:
| (低地址) |
|---|
| char buff [0~3] |
| char buff [4~7] |
| int authenticated |
| 前一个栈帧的返回地址 |
| (高地址) |
在verify_password函数运行时,首先32位(4字节)局部变量authenticated被压入栈中,然后是占64位(8字节)的局部变量buffer,两个变量在栈中是连续存储的,即buff[8~11]为authenticated的地址。
当输入的密码长度为7个字符时,加上字符串末尾的'\0',总共是8个字节,正好填满buffer。但当输入的密码长度为8个字符以上时,程序会出现栈溢出。
在输入错误密码并执行strcmp之后,authenticated的值被赋为非零(假设为0x41),在小端模式下,authenticated的值会被存储为0x41 0x00 0x00 0x00。当输入的密码长度为8个字符时,strcpy(buffer, password)会将输入的密码(包括末尾的'\0')共9个字节复制到buffer中,这会导致8字节大小的buffer溢出,最后末尾的'\0'覆盖了authenticated变量的低地址字节(0x41)。最终authenticated的值变为0x00 0x00 0x00 0x00,即0,导致程序认为密码验证成功。
Please input your password: 8765432
Password is incorrect!
Please input your password: 87654321
Password is correct!
留言