返回目录

简单缓冲区溢出实践

安全 渗透

简单缓冲区溢出实践

示例

以下这段简单的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!

留言