简体   繁体   English

在C程序中找到漏洞

[英]Find the vulnerability in the C program

Studying for an exam in software security and came across this but can't find the vulnerability.学习软件安全考试并遇到此问题但找不到漏洞。 If you input the name "John Doe" and the salary 4000 then the program will write the string "John Doe: $4000".如果您输入姓名“John Doe”和薪水 4000,那么程序将写入字符串“John Doe: $4000”。 From what I can tell the program accounts for \0, there is no format string bug, no buffer overflow.据我所知,程序占\0,没有格式字符串错误,没有缓冲区溢出。 Don't know what I missed.不知道我错过了什么。

Edit: Forgot to add that the "name" parameter can be assumed to a valid null-terminated string.编辑:忘记添加“名称”参数可以假定为有效的以空字符结尾的字符串。

/* Calculates the number of letters (i.e. digits) that are needed to represent a decimal number as an ASCII string */
size_t count_digits(unsigned int number)
{
    unsigned int left = number;
    size_t n= 0;
    while(left != 0) {
        left = left / 10;
        n++;
    }
    return n;
}

void add_record(const char* name, unsigned int salary)
{
    char buffer[256];

    size_t len = strlen(name);
    size_t num_digits = count_digits(salary);

    /* 5 extra bytes required for colon and space after name + dollar sign, endline and NULL-terminator */
    if(len > SIZE_MAX - 5 || len + 5 > SIZE_MAX - num_digits) {
        printf("integer overflow");
        exit(1);
    }

    len = len + num_digits + 5;

    if (len > sizeof(buffer)) {
        printf("Too long string");
        exit(1);
    }

    /* Output formatted string to buffer (in the format string, %s denotes a string, and %u denotes an unsigned int that is printed as a decimal number) */
    sprintf(buffer, "%s: $%u\n", name, salary);

    // Write buffer to file
    fputs(buffer, global_file_handle);
}

count_digits incorrectly returns zero for zero. count_digits错误地将零返回为零。 The correct result is one.正确的结果是一。 A name of 251 characters with a salary of zero will require 257 characters (251 for name, 1 for salary, 5 for color, space, dollar sign, new-line, and null), but len will be incorrectly computed as 256, and len > sizeof(buffer) will not be triggered, so the code will overflow buffer .工资为零的 251 个字符的名称将需要 257 个字符(名称为 251,工资为 1,颜色、空格、美元符号、换行符和 null 为 5),但len将被错误地计算为 256,并且len > sizeof(buffer)不会被触发,所以代码会溢出buffer

(Another problem is strlen has undefined behavior when name is not null-terminated, but the context of name is not clear from the problem statement.) (另一个问题是当name不是以 null 结尾时strlen具有未定义的行为,但从问题陈述中并不清楚name的上下文。)

This is not an answer, but an example of what the code potentially should have been to avoid the buffer overflow described by Erik Postpischil.这不是一个答案,而是一个示例代码可能应该避免 Erik Postpischil 描述的缓冲区溢出。

The count_digits function is wrong (in case of 0 ), but also unnecessary. count_digits function 是错误的(在0的情况下),但也是不必要的。 It is possible to limit the output to buffer using snprintf :可以使用snprintf将 output 限制为buffer

void add_record(const char* name, unsigned int salary)
{
    char buffer[256];
    int len;

    len = snprintf(buffer, sizeof buffer, "%s: $%u\n", name, salary);
    if (len >= sizeof(buffer)) {
        printf("Too long string");
        exit(1);
    }

    fputs(buffer, global_file_handle);
}

Note that if len is exactly equal to sizeof buffer , this will mean that the resulting string was already truncated.请注意,如果len正好等于sizeof buffer ,这将意味着生成的字符串已经被截断。 In fact, len + 1 is the size that buffer should have been to prevent truncation.事实上, len + 1buffer应该防止截断的大小。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM