# 整数溢出 {{#include ../banners/hacktricks-training.md}} ## 基本信息 在**整数溢出**的核心是计算机编程中数据类型的**大小**所施加的限制和数据的**解释**。 例如,一个**8位无符号整数**可以表示从**0到255**的值。如果你尝试在8位无符号整数中存储值256,由于其存储容量的限制,它会回绕到0。同样,对于一个**16位无符号整数**,它可以容纳从**0到65,535**的值,将1加到65,535会将值回绕到0。 此外,一个**8位有符号整数**可以表示从**-128到127**的值。这是因为一个位用于表示符号(正或负),剩下7个位用于表示大小。最小的负数表示为**-128**(二进制`10000000`),最大的正数是**127**(二进制`01111111`)。 ### 最大值 对于潜在的**网络漏洞**,了解最大支持值是非常有趣的: {{#tabs}} {{#tab name="Rust"}} ```rust fn main() { let mut quantity = 2147483647; let (mul_result, _) = i32::overflowing_mul(32767, quantity); let (add_result, _) = i32::overflowing_add(1, quantity); println!("{}", mul_result); println!("{}", add_result); } ``` {{#endtab}} {{#tab name="C"}} ```c #include #include int main() { int a = INT_MAX; int b = 0; int c = 0; b = a * 100; c = a + 1; printf("%d\n", INT_MAX); printf("%d\n", b); printf("%d\n", c); return 0; } ``` {{#endtab}} {{#endtabs}} ## 示例 ### 纯溢出 打印的结果将是 0,因为我们溢出了 char: ```c #include int main() { unsigned char max = 255; // 8-bit unsigned integer unsigned char result = max + 1; printf("Result: %d\n", result); // Expected to overflow return 0; } ``` ### Signed to Unsigned Conversion 考虑一种情况,其中从用户输入读取一个有符号整数,然后在一个将其视为无符号整数的上下文中使用,而没有进行适当的验证: ```c #include int main() { int userInput; // Signed integer printf("Enter a number: "); scanf("%d", &userInput); // Treating the signed input as unsigned without validation unsigned int processedInput = (unsigned int)userInput; // A condition that might not work as intended if userInput is negative if (processedInput > 1000) { printf("Processed Input is large: %u\n", processedInput); } else { printf("Processed Input is within range: %u\n", processedInput); } return 0; } ``` 在这个例子中,如果用户输入一个负数,由于二进制值的解释方式,它将被解释为一个大的无符号整数,这可能导致意外行为。 ### 其他示例 - [https://guyinatuxedo.github.io/35-integer_exploitation/int_overflow_post/index.html](https://guyinatuxedo.github.io/35-integer_exploitation/int_overflow_post/index.html) - 仅使用 1B 来存储密码的大小,因此可能会溢出并使其认为长度为 4,而实际上是 260,以绕过长度检查保护 - [https://guyinatuxedo.github.io/35-integer_exploitation/puzzle/index.html](https://guyinatuxedo.github.io/35-integer_exploitation/puzzle/index.html) - 给定几个数字,使用 z3 找出一个新数字,使其与第一个数字相乘得到第二个数字: ``` (((argv[1] * 0x1064deadbeef4601) & 0xffffffffffffffff) == 0xD1038D2E07B42569) ``` - [https://8ksec.io/arm64-reversing-and-exploitation-part-8-exploiting-an-integer-overflow-vulnerability/](https://8ksec.io/arm64-reversing-and-exploitation-part-8-exploiting-an-integer-overflow-vulnerability/) - 仅使用 1B 来存储密码的大小,因此可能会溢出并使其认为长度为 4,而实际上是 260,以绕过长度检查保护并在栈中覆盖下一个局部变量,从而绕过这两种保护 ## ARM64 这在 ARM64 中**没有变化**,正如你在 [**这篇博客文章**](https://8ksec.io/arm64-reversing-and-exploitation-part-8-exploiting-an-integer-overflow-vulnerability/)中看到的。 {{#include ../banners/hacktricks-training.md}}