我是网络安全的新手,我试图理解为什么以下代码容易受到堆溢出攻击...
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)
读取了128
中char name
的{{1}}分配的缓冲区大小以外的内容?
任何帮助都会很棒
答案 0 :(得分:1)
heap overflow attack与buffer overflow attack相似,不同之处在于,攻击者没有覆盖堆栈中的值,而是践踏了堆中的数据。
在代码中请注意,有两个动态分配的值:
d = malloc(sizeof(struct data));
f = malloc(sizeof(struct fp));
因此d
现在保存堆中128字节内存块的地址,而f
保存8字节(假设是64位计算机)内存块的地址。从理论上讲,这两个地址可能相距不远,但是由于它们都相对较小,因此操作系统很可能分配了一块较大的连续内存,并为您提供了彼此相邻的指针。
因此,一旦您运行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
。现在,攻击者仅通过写入f
就可以修改d
的内容。
为利用此漏洞,攻击者通过重复输入所有256个字节的内容来馈送他们已写入d
的某些代码的地址。如果攻击者已在地址0xbadc0de
中存储了一些恶意代码,则他们会将0xbadc0de
输入stdin 32次(256字节),以使堆被覆盖。
| 0xbadc0de |
+-------------+
f -> | 0xbadc0de |
+-------------+
| ... |
| 0xbadc0de |
| 0xbadc0de |
d -> | 0xbadc0de |
+-------------+
| |
然后,您的代码到达该行
f->fp();
这是使用存储在f
中的地址进行的函数调用。机器转到内存位置f
并检索存储在其中的值,该值现在是攻击者恶意代码的地址。由于我们将其称为函数,因此机器现在跳至该地址并开始执行存储在该地址的代码,现在您的手上有了一个可爱的arbitrary code execution攻击向量。