Qu'est-ce qu'une attaque par débordement d'entier (avec exemples) ?
Les attaques par débordement d’entier impliquent l’exploitation de bugs dans les logiciels. Lorsque ces défauts de dépassement d'entier sont abusés, cela peut conduire à des résultats désastreux, notamment infecter des appareils avec des logiciels espions .
Les dépassements d’entiers constituent une menace de sécurité importante. En 2021, ils se sont classés 12ème dans la mise à jour Liste d'énumération des faiblesses communes (CWE) des défauts, bugs, erreurs et autres erreurs les plus courants que ce soit au niveau matériel ou logiciel. L’équipe à l’origine de la liste a classé les dépassements d’entiers juste après « Authentification manquante pour une fonction critique », en raison de la gravité et de la prévalence des dépassements d’entiers.
Codé CWE-190, dépassements d'entier déplacé vers le bas d'une place de la 11ème place l'année précédente. Ils constituent depuis longtemps l'une des faiblesses logicielles les plus préoccupantes, se situant à numéro 8 en 2019 .
Même si les dépassements d’entiers progressent lentement dans la liste, cela ne signifie pas qu’ils constituent une menace dont nous n’avons plus à nous soucier. Ils sont toujours répandus et peuvent avoir des conséquences importantes, dont nous parlerons dans le Exemples d'attaques par débordement d'entier section.
Cela nous amène à la question fondamentale :
Qu'est-ce qu'un débordement d'entier ?
Il sera plus facile de comprendre les débordements d’entiers si nous commençons par les expliquer par une métaphore.
Une métaphore des débordements d'entiers
Imaginez que vous possédez une vieille voiture que vous conduisez depuis trente ans. Vous aimez la voiture, l'emmenez en road trip et l'utilisez tous les jours. Il a toujours été fiable et vous y avez consacré beaucoup de temps. Tant de temps et tant de kilomètres que le compteur kilométrique atteint déjà 999 999. Vous avez bien pris soin de votre voiture au fil des années et vous êtes impatient de célébrer.
La voiture n’a qu’un compteur kilométrique analogique à six chiffres, alors que va-t-il se passer lorsque vous parcourez ce kilomètre supplémentaire ? Il ne peut pas atteindre un million, car il ne possède tout simplement pas le septième chiffre nécessaire pour afficher des valeurs d’un million ou plus.
Au lieu de cela, lorsque vous conduisez votre voiture et parcourez un kilomètre supplémentaire, le compteur kilométrique reviendra à 000 000 milles. Pas un million. Zéro. La lecture du compteur kilométrique est exactement la même que celle d’une voiture qui vient tout juste de sortir de l’usine. Malgré tous les soins que vous avez apportés à votre voiture, tout le monde peut constater qu’elle n’est pas neuve. Les sièges sont usés, une partie de la peinture est écaillée et le moteur ne ronronne plus aussi doucement qu’avant.
Mais il est écrit 000 000. Ce qui s'est passé?
Ceci est un exemple de débordement d'entier .
Nous voyons chaque jour la même chose sur nos horloges. Les secondes défilent et tout d’un coup il est midi. Lorsqu'une heure de plus s'écoule, nous sommes de retour à 13 heures. Pourquoi?
Une horloge qui passe midi. Horloge Heure Montre par designermariene et sous licence CC0 .
C’est un autre débordement d’entier. Au lieu de continuer jusqu'à 13h, 14h. … 98 heures, 99 heures, etc., l'horloge ne dépasse pas midi (sauf si nous parlons d'horloges de 24 heures, auquel cas la même chose se produit, juste à 24 au lieu de 12). Le temps ne cesse de passer, et pourtant notre décompte se réinitialise et revient au début.
Non, la voiture n’a pas soudainement parcouru tous ces kilomètres, et nous n’avons pas non plus voyagé dans le temps entre 12 h 59 et 13 heures. Dans les deux cas, il existe des raisons pratiques pour lesquelles nous ne continuons pas à compter au-delà de ces limites.
Très peu de voitures parcourent un million de kilomètres, et personne ne confondrait une voiture d’un million de kilomètres avec une voiture neuve, donc le premier exemple ne pose pas de problèmes majeurs dans le monde réel. Nous utilisons des horloges pour nous aider à suivre nos journées et disposons d’autres systèmes pour suivre le temps à plus grande échelle. Entre l'ajout du matin et du soir après l'heure et en utilisant la date, le mois et l'année, tout le monde est capable de se coordonner très bien. Il n’est pas nécessaire de remonter à un milliard d’heures pour savoir que le temps ne recommence pas deux fois par jour.
Oui, ce sont des débordements d’entiers, mais ils n’entraînent pas vraiment de complications. Maintenant que nous avons démontré certains dépassements d’entiers que nous constatons dans notre vie quotidienne, voyons comment les dépassements d’entiers affectent les ordinateurs et comment ils peuvent conduire à des attaques par dépassement d’entiers.
Comment fonctionnent les dépassements d’entiers dans les ordinateurs ?
Au niveau le plus bas, les ordinateurs font simplement beaucoup de mathématiques. Que vous regardiez des photos de chats en ligne, tapiez un document dans Microsoft Word, ajoutiez des nombres décimaux dans votre calculatrice ou codiez en Python, au fond, ce ne sont que des zéros et des uns manipulés de manière précise.
Dans toutes les tâches que nous effectuons sur nos ordinateurs, ils effectuent constamment d’innombrables additions binaires et autres opérations mathématiques.
Ces calculs sont effectués sur des entiers binaires, qui ne sont essentiellement que des chaînes de nombres en binaire. Le problème des débordements d’entiers se pose lorsque les résultats de ces opérations sont plus grands que l’espace disponible pour les stocker.
Si un programme effectue un calcul et que la vraie réponse est supérieure à l'espace disponible, cela peut entraîner un dépassement d'entier. Ces dépassements d'entiers peuvent amener le programme à utiliser des nombres incorrects et à réagir de manière involontaire, ce qui peut ensuite être exploité par des attaquants.
Contrairement à nos exemples avec le compteur kilométrique et l’horloge, les dépassements d’entiers peuvent causer des problèmes importants dans les ordinateurs. Les conséquences peuvent être graves même en l’absence d’activité malveillante de la part des pirates. Dans les années 90, une simple erreur de dépassement d’entier était une raison importante de l’explosion d’un Fusée de l'Agence spatiale européenne cela a coûté des centaines de millions de dollars.
Quelle peut être la taille des entiers ?
À titre d'exemple, l'une des conceptions les plus courantes pour les ordinateurs personnels est l'architecture x86-64. Sur ce type d'architecture, les registres à usage général sont capables d'opérer directement sur des entiers de 64 bits (il existe voies indirectes dans lequel ils peuvent opérer sur des nombres plus grands, ce qui est important pour les grands nombres que nous utilisons souvent en cryptographie, mais nous n’en parlerons pas dans cet article). Si votre ordinateur dispose d'un processeur 64 bits, cela signifie qu'il doit pouvoir fonctionner sur des nombres entiers allant jusqu'à 264 en une seule opération. Écrit entièrement en binaire, cela signifie des nombres allant jusqu'à :
1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111
Pour les non-robots, la valeur décimale équivalente est :
18 446 744 073 709 551 616
Cela représente 17 179 869 téraoctets de données, ce qui est énorme étant donné que le dernier iPhone a un maximum d'un téraoctet, ce qui est considéré comme plus que suffisant pour la plupart des utilisateurs.
Entiers signés, nombres négatifs et complément à deux
Les ordinateurs doivent également être capables de stocker des nombres négatifs à de nombreuses fins. Au niveau le plus bas, les ordinateurs ne peuvent pas simplement placer un signe moins devant un nombre pour indiquer qu’il est négatif, comme le font les humains. Ils ne peuvent représenter les données qu’avec des zéros et des uns à ce niveau ; ils ne peuvent utiliser aucun symbole pratique.
La manière la plus courante d’y parvenir est de recourir à ce que l’on appelle le complément à deux. Le complément à deux nous permet de représenter des entiers signés, ce qui signifie essentiellement que nous avons un moyen d’utiliser à la fois des nombres positifs et négatifs plutôt que uniquement des nombres positifs.
Lorsque le complément à deux est utilisé, le chiffre binaire le plus à gauche ne représente plus une partie de la valeur du nombre. Au lieu de cela, il indique si le nombre est positif ou négatif. Le chiffre le plus à gauche est un 0 s’il s’agit d’un nombre positif et un 1 s’il s’agit d’un nombre négatif.
Si on comptait juste en binaire :
0, 1, 2, 3
Serait représenté comme :
00, 01, 10, 11
Avec la représentation en complément à deux, nous ajoutons un autre chiffre à gauche, et ce chiffre le plus à gauche devient le signe. Ce sont maintenant des entiers signés. Cette fois, nous allons inverser les choses et vous montrer d’abord le binaire :
000, 001, 010, 011, 100, 101, 110, 111
Comme nous l’avons mentionné précédemment, le zéro supplémentaire à l’extrême gauche des quatre premiers nombres nous indique simplement que les nombres sont positifs. En dehors de cela, cela ne modifie en rien leur valeur.
Après cela, les choses deviennent un peu plus délicates. Nous savons que dans le complément à deux, un 1 dans le chiffre le plus à gauche signifie que le nombre est négatif, donc 1 00, 101, 110 et 111 doivent inclure un symbole moins. Mais par où commencer ?
Dans le système du complément à deux, le plus grand nombre binaire a la plus petite valeur négative dans le système décimal. Lorsque nous n’avons affaire qu’à des nombres à trois bits, cela signifie que 111 vaut -1. A partir de là, nous pouvons revenir en arrière. 110 vaut -2, 101 vaut -3 et 100 vaut -4.
Aussi peu intuitif que cela puisse paraître, dans le système du complément à deux, les valeurs binaires séquentielles de :
000, 001, 010, 011, 100, 101, 110, 111
Représente les nombres décimaux suivants :
0, 1, 2, 3, -4, -3, -2, -1
Oui, c'est étrange, mais il y en a effectivement de bonnes raisons pour ça. Malheureusement, les expliquer nous amènerait à prendre une trop grande tangente.
Le complément à deux en action
Jetons un coup d'œil à ce que serait notre nombre de 64 bits ci-dessus dans une représentation en complément à deux. C’était une série de 64 uns, et on sait maintenant qu’en complément à deux, le plus à gauche signifie que ce doit être un nombre négatif. Si nous mettons la chaîne de 1 de 64 bits dans un convertisseur de complément à deux (saisissez 64 dans le champ Nombre de bits, et n'oubliez pas de laisser de côté les espaces), cela nous donne le nombre décimal de :
-1
Si vous avez suivi de près, vous vous attendiez peut-être à ce résultat, car nous avons mentionné que le plus grand nombre binaire a la plus petite valeur négative dans le système décimal et qu'une chaîne composée uniquement de 1 est la plus grande valeur de 64 bits possible.
Si nous voulons déterminer l’étendue d’une chaîne de 64 bits dans le système du complément à deux, nous pouvons trouver le nombre négatif le plus élevé en convertissant le plus petit nombre binaire commençant par un. Le plus petit nombre binaire commençant par un est la chaîne suivante :
1000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
Lorsqu'on le met dans le même convertisseur (encore une fois, il faut saisir 64 dans le champ Nombre de bits, et ne pas oublier de laisser les espaces), cela nous donne :
-9 223 372 036 854 775 808
Pour connaître le nombre positif le plus élevé qu'un processeur 64 bits peut gérer (de manière simple, il existe d'autres moyens), il suffit de saisir le nombre 64 bits le plus élevé qui commence par un 0 (pour indiquer qu'il est positif). . Par conséquent, nous devons mettre ce qui suit dans la même calculatrice que celle que nous avons utilisée dans les opérations précédentes :
0111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111
Cela nous donne :
9 223 372 036 854 775 807
En théorie, un registre de 64 bits peut gérer directement les nombres signés de n'importe quelle valeur comprise entre -9 223 372 036 854 775 808 et 9 223 372 036 854 775 807.
Limitations sur les entiers en C
Les nombres entiers ne sont pas seulement limités par les registres disponibles. Ils peuvent également être limités par la programmation. A titre d'exemple, voici quelques-uns Les différents types entiers de C et les valeurs qu'ils autorisent :
- SHRT_MIN (la valeur minimale pour un entier court) : -32 768 bits
- SHRT_MAX (la valeur maximale pour un entier court) : +32 767 bits
- USHRT_MAX (la valeur maximale pour un entier court non signé) : 65 535 bits
- INT_MIN (la valeur minimale pour un entier) : -2 147 483 648 bits
- INT_MAX (la valeur maximale pour un entier) : +2 147 483 647 bits
- UINT_MAX (la valeur maximale pour un entier non signé) : 4 294 967 295 bits
- LONG_MIN (la valeur minimale pour un entier long) : -9 223 372 036 854 775 808 bits
- LONG_MAX (la valeur maximale pour un entier long) : +9 223 372 036 854 775 807 bits
- ULONG_MAX (la valeur maximale pour un entier long non signé) : 18 446 744 073 709 551 615 bits
Prenons SHRT_MAX et INT_MAX comme exemples. Si le résultat qui devait être stocké dans la position allouée dépassait respectivement +32 767 bits ou +2 147 483 647 bits, il s’agirait d’un dépassement d’entier. Par conséquent, un résultat de +32 788 bits serait un dépassement d’entier dans le premier cas. Le dépassement d'entier pourrait également avoir une valeur nettement plus grande, quelque chose comme +3 000 000 000 de bits dans le second cas. Cela fonctionne de la même manière pour LONG_MAX, sauf que la valeur maximale est beaucoup plus élevée.
Maintenant, regardons SHRT_MIN. La valeur minimale est de -32 768 bits, alors que se passe-t-il si nous avons une valeur de -32 769 ou -40 000 ? Vous pourriez être tenté de l’appeler un débordement entier, et beaucoup de gens le font. Les chiffres sont trop faibles pour la valeur minimale, donc un dépassement inférieur semble logique.
Cependant, c’est en réalité le même problème dans l’autre sens : la valeur que nous devons stocker occupe plus de caractères que ce qui lui est alloué.
Si vous pouvez mettre la main sur un exemplaire du livre de Robert SeacordCodage sécurisé en C et C++, leSécurité entièreLa section indique que :
Un dépassement d'entier se produit lorsqu'un entier est augmenté au-delà de sa valeur maximale ou diminué au-delà de sa valeur minimale… La diminution d'un entier au-delà de sa valeur minimale est souvent appelée un dépassement inférieur d'entier, bien que techniquement, ce terme fasse référence à une condition de virgule flottante.
Par conséquent, il est préférable d’appeler également cette situation un débordement d’entier. La situation est également similaire pour INT_MIN et LONG_MIN. Lorsque les résultats d’une opération sont inférieurs à leurs valeurs minimales respectives, cela provoquera un débordement d’entier.
Nous avons gardé chacune des variables non signées séparées pour le moment, pour des raisons qui apparaîtront dans les sections suivantes. Alors, que se passe-t-il si une opération aboutit à des valeurs qui dépassent les limites des variables USHRT_MAX, UINT_MAX et ULONG_MAX ? Encore une fois, les valeurs seraient trop grandes pour être stockées dans l'espace alloué. Malgré cela, le Norme C précise spécifiquement que ces situations « ne pourront jamais déborder ». Cependant, il n’est toujours pas inhabituel que les gens parlent de ces résultats pour des variables non signées comme de débordements d’entiers.
Ces cas non signés ne diffèrent pas seulement par leurs valeurs maximales qui sont à peu près le double de celles de leurs frères signés SHRT_MAX, INT_MAX et LONG_MAX. Ils entraînent également des comportements différents.
Que se passe-t-il en cas de débordement d'entier en C (variables non signées et wraparounds) ?
Si les variables non signées dépassent la valeur maximale (telles que celles répertoriées dans USHRT_MAX, UINT_MAX et ULONG_MAX) dans une situation donnée, cela revient simplement à utiliser Arithmétique modulaire . C'est fondamentalement la même chose que le compteur kilométrique de la voiture qui passe de 999 999 à zéro.
Par exemple, le USHRT_MAX est de 65 535 bits, qui s'affiche en binaire comme :
1111 1111 1111 1111
Si nous devions ajouter 1 à la valeur entière courte non signée maximale de 65 535 bits, cela reviendrait simplement à :
0000 0000 0000 0000
Dans d’autres circonstances, on s’attendrait normalement à ce que le résultat de cette opération soit :
1 1111 1111 1111 1111
Ce retour à une chaîne de zéros peut être assez problématique dans diverses situations. C’est un exemple exagéré, mais nous sommes sûrs que vous pouvez imaginer à quel point ce serait dévastateur si votre compte bancaire revenait à zéro.
Lorsque la valeur maximale non signée provoque un bouclage vers une valeur très différente du résultat attendu, cela peut entraîner de nombreuses complications, erreurs, plantages, boucles infinies, corruption de données et bien plus encore. Il est donc essentiel de concevoir nos programmes pour éviter les rebouclages involontaires.
Alors que se passe-t-il dans les exemples de débordements d’entiers signés ?
Nous ne pouvons pas le prédire.
C'est parce que le Norme C indique que les dépassements d'entiers signés entraînent un comportement indéfini.
Que se passe-t-il en cas de débordement d'entier en C (variables signées et comportement non défini) ?
Dans un monde idéal, les développeurs sont censés programmer leurs logiciels de manière à ce qu’aucun comportement indéfini ne se produise. Lorsque les compilateurs supposent qu’aucun comportement indéfini ne se produit, cela leur permet d’optimiser le code.
Cependant, le monde n’est pas parfait, les gens font des erreurs et certains développeurs écrivent du code pouvant entraîner un comportement indéfini.
Lorsqu'un dépassement d'entier entraîne un comportement indéfini, aucune action prédéfinie n'est définie. Essentiellement, un comportement indéfini signifie que la condition est inattendue et que nous ne savons pas ce que le programme fera réellement.
Cela signifie que contrairement aux cas précédents où les valeurs non signées dépassent les limites, nous ne pouvons pas être sûrs de la manière dont le programme agira réellement. La valeur peut simplement revenir en arrière et provoquer des problèmes similaires à ceux répertoriés dans la section précédente. Cela pourrait également donner un entier négatif. Dans certaines situations, vous pourriez même avoir de la chance et cela pourrait fonctionner comme prévu malgré le dépassement d'entier.
Cela dépend vraiment des circonstances individuelles, mais un comportement indéfini entraînera très probablement de graves erreurs. Il va sans dire qu’un comportement imprévisible dans les programmes est mauvais, car nous ne savons pas ce qui va se passer, quels bugs cela provoquera ou si cela ouvrira la porte aux attaquants.
C'est pourquoi les programmeurs doivent être extrêmement prudents lors de l'écriture de leur code, afin d'éviter les situations pouvant conduire à un comportement indéfini.
Débordements d'entiers dans d'autres situations
Nous avons discuté des débordements d’entiers en C pour vous donner un exemple plus concret, mais il s’agit en réalité d’un problème beaucoup plus vaste. Comme nous l'avons vu dans notre discussion sur C, une valeur qui dépasse l'espace qui lui est alloué peut soit se retourner, soit entraîner un comportement indéfini, ce qui peut entraîner de graves problèmes. Des problèmes similaires peuvent également survenir dans d’autres circonstances. Nous verrons rapidement comment les dépassements d'entiers sont traités dans certaines des situations les plus courantes :
Serrage
Dans certaines circonstances, les valeurs dépassant les limites peuvent être serré au lieu de passer par l'arithmétique modulaire. Le serrage signifie essentiellement que les valeurs sont restreintes afin qu'elles ne puissent être comprises qu'entre deux nombres prédéfinis. Ceci est également connu sous le nom de saturation.
Disons que les valeurs minimale et maximale sont les suivantes :
-32 768
+32 767 bits
Nous pourrions éviter les débordements d'entiers en limitant toutes les valeurs qui dépassent ce minimum ou ce maximum. A titre d'exemple, une opération peut donner une valeur de -32 770 bits. Cela dépasse la valeur minimale autorisée de 2 bits et pourrait donc entraîner un dépassement d'entier.
Si le programme avait été codé pour limiter les valeurs entre -32 678 et +32 767, les valeurs qui les dépassent sont limitées à ces minimums et maximums respectifs. Notre valeur de -32 770 bits serait limitée et stockée à la place sous la forme -32 678, ce qui empêcherait le débordement d'entier.
Cela fonctionnerait de la même manière si le résultat d’une opération était de +40 000. Le bridage entrerait en jeu et le résultat serait réduit au maximum, +32.767.
Lorsque les opérations produisent des résultats dont les valeurs sont comprises entre ces limites inférieure et supérieure, elles ne sont pas affectées par le verrouillage. Si une opération calculait une valeur de -25 342 ou +843, ces résultats ne seraient en aucun cas limités ou modifiés.
C#
Lorsqu'un débordement d'entier se produit dans C# , il s'enroule par défaut. Dans les contextes cochés, une OverflowException vous alerte du dépassement d'entier. Cela vous aide à découvrir les problèmes de logique dans votre programme. Si la vérification des débordements est définie par défaut, vous pouvez temporairement éviter ces vérifications à l'aide de l'option décoché mot-clé.
Java
En Java, le comportement par défaut en cas de dépassement d'entier est que les valeurs s'enroulent sans aucune indication manifeste. Il ne lève pas d'exception en cas de dépassement d'entier, ce qui peut rendre difficile la découverte de ces problèmes. Cependant, dès Java8 vous pouvez utiliserajouterExact()lever une exception si un dépassement d'entier se produit
Python
Les entiers en python ont précision arbitraire , ce qui signifie que des nombres arbitrairement grands peuvent être représentés. La seule limitation est la mémoire. Cela se traduit parErreur mémoireplutôt.
Cela signifie que les dépassements d’entiers ne se produisent normalement pas si les opérations sont uniquement effectuées en Python. Malgré cela, raisons historiques peut occasionnellement soulever uneErreur de débordementpour les entiers situés en dehors de la plage requise.
Les opérations effectuées dans la pile pydata peuvent entraîner des dépassements d'entiers, en raison des entiers de précision fixe impliqués. Opérations en virgule flottante ne sont généralement pas vérifiés, en raison de problèmes de standardisation liés à la gestion des exceptions à virgule flottante en C. En effet, les entiers à précision fixe de la pile pydata sont basés sur le langage de programmation C.
Évitement général des débordements d’entiers
Les bousculades, les comportements indéfinis et autres résultats sont tous indésirables, il est donc important d’éviter les débordements d’entiers en premier lieu. Avec les bonnes précautions, nous pouvons prévenir les débordements d’entiers, ainsi que les bugs et attaques potentielles auxquels ils peuvent conduire.
Pour commencer, les développeurs doivent attribuer à leurs variables des valeurs minimales et maximales suffisamment grandes pour pouvoir stocker toutes les valeurs possibles pouvant être calculées via une opération donnée.
Lorsque l'espace disponible est limité, les opérations doivent être ordonnées avec soin et les valeurs des variables nécessitent également une vérification approfondie. Ce processus doit inclure attention particulière à:
- Différences potentielles entre la représentation 32 bits et 64 bits.
- Écarts dans la taille des octets.
- Précision.
- Comment le langage utilisé gère les nombres trop petits ou trop grands pour les limites.
- Des calculs sans nombre.
En plus des mesures de prévention ci-dessus pour les débordements d'entiers, nous devrions également nous préoccuper de la question étroitement liée de conversions entières . Les conversions d'entiers se produisent lorsqu'un type d'entier est interprété comme un autre type. Lorsque l’entier source est interprété comme s’il s’agissait de l’entier de destination, cette valeur interprétée peut être très différente. Les conversions entières se répartissent en plusieurs sous-types différents :
- Troncations d'entiers — Il s'agit du cas où un entier plus grand est converti en un type entier avec une longueur plus courte, ce qui entraîne que la valeur la plus grande est tronquée à la longueur la plus courte. Seuls les bits les moins significatifs sont conservés, modifiant la valeur de l'entier. Lorsque la valeur n’est pas celle qu’elle devrait être, cela peut conduire à toutes sortes de résultats inattendus.
- Incohérences entre les entiers signés et non signés — Les erreurs de signature peuvent avoir des conséquences importantes. Nous avons déjà expliqué comment le chiffre le plus à gauche représente le signe du nombre dans le système du complément à deux, un 1 étant négatif et un 0 étant positif. Si un grand nombre non signé commence par un 1 et qu’il est mal interprété, il pourrait plutôt être considéré comme un nombre négatif, ce qui pourrait avoir des effets significatifs sur le résultat.
- Extension de signe — Cela peut se produire lorsqu'un entier signé est converti en une longueur de bits plus grande. Si le nombre d'origine est négatif, extension de signe peut conduire à des valeurs inattendues pouvant entraîner des complications.
Bien que ce qui précède ne conduise pas à des dépassements d'entiers, ils peuvent produire des erreurs qui doivent être corrigées pour garantir le bon fonctionnement du programme.
Détection des débordements d'entiers
Vous pouvez utiliser des outils d'analyse statique comme cppcheck pour vérifier les débordements d'entiers signés en C et C++. Tel outils d'analyse statique utiliser des techniques basées sur des contraintes ou une analyse des flux de données pour minimiser les faux positifs, ce qui donne lieu à des méthodes de détection très efficaces.
Autres techniques d'atténuation
En raison de la gravité des dépassements d’entiers, il est important d’en tenir compte. d'autres mesures pour les éviter :
- Développez le programme avec un langage limitant les débordements d'entiers, tel que Python. D'autres options consistent à utiliser un langage qui permet d'éviter plus facilement les débordements d'entiers, ou un langage qui vérifie automatiquement les limites.
- Utilisez une bibliothèque fiable qui prévient ces faiblesses ou les rend plus facilement évitables. IntegerLib pour C et C++, ou SafeInt pour C++ sont tous deux de bons exemples de bibliothèques qui permettent d'éviter plus facilement les conséquences inattendues liées aux dépassements d'entiers.
Débordements d'entier vs débordements de tampon
Débordements d’entiers et débordements de tampon sont des bugs quelque peu similaires. Comme nous l'avons dit, un dépassement d'entier se produit lorsque le résultat d'une opération est trop grand pour l'espace qui lui est alloué, provoquant soit un bouclage, un comportement indéfini ou d'autres erreurs.
Des débordements de tampon se produisent également à un niveau similaire. Cependant, au lieu de recommencer comme le compteur kilométrique d’une voiture, les débordements de tampon occupent l’espace voisin, écrasant les données légitimes.
Utilisons des exemples simplifiés pour montrer la différence entre les deux. Dans les deux cas, nous avons deux tampons de 8 octets l'un à côté de l'autre, stockant tous deux valeurs hexadécimales (ce ne sont que différentes manières de représenter les nombres binaires).
Exemple de dépassement d'entier
Tout d’abord, nous allons démontrer un débordement d’entier :
FFFFFFFF 87D9676E
Disons que le tampon de gauche va subir une opération où un 1 supplémentaire sera ajouté. Le tampon de droite stocke les données qui seront nécessaires à l'avenir.
Lorsque nous ajoutons le 1 au tampon de gauche, nous devrions obtenir le résultat suivant :
100 000 000 87D9676E
(Notez qu'en hexadécimal, FFFFFFFF agit de manière quelque peu similaire à 99999999 en décimal, donc l'ajout d'un un nous donne 1 00000000.)
Cependant, s'il n'y a que huit bits d'espace disponible et que nous rencontrons un débordement d'entier, le résultat pourrait impliquer un bouclage avec l'arithmétique modulaire, nous donnant par erreur une valeur de :
00000000 87D9676E
Cela pourrait également conduire à un comportement indéfini et à quelque chose d’étrange qui pourrait se produire. Quoi qu’il en soit, cela conduit à une faille et le développeur aurait dû faire quelque chose pour éviter que cela ne se produise.
Exemple de débordement de tampon
Regardons maintenant la même opération avec les deux mêmes tampons et le même ajout d'un seul 1 :
FFFFFFFF 87D9676E
Dans ce cas, disons que la vérification des limites est insuffisante et que l’opération déclenchera un débordement de tampon.
Encore une fois, on s'attendrait au résultat suivant :
100 000 000 87D9676E
Cependant, en raison de l’anomalie de débordement de tampon, nous nous retrouvons en réalité avec :
1000000017D9676E
Dans cet exemple, le résultat de l’opération ne s’est pas simplement déroulé comme l’a fait le dépassement d’entier. Au lieu de cela, le débordement de tampon a écrasé le premier caractère du registre de droite, remplaçant le 8 par un 1, ce qui modifie considérablement sa valeur.
Lorsque le système va utiliser les données dans le bon tampon, il ne pourra pas accéder à la valeur correcte, ce qui entraînera finalement une erreur.
Dans les situations où des débordements de tampon sont possibles, ils peuvent être exploités par des attaquants. Les pirates peuvent délibérément créer du code pour provoquer un débordement de tampon leur permettant d'écrire dans des zones adjacentes.
Lorsque les zones contenant du code exécutable sont écrasées par du code malveillant, un attaquant peut exécuter son propre code et tenter d'élever ses privilèges pour tenter d'accéder à l'ensemble du système.
Il est intéressant de noter que les débordements d’entiers peuvent en réalité conduire à des débordements de tampon . Si un dépassement d'entier se produit pour la variable qui détermine la longueur en bits du tampon, cela peut entraîner un bouclage qui produit un nombre beaucoup plus petit.
Lorsque cela rend le tampon trop petit pour les valeurs qui doivent y être stockées, les données débordent dans les tampons adjacents et écrasent les données. Cela signifie que les dépassements d’entiers peuvent entraîner des risques de sécurité très importants.
Attaques par débordement d'entier
L'un des principaux problèmes de dépassement d'entier est que un processus ne peut pas vérifier le résultat d'un calcul après qu'il a eu lieu , ce qui signifie qu'il ne peut pas déterminer s'il existe une différence entre ce que devrait être le résultat et le résultat stocké en raison de l'erreur de dépassement d'entier.
Cependant, débordements d'entiers ne permettent pas aux attaquants de diriger le contrôle du flux d’exécution, ni d’écraser de manière directe. En fin de compte, cela signifie que même si les dépassements d’entiers peuvent provoquer des erreurs importantes, les attaquants ne peuvent pas les exploiter dans la majorité des cas.
Malgré cela, il existe encore des cas dans lesquels des attaquants peuvent abuser des débordements d’entiers. Il s'agit notamment de situations dans lesquelles ils peuvent dépasser la variable de longueur de tampon, ce qui peut finalement entraîner un débordement de tampon, comme nous l'avons vu dans la section précédente.
Exemples d'attaques par débordement d'entier
Les débordements d’entiers ont été un élément d’une série d’attaques importantes. Certains d'entre eux incluent :
Un débordement d’entier a conduit au logiciel espion Pegasus sur le téléphone d’un activiste saoudien
En mars 2021, Le laboratoire citoyen examiné le téléphone d'un activiste saoudien. Citizen Lab est une organisation canadienne qui mène des recherches à la jonction entre les droits de la personne, la sécurité mondiale et les technologies de communication. Il mène des enquêtes de haut niveau et est réputé pour son travail de documentation des attaques sophistiquées contre des militants.
Dans ce cas, l'organisation a pu déterminer que le militant saoudien anonyme avait été infecté par le logiciel espion Pegasus du groupe NSO via un exploit sans clic . Cela signifie que le destinataire n’a même pas eu à cliquer sur le mauvais fichier ou lien pour que le malware s’exécute.
Qu’est-ce que le logiciel espion Pegasus et qui se cache derrière ?
Pegasus est l’un des exemples de logiciels de piratage les plus sophistiqués connus du public. Il peut être utilisé pour lancer des attaques beaucoup plus avancées que celles dont votre pirate informatique ordinaire est capable.
En effet, le groupe NSO, qui a créé Pegasus, dispose d’une équipe nombreuse et coordonnée de professionnels de la sécurité qui ont passé au crible les bogues des logiciels couramment utilisés. Plutôt que de les divulguer publiquement (comme on pourrait l'espérer d'une entreprise responsable), ils les regroupent dans des outils logiciels que le réclamations de l'entreprise fournir «… aux gouvernements autorisés une technologie qui les aide à lutter contre le terrorisme et la criminalité».
Même si cela peut être le cas dans certains cas, le groupe NSO a également été accusé d'autoriser ses outils à cibler les militants des droits de l'homme dans Mexique , Inde , et une foule d’autres pays. Il a également été accusé d'avoir joué un rôle dans la mort d'un autre dissident saoudien, Jamal Khashoggi .
Le fait est que Pegasus est un malware très sérieux, réputé pour ses vrilles dans des transactions louches et moralement répugnantes.
Le piratage du militant saoudien
Dans le cas de cet activiste saoudien anonyme, Citizen Lab a récemment réanalysé une sauvegarde iTunes qu'il avait réalisée de l'appareil.
Au cours de cette récente analyse, les enquêteurs ont découvert plus de 30 fichiers portant l'extension .gif dans leBibliothèque/SMS/Pièces jointes. Celles-ci ont été reçues juste avant l’infection du téléphone par le logiciel espion Pegasus.
Cependant, ces fichiers n’étaient pas réellement des gifs. Au lieu de cela, 27 d’entre eux étaient des fichiers Adobe PSD, ce qui a provoqué un crash d’IMTranscoderAgent sur l’appareil. Quatre des fichiers étaient en réalité des fichiers Adobe PDF contenant des flux codés en JBOG2.
Citizen Lab a remarqué que certains formats de fichiers correspondaient à des plantages qu'ils avaient précédemment observés sur un autre appareil piraté avec le logiciel espion Pegasus. Ils soupçonnaient que ces fichiers « .gif » contenaient des aspects de ce que Citizen Labs a surnommé le ENTRÉE FORCÉE exploiter la chaîne.
Cet exploit a profité d’une vulnérabilité de dépassement d’entier présente dans la bibliothèque de rendu d’images CoreGraphics d’Apple.
Apple publie un correctif de sécurité
Citizen Lab a envoyé ses conclusions à Apple en septembre, et en une semaine, Apple avait confirmé qu'il s'agissait d'un exploit zero-day affectant à la fois MacOS et iOS . La société a également émis un mise à jour de sécurité qui a corrigé la faille, pour l'empêcher d'être exploitable dans les versions futures.
La mise à jour d'Apple a révélé que « le traitement d'un PDF conçu de manière malveillante peut conduire à l'exécution de code arbitraire ». Il a également déclaré que la mise à jour corrigeait un dépassement d'entier avec une validation d'entrée améliorée.
Le CVE indique que le problème a été résolu dans « … Mise à jour de sécurité 2021-005 Catalina, iOS 14.8 et iPadOS 14.8, macOS Big Sur 11.6, watchOS 7.6.2 ».
Citizen Lab limite actuellement les informations techniques qu'il publiera sur l'exploit, peut-être pour éviter de faire savoir au groupe NSO quels aspects de sa chaîne d'exploit il a une compréhension.
Trac
En 2015, des chercheurs de Zimperium nouvelles publiées d'une famille de vulnérabilités dans la médiathèque d'Android, libstagefright . Le vecteur d'attaque impliquait des vulnérabilités de dépassement d'entier mises en œuvre dans le cadre du projet Android Open Source. et étaient impliqués dans la lecture de fichiers multimédias tels que les MP4.
L'un d'eux était un débordement d'entier dans libstagefright qui permettait aux attaquants d'exécuter du code à distance via des données MP4. Un autre dépassement d'entier dans libstagefright a permis aux attaquants de créer des données MPEG-4 qui exécuteraient à distance du code arbitraire.
Outre les autres vulnérabilités, la situation a permis aux attaquants d’élever leurs privilèges. L'un des aspects les plus effrayants de l'attaque était une preuve de concept qui montrait que des messages MMS soigneusement conçus pouvaient être envoyés à des appareils et que le code malveillant pouvait s'exécuter sans qu'aucune action de l'utilisateur final ne soit nécessaire.
Une autre préoccupation majeure impliquée La fragmentation d'Android .
Bien que Google ait déjà publié un correctif pour les derniers appareils Android au moment où le bug a été annoncé publiquement, des centaines de millions de personnes sont restées vulnérables à cet exploit en raison du grand nombre de fabricants de téléphones qui modifient le système d'exploitation Android et mettent ensuite des mois ou des années à transmettre les correctifs de sécurité nécessaires. .
Les utilisateurs ont pu profiter de certaines stratégies d'atténuation, telles que la désactivation du MMS, mais cette solution n'était guère valable pour de nombreux utilisateurs. En fin de compte, il s’agissait d’un grave problème de sécurité résultant de la manière complexe dont Android est distribué.
Attaques par débordement d'entier dans Microsoft Word
En 2018, le Équipe Mimecast détecté un groupe d'attaquants qui semblait avoir des origines serbes.
Le groupe était en train de créer des documents Microsoft Word pour exploiter les erreurs de dépassement d'entier dans la façon dont le traitement de texte gère le format de fichier OLE. Cela a permis au groupe de contourner les solutions de sécurité telles que les logiciels anti-malware et les technologies de sandboxing.
Mimecast a divulgué ses conclusions à Microsoft ainsi qu'une preuve de concept. Selon Mimecast, Microsoft a reconnu que le comportement découvert n'était pas intentionnel, mais a choisi de ne pas publier de correctif de sécurité à ce moment-là. Mimecast déclare que l’inaction de Microsoft est due au fait que le problème n’a pas provoqué l’exécution de code ni la corruption de la mémoire.
La vulnérabilité est due à un problème avec les en-têtes du format OLE. Lorsqu'il existe un identifiant de secteur important, la formule impliquée dans le calcul du décalage entraîne un dépassement d'entier.
Seuls les 32 bits de poids faible du décalage sont inclus, ce qui signifie que le décalage est beaucoup plus petit qu'il ne devrait l'être. Ce bogue pourrait être utilisé pour transmettre des charges utiles via des fichiers OLE, ce qui représentait une menace importante lorsqu'il était lié à d'autres vulnérabilités de Microsoft Word.
Les chercheurs ont remarqué une attaque impliquant l'exploitation de CVE-2017-11882 , qui est un bogue dans diverses versions de Microsoft Office Service Pack et de Microsoft Office 2016. Il s'agit d'une vulnérabilité de corruption de mémoire de Microsoft Office qui permet aux attaquants d'exécuter du code arbitraire, car il ne gère pas correctement les objets en mémoire. Microsoft a publié un correctif pour ce problème en 2017, l'attaque que nous décrivons n'a donc affecté que les versions qui n'étaient pas encore corrigées.
Les attaquants exploitaient CVE-2017-11882 avec un flux Equation Editor défini dans un objet OLE. Cet objet OLE utilisait le dépassement d'entier de l'ID de secteur, ce qui permettait au code malveillant de passer outre les solutions de sécurité sans être détecté.
La combinaison du dépassement d'entier avec l'exploit de l'éditeur d'équation a conduit Microsoft Word à ignorer les octets supérieurs de l'ID du secteur OLE. Il a ensuite chargé le code malveillant en mémoire, ce qui a laissé tomber une variante de Java JACKSBOT. Il s'agit d'une porte dérobée qui peut activer et infecter la cible chaque fois que Java est installé.
Si Java est installé et active JACKSBOT, cela peut avoir des conséquences dévastatrices. Il s'agit notamment de l'exécution de programmes, de l'exécution de commandes shell, de l'enregistrement des frappes au clavier, du vol de mots de passe mis en cache, etc.
Exploit du contrat intelligent Ethereum
En 2018, une startup de sécurité blockchain connue sous le nom de Bouclier Peck découvert une transaction inhabituelle. La société avait mis en place un système automatisé pour analyser les transferts de jetons basés sur Ethereum (ERC20) et pour envoyer des alertes chaque fois qu'elle découvrait un comportement anormal.
L'équipe a été accueillie par l'une de ces alertes le 22 avril. Il s’agissait de Beauty Chain (BEC), et sur deux transactions, un total de 8 000 000… (ce nombre est si grand qu’il contient un total de 63 zéros – pour le contexte, un milliard ne fait que 9 zéros)… 000 000 jetons ont été transférés .
Cryptolate indique que la pièce s'échange à 0,32 $ par jeton, mais malgré la valeur relativement faible de chaque jeton, le grand nombre d'entre eux en fait un nombre insondable.
PeckShield a commencé à examiner le code du contrat intelligent sous-jacent, qui indiquait que le transfert impliquait l'exploitation d'une vulnérabilité jusqu'alors inconnue dans le contrat.
La société a surnommé la vulnérabilité batchOverflow, qui implique un débordement d’entier en son cœur. La partie vulnérable du code se trouvait dans le transfert par lots. Le paramètre pour valeur pourrait être défini sur un nombre entier de 256 bits, ce qui correspond à peu près à la quantité totale de pièces transférées.
Cette variable pour valeur a été impliqué dans une formule pour calculer le montant . Parallèlement à d'autres mauvaises décisions de codage, le fait d'avoir un si grand nombre pour valeur a entraîné un débordement d'entier pour montant , ce qui le rend nul.
Ce montant La valeur zéro a permis à l'attaquant de passer les contrôles de sécurité, lui permettant ainsi de transférer les jetons.
Les chercheurs en sécurité ont trouvé plus d’une douzaine d’autres contrats ERC20 également vulnérables à batchOverflow. Bien qu’ils aient contacté les personnes impliquées dans les projets vulnérables, les principes d’Ethereum et le manque de mécanismes de réponse de sécurité existants ont rendu le processus difficile.
Un certain nombre d'échanges majeurs ont annoncé l'arrêt des dépôts de jetons ERC20 en réponse à cette vulnérabilité. Cela comprenait l'un des principaux échanges, OKEx. En fin de compte, ce bug de dépassement d’entier a porté un coup dur au marché plus large des crypto-monnaies, faisant chuter Ethereum de 664 $ à 612 $ au cours d’une période de 2020. seule journée .
Les attaques par débordement d’entier ne disparaîtront pas
Les attaques par débordement d’entier sont loin d’être nouvelles. Ces bugs sont présents dans les logiciels depuis longtemps et continueront de nous hanter dans le futur. Bien que des langages comme Python soient beaucoup plus résistants aux débordements d’entiers, ils sont loin d’être omniprésents.
En fin de compte, un utilisateur final ne peut pas faire grand-chose pour les éviter, à part peut-être essayer d'éviter les produits de développeurs peu recommandables.
La responsabilité de nous protéger incombe réellement aux programmeurs, et même si nous pouvons espérer que les gens se renseigneront et testeront leurs logiciels de manière plus approfondie, des erreurs continueront à être commises. Cela signifie que les dépassements d’entiers persistent, du moins pour le moment.