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
- Consultez les plans d'abonnement!
- Rejoignez le 💬 groupe Discord ou le groupe Telegram ou suivez-nous sur Twitter 🐦 @hacktricks_live.
- Partagez des astuces de piratage en soumettant des PR aux HackTricks et HackTricks Cloud dépôts GitHub.
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
- https://guyinatuxedo.github.io/35-integer_exploitation/int_overflow_post/index.html
- Seulement 1B est utilisé pour stocker la taille du mot de passe, il est donc possible de le déborder et de le faire penser qu'il a une longueur de 4 alors qu'il est en réalité de 260 pour contourner la protection de vérification de longueur
- https://guyinatuxedo.github.io/35-integer_exploitation/puzzle/index.html
- Étant donné quelques nombres, découvrez en utilisant z3 un nouveau nombre qui, multiplié par le premier, donnera le deuxième:
(((argv[1] * 0x1064deadbeef4601) & 0xffffffffffffffff) == 0xD1038D2E07B42569)
- https://8ksec.io/arm64-reversing-and-exploitation-part-8-exploiting-an-integer-overflow-vulnerability/
- Seulement 1B est utilisé pour stocker la taille du mot de passe, il est donc possible de le déborder et de le faire penser qu'il a une longueur de 4 alors qu'il est en réalité de 260 pour contourner la protection de vérification de longueur et écraser dans la pile la variable locale suivante et contourner les deux protections
ARM64
Cela ne change pas en ARM64 comme vous pouvez le voir dans cet article de blog.