Je fais un cours au collège, où l'un des laboratoires est d'effectuer des exploits de dépassement de tampon sur le code qu'ils nous donnent. Cela varie de simples exploits comme la modification de l'adresse de retour d'une fonction sur une pile pour revenir à une fonction différente, tout le code qui modifie un enregistrement/état de la mémoire de programmes, mais revient à la fonction que vous avez appelée, ce qui signifie que le La fonction que vous avez appelée est complètement inconsciente de l'exploit.
J'ai fait des recherches sur cela, et ces types d'exploits sont utilisés à peu près partout, même maintenant, dans des choses comme - courir homebrew sur la Wii et le jailbreak non attaché pour iOS 4.3.1
Ma question est pourquoi ce problème est-il si difficile à réparer? Il est évident qu'il s'agit d'un exploit majeur utilisé pour pirater des centaines de choses, mais semble que ce serait assez facile à réparer en tronquant simplement toutes les entrées après la longueur autorisée et simplement assainir toutes les entrées que vous prenez.
Edit: une autre perspective que j'aimerais que les réponses envisagent - pourquoi les créateurs de C ne résoutent pas ces problèmes en réimpliquant les bibliothèques?
ils ont réparer les bibliothèques.
Toute bibliothèque standard C moderne contient des variantes plus sûres de strcpy
, strcat
, sprintf
, etc.
Sur les systèmes C99 - qui est la plupart des UNIXES - vous les trouverez avec des noms tels que strncat
et snprintf
, le "n" indiquant qu'il faut un argument de la taille d'un tampon ou d'un nombre maximal d'éléments à copier.
Ces fonctions peuvent être utilisées pour gérer de nombreuses opérations plus sécurisées, mais rétrospectivement, leur convivialité n'est pas géniale. Par exemple, des implémentations snprintf
ne garantissent pas que le tampon est résilié par NULL. strncat
prend un certain nombre d'éléments à copier, mais de nombreuses personnes transmettent à tort la taille du tampon Dest.
Sous Windows, on trouve souvent le strcat_s
, sprintf_s
, le suffixe "_s" indiquant "sûr". Celles-ci ont également trouvé leur chemin dans la bibliothèque standard C en C11 et offrent plus de contrôle sur ce qui se passe en cas de débordement (troncature vs d'assert par exemple).
De nombreux vendeurs fournissent des alternatives encore plus standard telles que asprintf
dans le GNU LIBC, qui allouera automatiquement un tampon de la taille appropriée.
L'idée que vous pouvez "juste réparer c" est un malentendu. La fixation C n'est pas le problème - et a déjà été fait. Le problème est de fixer des décennies de code C écrits par des programmeurs ignorants, fatigués ou précipités, ou du code porté des contextes où la sécurité n'a pas d'importance pour les contextes où la sécurité fait. Aucune modification de la bibliothèque standard ne peut corriger ce code, bien que la migration vers des compilateurs plus récents et des bibliothèques standard puissent souvent aider à identifier les problèmes automatiquement.
Il n'est pas vraiment inexact de dire que c est en fait "Erreur-Pausse" par Conception. Mis à part des erreurs grelles comme gets
, le langage C ne peut pas vraiment être une autre solution sans perdre la caractéristique principale qui attire les gens à C en premier lieu.
C a été conçu comme une langue des systèmes pour agir comme une sorte d'assemblage portable ". Une caractéristique majeure du langage C est que, contrairement aux langues de niveau supérieur, C code C est souvent très étroitement au code de la machine. En d'autres termes, ++i
est généralement juste une instruction inc
, et vous pouvez souvent obtenir une idée générale de ce que le processeur fera à l'exécution en regardant le code C.
Mais l'ajout de la vérification des limites implicites ajoute beaucoup de frais généraux supplémentaires que le programmateur n'a pas demandé et pourrait ne pas vouloir. Ces frais généraux vont bien au-delà du stockage supplémentaire requis pour stocker la longueur de chaque matrice ou les instructions supplémentaires pour vérifier les limites de la matrice sur chaque accès au tableau. Qu'en est-il de l'arithmétique du pointeur? Ou si vous avez une fonction qui prend une fonction dans un pointeur? L'environnement d'exécution n'a aucun moyen de savoir si ce pointeur tombe dans les limites d'un bloc de mémoire légitimement attribué. Afin de suivre une trace de cela, vous auriez besoin d'une architecture d'exécution sérieuse qui peut vérifier chaque pointeur contre une table des blocs de mémoire actuellement alloués, à quel point nous entrons déjà dans le territoire d'exécution Java/C # -Style géré.
Je pense que le vrai problème n'est pas que ces types de bugs sont difficiles à réparer, mais qu'ils sont si faciles à faire: si vous utilisez strcpy
, sprintf
et amis dans le (apparemment ) La manière la plus simple qui puisse fonctionner, alors vous avez probablement ouvert la porte pour un débordement tampon. Et personne ne le remarquera que lorsque quelqu'un l'exploite (sauf si vous avez de très bons critiques de code). Ajoutez maintenant le fait qu'il existe de nombreux programmeurs médiocres et qu'ils sont sous la pression du temps la plupart du temps - et vous avez une recette pour le code qui est tellement criblé Avec la mémoire tampon débordent que ce sera difficile de les réparer tout simplement parce qu'il y en a beaucoup d'entre eux et qu'ils se cachent si bien.
Il est difficile de corriger les débordements de mémoire tampon car c ne fournit pratiquement aucun outil utile pour résoudre le problème. C'est une faille de langage fondamentale que les tampons natifs ne fournissent aucune protection et C'est pratiquement, sinon complètement, impossible de les remplacer par un produit supérieur, comme C++ l'a fait avec std::vector
et std::array
, et C'est difficile, même sous le mode de débogage, de trouver des débordements tampons.
Le problème n'est pas avec le C langue.
IMO, le principal obstacle majeur à surmonter est que c est tout simplement simple mal enseigné. Des décennies de mauvaises pratiques et de mauvaises informations ont été institutionnalisées dans des manuels de référence et des notes de conférence, empoisonnant les esprits de chaque nouvelle génération de programmeurs dès le début. Les étudiants reçoivent une brève description de fonctions d'E/S "faciles" telles que gets
1 ou scanf
puis laissé à leurs propres appareils. Ils ne leur sont pas dit où ou comment ces outils peuvent échouer ou comment prévenir ces échecs. Ils ne leur sont pas informés d'utiliser fgets
et strtol/strtod
Parce que ceux-ci sont considérés comme des outils "avancés". Ensuite, ils ont déclenché sur le monde professionnel pour faire de leurs ravages. Pas que bon nombre des programmeurs les plus expérimentés connaissent mieux, car ils ont reçu la même éducation endommagée par le cerveau. C'est fouensif. Je vois tellement de questions ici et sur le débordement de la pile et sur d'autres sites où il est clair que la personne qui demande la question est enseignée par une personne qui tout simplement ne sait pas ce qu'ils parlent de et de Bien sûr, vous ne pouvez pas simplement dire "votre professeur a tort", car il est professeur et que vous êtes juste un gars sur Internet.
Et puis vous avez la foule qui dédaigne toute réponse commençant par: "Eh bien, selon la norme de langue ..." Parce qu'ils travaillent dans le monde réel Et selon eux, la norme ne s'applique pas au monde réel . Je peux traiter avec quelqu'un qui a juste une mauvaise éducation, mais quiconque insiste sur son ignorant est juste une brûlure de l'industrie.
Il n'y aurait pas de problèmes de dépassement de tampon si la langue a été enseignée correctement en mettant l'accent sur la rédaction de code sécurisé. Ce n'est pas "difficile", ce n'est pas "avancé", c'est juste être prudent.
Oui, cela a été une déclaration.
Le problème est le plus important de l'incompétence de programmeur. N'oubliez pas que une application de 90 000 lignes nécessite uniquement ne Fonctionnement d'insécurité pour être Complètement Insécurité. Il est presque au-delà des domaines de la possibilité que toute application écrite au-dessus de la manipulation des chaînes fondamentalement insécurie sera 100% parfaite - ce qui signifie qu'il sera peu sûr.
Le problème est que les coûts d'insécurité ne soient pas facturés au bon destinataire (la société qui vendant l'application n'aura jamais à rembourser le prix d'achat) ou n'est pas clairement visible au moment des décisions de temps ("Nous devons expédier en mars, peu importe quoi! "). Je suis assez certain que si vous avez factorté les coûts à long terme et les coûts à vos utilisateurs plutôt qu'à votre entreprise, l'écriture en C ou les langues connexes serait beaucoup plus chère, probablement si cher que c'est clairement le mauvais choix de nombreux Les domaines où de nos jours, la sagesse conventionnelle dit que c'est une nécessité. Mais cela ne changera que si beaucoup de responsabilité logicielle plus stricte est introduite - que personne ne veut dans l'industrie.
L'une des grandes puissances de l'utilisation de C est qu'il vous permet de manipuler la mémoire de la manière dont vous voyez.
L'une des grandes faiblesses de l'utilisation de C est que cela vous permet de manipuler la mémoire de la manière que vous voyez en forme.
Il existe des versions sécuritaires de toutes les fonctions dangereuses. Cependant, les programmeurs et le compilateur n'appliquent pas strictement leur utilisation.
pourquoi les créateurs de C ne résoutent-ils pas ces problèmes en réinitialisant les bibliothèques?
Probablement parce que C++ l'a déjà fait et est compatible vers l'arrière avec le code C. Donc, si vous souhaitez un type de chaîne de sécurité dans votre code C, vous utilisez simplement STD :: String et écrivez votre code C à l'aide d'un compilateur C++.
Le sous-système de mémoire sous-jacent peut aider à prévenir les débordements de mémoire tampon en introduisant des blocs de protection et la vérification de la validité - de sorte que toutes les allocations ont 4 octets de "FEFEFEFE" ajoutés, lorsque ces blocs sont écrits, le système peut lancer un wobbler. Ce n'est pas garanti d'empêcher une mémoire de mémoire, mais cela montrera que quelque chose a mal tourné et doit être corrigé.
Je pense que le problème est que les anciennes routines de Strcpy etc. sont toujours présentes. S'ils ont été retirés en faveur de Strncpy, etc., cela aiderait.