hacktricks/src/binary-exploitation/integer-overflow.md

116 lines
5.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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}}