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

时间:2019-04-15 22:49:49

标签: c malloc heap buffer-overflow

我是网络安全的新手,我试图理解为什么以下代码容易受到堆溢出攻击...

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)读取了128char name的{​​{1}}分配的缓冲区大小以外的内容?

任何帮助都会很棒

1 个答案:

答案 0 :(得分:1)

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