You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Heap-Overflow还是Buffer-Overflow?代码memset写入额外字符的原因及漏洞问询

关于这段C代码的内存操作问题分析

咱们一步一步拆解你的问题,先理清代码里的关键细节,再逐个解答:

1. 为什么memset操作会写入额外字符?

你给a和b各用malloc(12)分配了12字节堆内存,但堆上两个内存块的地址差b-a远大于12。这是因为堆分配器(比如常见的glibc ptmalloc)会给每个堆块附加元数据(比如记录块大小、空闲状态的头部),而且内存分配会按固定字节数对齐(比如16字节),所以a和b的实际地址间隔d会比12大很多。

看代码里的执行流程:

  • 初始用bzero把a和b的12字节都清为'\0'
  • 接着用memset(a, 'a', 11),让a的前11位是'a',第12位保留'\0'(作为字符串终止符)
  • 但当你执行memset(a, 'a', b−a)时,写入长度是d(远大于12),这会把a的12字节全部覆盖成'a'(包括原本的终止符),还会继续写入a之后的内存区域——可能是b的内存块,也可能是堆的元数据区。

而printf("%s", a)会一直读取直到遇到'\0',现在a本身已经没有终止符了,所以会继续读取后面越界覆盖的内存内容(比如b里的'b'或者其他堆数据),最终就出现了额外字符。

2. 这段代码是否存在漏洞?

是的,存在明确的堆溢出(Heap-Overflow)漏洞。

堆溢出指的是写入的数据超出了堆内存块的合法分配大小,破坏了堆的元数据或其他内存区域。这段代码里的memset(a, 'a', b−a)完全无视a的12字节限制,越界写入会篡改堆分配器维护的关键数据(比如空闲链表指针、块大小标记)。这会导致后续的free(a)或free(b)操作直接崩溃,在更复杂的场景下,攻击者甚至可以利用这种漏洞篡改堆结构,执行任意恶意代码。

3. 如果是密码存储场景,每次打印是否会出现额外字符?

结果是不确定的,不一定每次都有额外字符,原因有两点:

  • 堆地址随机化(ASLR):现代系统默认开启ASLR,每次程序运行时堆的起始地址都会随机变化,b-a的差值也会跟着变。极端情况下如果某次差值刚好等于12(几乎不可能,因为堆元数据存在),那不会越界;但大多数时候差值会大于12,触发越界。
  • 越界区域的内容不确定:即使触发越界,覆盖的内存区域里是否有'\0'终止符是随机的。有时候可能很快遇到'\0',额外字符很少;有时候可能覆盖到没有终止符的区域,打印大量乱码,甚至直接导致程序崩溃。

另外要注意:用这种方式存储密码本身就极度不安全——明文存在堆里,越界操作还可能导致密码泄露到其他内存区域,被后续的内存分配读取到。

内容的提问来源于stack exchange,提问作者Tsolakidis Konstantinos

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 08:33:14