堆溢出攻击

6

我正在学习堆溢出攻击,我的教科书提供了以下易受攻击的C代码:

/* record type to allocate on heap */
typedef struct chunk {
    char inp[64];            /* vulnerable input buffer */
    void (*process)(char *); /* pointer to function to process inp */
} chunk_t;

void showlen(char *buf)
{
    int len;
    len = strlen(buf);
    printf("buffer5 read %d chars\n", len);
}

int main(int argc, char *argv[])
{
    chunk_t *next;

    setbuf(stdin, NULL);
    next = malloc(sizeof(chunk_t));
    next->process = showlen;
    printf("Enter value: ");
    gets(next->inp);
    next->process(next->inp);
    printf("buffer5 done\n");
}

然而,教科书并没有解释如何修复这个漏洞。如果有人能够解释一下这个漏洞以及修复它的方法,那就太好了。(问题的一部分是我来自Java,而不是C)


4
你的 inp 是64个字节。因此,如果输入65个字节,你就会溢出... - Marc B
4
为了解决这个问题,使用fgets()函数 - Andreas Fester
@orangesoda 这是哪本书? - user1971598
例如,通过输入一个精心制作的字节序列(很可能是非ASCII码),长度为68个字节,您可以用已知的另一个函数的地址覆盖函数指针,然后执行该函数(在更大的程序中,比如办公套件)。但这与堆无关,同样适用于堆栈上的结构体。为了做一些堆特定的事情,您需要针对您知道在堆上靠近的数据,或者可能操作存储在内存块之间的簿记信息(但我不确定这会做什么,除了使程序崩溃)。 - Peter - Reinstate Monica
请看这里 - LPs
教材为 Stallings 的《计算机安全原理与实践》(第二版)。 - tam5
4个回答

5
代码使用了 gets,它以潜在的安全问题而臭名昭著:你无法指定传递给它的缓冲区长度,它会一直从 stdin 读取,直到遇到 \nEOF。因此,它可能会溢出你的缓冲区并写入缓冲区外的内存,然后坏事情就会发生——程序可能崩溃、继续运行或播放色情视频。
要解决这个问题,你应该使用 fgets

5
问题在于gets()函数会一直读取缓冲区,直到它读取到换行符或到达文件结尾。它不知道缓冲区的大小,所以当它超过限制时就不会停止。如果输入的行长度超过64个字节,这将溢出缓冲区,并覆盖process。如果输入的用户知道这一点,他可以在第64个位置键入恰当的字符,从而将函数指针替换为指向他想让程序调用的其他函数的指针。
解决方法是使用除gets()之外的其他函数,这样您就可以指定要读取的输入量的限制。例如:
gets(next->inp);

你可以使用以下方法:

fgets(next->inp, sizeof(next->inp), stdin);

fgets()的第二个参数告诉它最多写入64个字节到next->inp中。因此,它最多从stdin读取63个字节(需要允许一个字节用于空字符串终止符)。


1
你可以通过设置process的地址来填充超过64字节的下一个内容。这样可以使人们插入任何所需的地址,该地址可以是任何函数的指针。
为了修复问题,请确保只将63个字节(一个用于空值)读入数组inp中 - 使用fgets即可。

0

gets函数不会限制来自stdin的文本量。如果超过63个字符从stdin中获取,就会发生溢出。

gets会丢弃LF字符(即Enter键),但会在末尾添加一个null字符,因此有了63个字符的限制。

如果inp处的值由64个非空字符填充,因为它可以直接访问,所以showlen函数将触发访问冲突,因为strlen将搜索inp之外的null-char以确定其大小。

使用fgets将修复第一个问题,但它也会添加LF字符和null,因此可读取文本的新限制为62。

对于第二个问题,只需注意inp上写入了什么内容。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接