mirror of
https://github.com/HackTricks-wiki/hacktricks.git
synced 2025-10-10 18:36:50 +00:00
116 lines
4.5 KiB
Markdown
116 lines
4.5 KiB
Markdown
# Przepełnienie całkowite
|
|
|
|
{{#include ../banners/hacktricks-training.md}}
|
|
|
|
## Podstawowe informacje
|
|
|
|
W sercu **przepełnienia całkowitego** leży ograniczenie narzucone przez **rozmiar** typów danych w programowaniu komputerowym oraz **interpretację** danych.
|
|
|
|
Na przykład, **8-bitowa liczba całkowita bez znaku** może reprezentować wartości od **0 do 255**. Jeśli spróbujesz przechować wartość 256 w 8-bitowej liczbie całkowitej bez znaku, zostanie ona zawinięta do 0 z powodu ograniczenia pojemności. Podobnie, dla **16-bitowej liczby całkowitej bez znaku**, która może przechowywać wartości od **0 do 65,535**, dodanie 1 do 65,535 spowoduje zawinięcie wartości z powrotem do 0.
|
|
|
|
Ponadto, **8-bitowa liczba całkowita ze znakiem** może reprezentować wartości od **-128 do 127**. Dzieje się tak, ponieważ jeden bit jest używany do reprezentacji znaku (dodatniego lub ujemnego), pozostawiając 7 bitów do reprezentacji wartości bezwzględnej. Najbardziej ujemna liczba jest reprezentowana jako **-128** (binarne `10000000`), a najbardziej dodatnia liczba to **127** (binarne `01111111`).
|
|
|
|
### Maksymalne wartości
|
|
|
|
Dla potencjalnych **luk w zabezpieczeniach w sieci** bardzo interesujące jest poznanie maksymalnych wspieranych wartości:
|
|
|
|
{{#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}}
|
|
|
|
## Przykłady
|
|
|
|
### Czyste przepełnienie
|
|
|
|
Wydrukowany wynik będzie równy 0, ponieważ przepełniliśmy 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
|
|
|
|
Rozważ sytuację, w której podpisana liczba całkowita jest odczytywana z wejścia użytkownika, a następnie używana w kontekście, który traktuje ją jako liczbę całkowitą bez znaku, bez odpowiedniej walidacji:
|
|
```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;
|
|
}
|
|
```
|
|
W tym przykładzie, jeśli użytkownik wprowadzi liczbę ujemną, zostanie ona zinterpretowana jako duża liczba całkowita bez znaku z powodu sposobu interpretacji wartości binarnych, co może prowadzić do nieoczekiwanego zachowania.
|
|
|
|
### Inne przykłady
|
|
|
|
- [https://guyinatuxedo.github.io/35-integer_exploitation/int_overflow_post/index.html](https://guyinatuxedo.github.io/35-integer_exploitation/int_overflow_post/index.html)
|
|
- Tylko 1B jest używane do przechowywania rozmiaru hasła, więc możliwe jest jego przepełnienie i sprawienie, że myśli, iż ma długość 4, podczas gdy w rzeczywistości ma 260, aby obejść ochronę sprawdzania długości
|
|
- [https://guyinatuxedo.github.io/35-integer_exploitation/puzzle/index.html](https://guyinatuxedo.github.io/35-integer_exploitation/puzzle/index.html)
|
|
|
|
- Mając kilka liczb, znajdź za pomocą z3 nową liczbę, która pomnożona przez pierwszą da drugą:
|
|
|
|
```
|
|
(((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/)
|
|
- Tylko 1B jest używane do przechowywania rozmiaru hasła, więc możliwe jest jego przepełnienie i sprawienie, że myśli, iż ma długość 4, podczas gdy w rzeczywistości ma 260, aby obejść ochronę sprawdzania długości i nadpisać w stosie następną zmienną lokalną oraz obejść obie ochrony
|
|
|
|
## ARM64
|
|
|
|
To **nie zmienia się w ARM64**, jak można zobaczyć w [**tym wpisie na blogu**](https://8ksec.io/arm64-reversing-and-exploitation-part-8-exploiting-an-integer-overflow-vulnerability/).
|
|
|
|
{{#include ../banners/hacktricks-training.md}}
|