hacktricks/binary-exploitation/integer-overflow.md

5.9 KiB

Débordement d'entier

{% hint style="success" %} Apprenez et pratiquez le piratage AWS :Formation HackTricks AWS Red Team Expert (ARTE)
Apprenez et pratiquez le piratage GCP : Formation HackTricks GCP Red Team Expert (GRTE)

Soutenez HackTricks
{% endhint %}

Informations de base

Au cœur d'un débordement d'entier se trouve la limitation imposée par la taille des types de données en programmation informatique et l'interprétation des données.

Par exemple, un entier non signé sur 8 bits peut représenter des valeurs de 0 à 255. Si vous essayez de stocker la valeur 256 dans un entier non signé sur 8 bits, elle revient à 0 en raison de la limitation de sa capacité de stockage. De même, pour un entier non signé sur 16 bits, qui peut contenir des valeurs de 0 à 65 535, ajouter 1 à 65 535 ramènera la valeur à 0.

De plus, un entier signé sur 8 bits peut représenter des valeurs de -128 à 127. Cela est dû au fait qu'un bit est utilisé pour représenter le signe (positif ou négatif), laissant 7 bits pour représenter la magnitude. Le nombre le plus négatif est représenté par -128 (binaire 10000000), et le nombre le plus positif est 127 (binaire 01111111).

Valeurs maximales

Pour les potentielles vulnérabilités web, il est très intéressant de connaître les valeurs maximales prises en charge :

{% tabs %} {% tab title="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 title="C" %} Les débordements d'entiers se produisent lorsqu'une opération mathématique dépasse la capacité maximale d'un type de données. Cela peut entraîner des résultats inattendus, tels que des valeurs incorrectes ou des plantages de programme. Il est important de vérifier et de gérer correctement les débordements d'entiers pour éviter les vulnérabilités de sécurité.

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

Exemples

Débordement pur

Le résultat imprimé sera 0 car nous avons débordé le 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;
}

Conversion de signé à non signé

Considérez une situation où un entier signé est lu à partir de l'entrée utilisateur, puis utilisé dans un contexte qui le traite comme un entier non signé, sans validation appropriée :

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

Dans cet exemple, si un utilisateur entre un nombre négatif, il sera interprété comme un grand entier non signé en raison de la façon dont les valeurs binaires sont interprétées, ce qui peut entraîner un comportement inattendu.

Autres exemples

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

ARM64

Cela ne change pas en ARM64 comme vous pouvez le voir dans cet article de blog.