4.4 KiB
Overflow di Interi
{{#include ../banners/hacktricks-training.md}}
Informazioni di Base
Al centro di un overflow di interi c'è la limitazione imposta dalla dimensione dei tipi di dati nella programmazione informatica e dall'interpretazione dei dati.
Ad esempio, un intero senza segno a 8 bit può rappresentare valori da 0 a 255. Se si tenta di memorizzare il valore 256 in un intero senza segno a 8 bit, esso torna a 0 a causa della limitazione della sua capacità di memorizzazione. Allo stesso modo, per un intero senza segno a 16 bit, che può contenere valori da 0 a 65.535, aggiungere 1 a 65.535 riporterà il valore a 0.
Inoltre, un intero con segno a 8 bit può rappresentare valori da -128 a 127. Questo perché un bit è utilizzato per rappresentare il segno (positivo o negativo), lasciando 7 bit per rappresentare la grandezza. Il numero più negativo è rappresentato come -128 (binario 10000000
), e il numero più positivo è 127 (binario 01111111
).
Valori massimi
Per le potenziali vulnerabilità web è molto interessante conoscere i valori massimi supportati:
{{#tabs}} {{#tab name="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"}}
#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}}
Esempi
Overflow puro
Il risultato stampato sarà 0 poiché abbiamo sovraccaricato il char:
#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;
}
Conversione da Firmato a Non Firmato
Considera una situazione in cui un intero firmato viene letto dall'input dell'utente e poi utilizzato in un contesto che lo tratta come un intero non firmato, senza una corretta validazione:
#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;
}
In questo esempio, se un utente inserisce un numero negativo, verrà interpretato come un grande intero senza segno a causa del modo in cui i valori binari vengono interpretati, portando potenzialmente a comportamenti imprevisti.
Altri Esempi
-
https://guyinatuxedo.github.io/35-integer_exploitation/int_overflow_post/index.html
-
Solo 1B è utilizzato per memorizzare la dimensione della password, quindi è possibile sovraccaricarlo e farlo pensare che la sua lunghezza sia 4 mentre in realtà è 260 per bypassare la protezione del controllo della lunghezza
-
https://guyinatuxedo.github.io/35-integer_exploitation/puzzle/index.html
-
Dati un paio di numeri, scopri usando z3 un nuovo numero che moltiplicato per il primo darà il secondo:
(((argv[1] * 0x1064deadbeef4601) & 0xffffffffffffffff) == 0xD1038D2E07B42569)
- https://8ksec.io/arm64-reversing-and-exploitation-part-8-exploiting-an-integer-overflow-vulnerability/
- Solo 1B è utilizzato per memorizzare la dimensione della password, quindi è possibile sovraccaricarlo e farlo pensare che la sua lunghezza sia 4 mentre in realtà è 260 per bypassare la protezione del controllo della lunghezza e sovrascrivere nello stack la successiva variabile locale e bypassare entrambe le protezioni
ARM64
Questo non cambia in ARM64 come puoi vedere in questo post del blog.
{{#include ../banners/hacktricks-training.md}}