为什么下面的代码容易受到堆溢出攻击
Why is the following code susceptible to heap overflow attack
我是网络安全新手,我想了解为什么以下代码容易受到堆溢出攻击...
struct data {
char name[128];
};
struct fp {
int (*fp)();
};
void printName() {
printf("Printing function...\n");
}
int main(int argc, char **argv) {
struct data *d;
struct fp *f;
d = malloc(sizeof(struct data));
f = malloc(sizeof(struct fp));
f->fp = printName;
read(stdin,d->name,256);
f->fp();
}
是否因为 read(stdin, d->name, 256)
读取的内容超过 struct data
中为 char name
分配的缓冲区大小 128
?
任何帮助都会很棒
A heap overflow attack is similar to a buffer overflow attack,除了不是覆盖堆栈中的值,攻击者践踏堆中的数据。
请注意您的代码中有两个动态分配的值:
d = malloc(sizeof(struct data));
f = malloc(sizeof(struct fp));
所以 d
现在保存了堆中 128 字节内存块的地址,而 f
保存了 8 字节(假设是 64 位机器)内存块的地址的记忆。从理论上讲,这两个地址可能彼此相距甚远,但由于它们都相对较小,因此 OS 可能分配了一大块连续内存并为您提供了彼此相邻的指针。
所以一旦你 运行 f->fp = printName;
,你的堆看起来像这样:
注:每行8字节宽
| |
+------------------------+
f -> | <Address of printName> |
+------------------------+
| ▲ |
| 11 more rows |
| not shown |
| |
d -> | <Uninitialized data> |
+------------------------+
| |
您对漏洞来源的初步评估是正确的。 d
指向 128 字节的内存,但是你让用户向该区域写入 256 字节。 C 没有边界检查机制,因此编译器非常乐意让您越过 d
内存的边界进行写入。如果 f
就在 d
旁边,您将越过 d
的边缘掉入 f
。现在,攻击者只需写入 d
.
即可修改 f
的内容
为了利用此漏洞,攻击者通过对所有 256 字节的输入重复该地址来提供他们写入 d
的某些代码的地址。如果攻击者在地址 0xbadc0de
存储了一些恶意代码,他们会将 0xbadc0de
提供给 stdin 32 次(256 字节),以便堆被覆盖。
| 0xbadc0de |
+-------------+
f -> | 0xbadc0de |
+-------------+
| ... |
| 0xbadc0de |
| 0xbadc0de |
d -> | 0xbadc0de |
+-------------+
| |
然后,你的代码到达行
f->fp();
这是一个使用存储在 f
中的地址的函数调用。机器转到内存位置 f
并检索存储在那里的值,该值现在是攻击者恶意代码的地址。由于我们将其作为函数调用,机器现在跳转到该地址并开始执行存储在那里的代码,现在您手上就有了一个可爱的 arbitrary code execution 攻击向量。
我是网络安全新手,我想了解为什么以下代码容易受到堆溢出攻击...
struct data {
char name[128];
};
struct fp {
int (*fp)();
};
void printName() {
printf("Printing function...\n");
}
int main(int argc, char **argv) {
struct data *d;
struct fp *f;
d = malloc(sizeof(struct data));
f = malloc(sizeof(struct fp));
f->fp = printName;
read(stdin,d->name,256);
f->fp();
}
是否因为 read(stdin, d->name, 256)
读取的内容超过 struct data
中为 char name
分配的缓冲区大小 128
?
任何帮助都会很棒
A heap overflow attack is similar to a buffer overflow attack,除了不是覆盖堆栈中的值,攻击者践踏堆中的数据。
请注意您的代码中有两个动态分配的值:
d = malloc(sizeof(struct data));
f = malloc(sizeof(struct fp));
所以 d
现在保存了堆中 128 字节内存块的地址,而 f
保存了 8 字节(假设是 64 位机器)内存块的地址的记忆。从理论上讲,这两个地址可能彼此相距甚远,但由于它们都相对较小,因此 OS 可能分配了一大块连续内存并为您提供了彼此相邻的指针。
所以一旦你 运行 f->fp = printName;
,你的堆看起来像这样:
注:每行8字节宽
| |
+------------------------+
f -> | <Address of printName> |
+------------------------+
| ▲ |
| 11 more rows |
| not shown |
| |
d -> | <Uninitialized data> |
+------------------------+
| |
您对漏洞来源的初步评估是正确的。 d
指向 128 字节的内存,但是你让用户向该区域写入 256 字节。 C 没有边界检查机制,因此编译器非常乐意让您越过 d
内存的边界进行写入。如果 f
就在 d
旁边,您将越过 d
的边缘掉入 f
。现在,攻击者只需写入 d
.
f
的内容
为了利用此漏洞,攻击者通过对所有 256 字节的输入重复该地址来提供他们写入 d
的某些代码的地址。如果攻击者在地址 0xbadc0de
存储了一些恶意代码,他们会将 0xbadc0de
提供给 stdin 32 次(256 字节),以便堆被覆盖。
| 0xbadc0de |
+-------------+
f -> | 0xbadc0de |
+-------------+
| ... |
| 0xbadc0de |
| 0xbadc0de |
d -> | 0xbadc0de |
+-------------+
| |
然后,你的代码到达行
f->fp();
这是一个使用存储在 f
中的地址的函数调用。机器转到内存位置 f
并检索存储在那里的值,该值现在是攻击者恶意代码的地址。由于我们将其作为函数调用,机器现在跳转到该地址并开始执行存储在那里的代码,现在您手上就有了一个可爱的 arbitrary code execution 攻击向量。