为什么下面的代码容易受到堆溢出攻击

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 攻击向量。