mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
116 lines
5.8 KiB
Markdown
116 lines
5.8 KiB
Markdown
# Integer Overflow
|
||
|
||
{{#include ../banners/hacktricks-training.md}}
|
||
|
||
## Basic Information
|
||
|
||
В основі **переповнення цілого числа** лежить обмеження, накладене на **розмір** типів даних у комп'ютерному програмуванні та **інтерпретацію** даних.
|
||
|
||
Наприклад, **8-бітне беззнакове ціле число** може представляти значення від **0 до 255**. Якщо ви спробуєте зберегти значення 256 в 8-бітному беззнаковому цілому числі, воно обернеться назад до 0 через обмеження його ємності. Аналогічно, для **16-бітного беззнакового цілого числа**, яке може містити значення від **0 до 65,535**, додавання 1 до 65,535 поверне значення назад до 0.
|
||
|
||
Більше того, **8-бітне знакове ціле число** може представляти значення від **-128 до 127**. Це пов'язано з тим, що один біт використовується для представлення знака (позитивний або негативний), залишаючи 7 біт для представлення величини. Найбільш негативне число представляється як **-128** (бінарне `10000000`), а найбільш позитивне число — **127** (бінарне `01111111`).
|
||
|
||
### Max values
|
||
|
||
Для потенційних **веб-уразливостей** дуже цікаво знати максимальні підтримувані значення:
|
||
|
||
{{#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 <stdio.h>
|
||
#include <limits.h>
|
||
|
||
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 <stdio.h>
|
||
|
||
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 <stdio.h>
|
||
|
||
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}}
|