使用unsigned int作为数组索引是否会引发缓冲区溢出漏洞?
结论
你的核心判断方向是对的,但存在几处细节偏差,同时这段代码还有比类型转换问题更基础的致命错误。
先谈代码本身的基础错误(还没到漏洞触发环节)
这段代码连正常编译运行都做不到,有两个低级笔误:
scanf("%d", i);和scanf("%d", v);写法错误:scanf读取整数时需要传入变量的内存地址,正确写法是scanf("%d", &i);、scanf("%d", &v);。当前写法直接把未初始化的i、v的值当地址传入,会直接触发未定义行为,大概率当场崩溃,根本走不到调用setter的逻辑。setter(i, v, a)调用语句末尾漏了分号,属于语法错误,无法通过编译。
我们默认这两个是写示例时的疏漏、修正后再讨论漏洞逻辑。
关于类型转换触发越界的判断
你提到的带符号int类型的负数隐式转换为unsigned int类型时,会变成数值极大的无符号整数这个C语言规则是准确的,这确实是可被利用的漏洞点:
setter的形参i定义为unsigned int类型,main中传入的i是带符号int,传参时会发生隐式类型转换。如果用户输入负的i值,转换后会得到一个非常大的无符号整数,执行a[i] = v时,指针偏移会按这个大值计算,直接写到长度仅50个int的a数组范围外,属于典型的栈上越界写漏洞。
但要明确:这个类型转换不是漏洞的根本成因。这段代码完全没有对i做任何边界校验,哪怕用户输入i≥50的正整数,一样会越界写数组外的内存,类型转换只是让负数输入也能成为有效索引,扩大了可利用的输入范围而已。
你提到的利用方案的细节错误
你举的i=-1、v=40覆写返回地址跳转win函数的例子是无法生效的,有两个明显问题:
- i=-1转成unsigned int后的值是
UINT_MAX(32位环境下为4294967295),对应的内存偏移量是UINT_MAX * sizeof(int),这个地址离栈上a数组的基址极远,访问时会直接触发段错误,根本碰不到栈上存储的函数返回地址。要覆写返回地址,需要先计算a数组基址到返回地址存储位置的准确偏移,反推出对应的i值(如果这个偏移对应的i用带符号数表示为负数,才会用到你说的类型转换逻辑)。 - v=40不可能是win函数的内存地址。用户态程序的代码段加载地址远大于40,要覆写返回地址跳转到win函数,需要先获取win函数在内存中的实际加载地址,作为v的值输入才有可能生效。
内容的提问来源于stack exchange,提问作者user18005111
相关产品推荐
相关产品推荐

