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

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

(((argv[1] * 0x1064deadbeef4601) & 0xffffffffffffffff) == 0xD1038D2E07B42569)

ARM64

Questo non cambia in ARM64 come puoi vedere in questo post del blog.

{{#include ../banners/hacktricks-training.md}}