【问题标题】:Why is the following code susceptible to heap overflow attack为什么下面的代码容易受到堆溢出攻击
【发布时间】:2019-09-05 23:17:12
【问题描述】:

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

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) 读取的缓冲区大小超过了char namestruct data 中分配的128 的缓冲区大小吗?

任何帮助都会很棒

【问题讨论】:

  • 是的,它允许分配更多空间。但我认为这是缓冲区溢出而不是堆溢出
  • 有人告诉我这与指针本身有关。但是,伙计,我非常困惑,而且我对 C 和一般计算都是新手 :( :(
  • read(stdin,d->name,256); 看起来不对。确定在这里使用stdinread(int fd, void *buf, size_t count)? (启用所有编译器警告)

标签: c malloc heap-memory buffer-overflow


【解决方案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。现在,攻击者可以通过写信给d来修改f的内容。

为了利用此漏洞,攻击者通过对所有 256 个字节的输入重复该地址来提供他们已写入 d 的某些代码的地址。如果攻击者在地址0xbadc0de 存储了一些恶意代码,他们会将0xbadc0de 输入标准输入32 次(256 字节),从而覆盖堆。

     |  0xbadc0de  |
     +-------------+
f -> |  0xbadc0de  |
     +-------------+
     |     ...     |
     |  0xbadc0de  |
     |  0xbadc0de  |
d -> |  0xbadc0de  |
     +-------------+
     |             |

然后,您的代码到达该行

f->fp();

这是一个使用存储在f 中的地址的函数调用。机器转到内存位置f 并检索存储在那里的值,该值现在是攻击者恶意代码的地址。由于我们将其作为函数调用,机器现在跳转到该地址并开始执行存储在那里的代码,现在您手上就有了一个可爱的arbitrary code execution 攻击向量。

【讨论】:

  • 感谢先生的详细解释!快点,f -&gt; fp() 是什么意思? fp() 是什么?甚至是某种函数调用?
  • 箭头运算符 (-&gt;) 是“取消引用和访问”。 f 是指向struct fp 的指针,所以f-&gt;fp 等价于(*f).fp,即获取位于内存位置fstruct fp 并访问其名为fp 的成员。 fp 成员是一个指向函数的指针,因此将 () 放在它调用它指向的函数之后。
  • 更一般地说,在 C 中,函数名被视为指向这些函数的指针。所以someFunc() 只是将someFunc 作为指向函数的指针加载然后执行它,就像f-&gt;fp() 加载f-&gt;fp 并执行它一样。就像您可以存储指向数据的指针一样,您可以存储指向函数的指针,这实际上与通过名称调用函数相同。
  • 我明白了,它现在开始有意义了。所以本质上,read(stdin, d-&gt;name, 256) 中存在缓冲区溢出,因此,一些内存内容泄漏到了相邻的结构中。然后,当指针f 取消引用结构fp 时,他们可以改为将其指向堆中的不同函数?到目前为止,我感谢您的帮助-如果您能提供图表,那将是非常好的先生。上帝保佑先生!!
  • 没错!我实际上想过在答案中放一张图表,但最初决定不这样做。如果对您有帮助,我将返回并编辑答案以包括一些现在。
猜你喜欢
  • 1970-01-01
  • 2017-10-07
  • 1970-01-01
  • 1970-01-01
  • 2014-04-19
  • 1970-01-01
  • 2014-03-17
  • 2016-01-02
  • 2015-03-11
相关资源
最近更新 更多