堆溢出攻击
Heap Overflow Attack
我正在学习堆溢出攻击,我的教科书提供了以下易受攻击的 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)
该代码使用 gets
,它因潜在的安全问题而臭名昭著:无法指定您传递给它的缓冲区的长度,它只会继续从 stdin
读取直到遇到\n
或EOF
。因此,它可能会溢出您的缓冲区并写入缓冲区之外的内存,然后就会发生坏事 - 它可能会崩溃,它可能会保持 运行,它可能会开始播放色情内容。
要解决此问题,您应该改用 fgets
。
您可以通过设置 process
的地址来填充超过 64 字节的 next。从而使人们能够插入任何想要的地址。地址可以是指向任何函数的指针。
要修复简单确保只有 63 个字节(一个表示空)被读入数组 inp
- 使用 fgets
问题是 gets()
将继续读入缓冲区,直到它读取一个换行符或到达 EOF。它不知道缓冲区的大小,所以它不知道在达到限制时应该停止。如果该行是 64 字节或更长,这将超出缓冲区,并覆盖 process
。如果输入输入的用户知道这一点,他可以在位置 64 处键入正确的字符,将函数指针替换为指向他想让程序调用的其他函数的指针。
修复方法是使用 gets()
以外的函数,因此您可以指定对将读取的输入量的限制。而不是
gets(next->inp);
您可以使用:
fgets(next->inp, sizeof(next->inp), stdin);
fgets()
的第二个参数告诉它最多写入 64 个字节到 next->inp
。因此它将最多从 stdin
中读取 63 个字节(它需要为空字符串终止符允许一个字节)。
gets 函数不限制来自 stdin
的文本数量。如果超过 63 个字符来自 stdin
,就会发生溢出。
gets 丢弃了 LF 字符,这将是一个 [Enter] 键,但它在末尾添加了一个空字符,因此限制了 63 个字符。
如果inp
处的值填充了64个非空字符,因为可以直接访问,showlen
函数会触发访问冲突,因为strlen
会搜索超出 inp
的空字符以确定其大小。
使用 fgets
可以很好地解决第一个问题,但它还会添加一个 LF 字符和 null,因此可读文本的新限制为 62。
第二个,只要注意写在inp
上的内容即可。
我正在学习堆溢出攻击,我的教科书提供了以下易受攻击的 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)
该代码使用 gets
,它因潜在的安全问题而臭名昭著:无法指定您传递给它的缓冲区的长度,它只会继续从 stdin
读取直到遇到\n
或EOF
。因此,它可能会溢出您的缓冲区并写入缓冲区之外的内存,然后就会发生坏事 - 它可能会崩溃,它可能会保持 运行,它可能会开始播放色情内容。
要解决此问题,您应该改用 fgets
。
您可以通过设置 process
的地址来填充超过 64 字节的 next。从而使人们能够插入任何想要的地址。地址可以是指向任何函数的指针。
要修复简单确保只有 63 个字节(一个表示空)被读入数组 inp
- 使用 fgets
问题是 gets()
将继续读入缓冲区,直到它读取一个换行符或到达 EOF。它不知道缓冲区的大小,所以它不知道在达到限制时应该停止。如果该行是 64 字节或更长,这将超出缓冲区,并覆盖 process
。如果输入输入的用户知道这一点,他可以在位置 64 处键入正确的字符,将函数指针替换为指向他想让程序调用的其他函数的指针。
修复方法是使用 gets()
以外的函数,因此您可以指定对将读取的输入量的限制。而不是
gets(next->inp);
您可以使用:
fgets(next->inp, sizeof(next->inp), stdin);
fgets()
的第二个参数告诉它最多写入 64 个字节到 next->inp
。因此它将最多从 stdin
中读取 63 个字节(它需要为空字符串终止符允许一个字节)。
gets 函数不限制来自 stdin
的文本数量。如果超过 63 个字符来自 stdin
,就会发生溢出。
gets 丢弃了 LF 字符,这将是一个 [Enter] 键,但它在末尾添加了一个空字符,因此限制了 63 个字符。
如果inp
处的值填充了64个非空字符,因为可以直接访问,showlen
函数会触发访问冲突,因为strlen
会搜索超出 inp
的空字符以确定其大小。
使用 fgets
可以很好地解决第一个问题,但它还会添加一个 LF 字符和 null,因此可读文本的新限制为 62。
第二个,只要注意写在inp
上的内容即可。