Il est parfois difficile de trouver un bon sujet d'article, je peux y
passer des heures. Je pensais en voir trouvé un excellent, le sujet
était « La vie des chiens chez les Inuits ». Mais on m'a dit, que le
sujet était un peu trop polémique, et pas assez fédérateur. Qu'à cela
ne tienne, un nouveau brainstorming avec moi-même. Puis... Bon dieu, mais
c'est bien sûr...
L'Idée, le Sujet sans qui la sécurité informatique ne serait pas vraiment ce qu'elle est. LA vulnérabilité, LA faille... en deux mots, Buffer Overflow (ou dans la langue de Victor Hugo, le dépassement de tampon). « Bue feur oh vert flot, kezako ? ». Pas d'insultes, s'il vous plait... Ce n'est pas un bon sujet ? Tout logiciel passé ou à venir aura au moins une vulnérabilité de type buffer overflow, ceci est un axiome qui peut même se démontrer (c'est dire) vu la complexité grandissante des logiciels. Ceci est la conséquence directe de la non validation de la longueurs des tampons mémoires ou de la non vérification des données copiées dans ce tampon.
Un exemple simple
Char buf [100] ;
...
Buf [101] = 'dommage' ;
Dans ce cas, tout à fait correct pour le compilateur d'un point de vue syntaxe, on crée un débordement sur... on ne sait pas, une partie de la mémoire, qui peut entrainer un plantage du programme, et une possibilité (ceci est à définir) de prendre le contrôle de la machine entière. Pourtant, ce type d'erreur pourrait être aisée à annihiler, il est « facile » de contrôler les variables, il suffit d'avoir les bonnes pratiques de programmation. Plus « facile » à dire qu'à faire à en croire la pratique et la réalité.
Afin de mieux comprendre pourquoi ce dépassement peut être un problème, il faut se rappeler comment un système d'exploitation gère sa mémoire. Chaque programme a besoin de mémoire pour fonctionner, et en gros la mémoire est divisé en trois parties :
Seulement voilà les deux dernières parties sont gérées dynamiquement, la file s'étend en commençant par les adresses basses, la pile fait exactement le contraire. Et ce qui peut arriver arrive, si l'on passe un argument trop gros à la pile, il sera traité, et ira donc dans la file, et débordera sur la mémoire allouée à la pile, dans ce cas, le pointeur de pile est modifié, donc l'adresse de retour est modifiée, donc fini le programme... L'attaque la plus simple se rapproche donc d'un deni de service du programme. Mais elle peut être plus ambitieuse, on peut positionner dans la pile une adresse de retour correspondant au petit programme malicieux qui permettra de prendre le contrôle. Je ne m'appesantirai pas sur la façon de faire, il existe sur Internet une littérature abondante sur ce sujet, par exemple « Smash the Stack for Fun and Profit que vous trouverez sur http://www.phrack.org) .
Il existe bien des méthodes à postériori pour essayer d'éviter cette plaie, comme des audits de code par exemple, ou une meilleure protection des systèmes grâce à des HIPS. Mais, il faut le répéter ce ne seront que des rustines, la seule méthode fiable est de sensibiliser à la sécurité les programmeurs, c'est-à-dire à l'amont de tout projet de développement. Afin qu'ils puissent contrôler tous les types d'entrée de variables du programme (soit par saisie directe, soit par passage de paramètre à la pile).
L'Idée, le Sujet sans qui la sécurité informatique ne serait pas vraiment ce qu'elle est. LA vulnérabilité, LA faille... en deux mots, Buffer Overflow (ou dans la langue de Victor Hugo, le dépassement de tampon). « Bue feur oh vert flot, kezako ? ». Pas d'insultes, s'il vous plait... Ce n'est pas un bon sujet ? Tout logiciel passé ou à venir aura au moins une vulnérabilité de type buffer overflow, ceci est un axiome qui peut même se démontrer (c'est dire) vu la complexité grandissante des logiciels. Ceci est la conséquence directe de la non validation de la longueurs des tampons mémoires ou de la non vérification des données copiées dans ce tampon.
Un exemple simple
Char buf [100] ;
...
Buf [101] = 'dommage' ;
Dans ce cas, tout à fait correct pour le compilateur d'un point de vue syntaxe, on crée un débordement sur... on ne sait pas, une partie de la mémoire, qui peut entrainer un plantage du programme, et une possibilité (ceci est à définir) de prendre le contrôle de la machine entière. Pourtant, ce type d'erreur pourrait être aisée à annihiler, il est « facile » de contrôler les variables, il suffit d'avoir les bonnes pratiques de programmation. Plus « facile » à dire qu'à faire à en croire la pratique et la réalité.
Afin de mieux comprendre pourquoi ce dépassement peut être un problème, il faut se rappeler comment un système d'exploitation gère sa mémoire. Chaque programme a besoin de mémoire pour fonctionner, et en gros la mémoire est divisé en trois parties :
- La mémoire fixée pour le programme qui contient le code lui-même, des données statiques
- La file (heap) qui est utilisée pour stocker les données dynamiques
- La pile utilisée pour passer des variables aux fonctions ou à d'autres programmes
Seulement voilà les deux dernières parties sont gérées dynamiquement, la file s'étend en commençant par les adresses basses, la pile fait exactement le contraire. Et ce qui peut arriver arrive, si l'on passe un argument trop gros à la pile, il sera traité, et ira donc dans la file, et débordera sur la mémoire allouée à la pile, dans ce cas, le pointeur de pile est modifié, donc l'adresse de retour est modifiée, donc fini le programme... L'attaque la plus simple se rapproche donc d'un deni de service du programme. Mais elle peut être plus ambitieuse, on peut positionner dans la pile une adresse de retour correspondant au petit programme malicieux qui permettra de prendre le contrôle. Je ne m'appesantirai pas sur la façon de faire, il existe sur Internet une littérature abondante sur ce sujet, par exemple « Smash the Stack for Fun and Profit que vous trouverez sur http://www.phrack.org) .
Il existe bien des méthodes à postériori pour essayer d'éviter cette plaie, comme des audits de code par exemple, ou une meilleure protection des systèmes grâce à des HIPS. Mais, il faut le répéter ce ne seront que des rustines, la seule méthode fiable est de sensibiliser à la sécurité les programmeurs, c'est-à-dire à l'amont de tout projet de développement. Afin qu'ils puissent contrôler tous les types d'entrée de variables du programme (soit par saisie directe, soit par passage de paramètre à la pile).
Les buffer overflows c'est limite has been quand même...
L'avenir c'est les SQL Injections !
Dire qu'en plus j'ai joué à ce jeu débile. Heureusement que j'utilise un autre mot de passe pour les jeux que celui de ma messagerie.
D'ailleurs j'utilise aussi une autre messagerie pour les jeux...
Dans les cours sur l'architecture des données on parlait bien de "pile" pour le "stack", mais de "tas" pour le "heap". C'est une pile aussi : Last in first out (LIFO). Une file a un comportement différent : first in first out (FIFO).
Quand on dépasse la taille d'un tampon dans la pile, on écrase ce qui précède à cause de l'empilement et du sens d'écriture des données.
La pile gérant l'adresse de retour pour sortir d'une fonction, il est possible de l'écraser.
On peut alors redirigé le programme sur une portion de code qu'on a écrite dans le tampon (payload). On peut aussi rediriger sur des fonctions standards du système. Le but étant de prendre la main sur le serveur.
Un audit de code a posteriori peut permettre justement la sensibilisation des développeurs en leur expliquant les bonnes pratiques à utiliser. Mais il est vrai qu'un audit ne trouvera pas l'exhaustivité des erreurs.
Des méthodes existent au niveau des systèmes d'exploitation pour randomiser les adresses des fonctions et bien d'autres choses.
Mais bien sûr si les programmes sont mal codés... ces fonctions ne sont pas activables.
De même pour les instructions à activer lors de la compilation comme pour rajouter des canaris ou la protection d'exécution dans les données (notre fameuse payload). Un développeur qui utilise toujours strcat ne sait pas forcément comment activer les paramètres derniers cris pour protéger ses applications.
Les buffer overflow sont loin d'être has been. Il suffit de lire les alertes pour s'en rendre compte! Il y en a des nouveaux de découvert toutes les semaines si ce n'est tous les jours...
Un point souvent oublié sur la présence de failles dans le développement d'applications
(que ce soit pour les buffers, les stacks et autres overflow, comme pour les injections SQL et autres XSS) est la pression "économique" sur le développement.
Tant que la gestion de projet n'intègre pas de Q&A sécurité (en terme de budget,planning, ressource etc...) il n'y aura pas de progrès.
Tant que le commanditaire (interne ou en sous-traitance) n'intègre pas de volet sécurité, il n'y aura pas de progrès
On retrouve trop souvent ces erreurs dans les projets gagnés sur appel d'offre, les cycles courts etc...
Il est sincèrement pas trivial de coder proprement et de rentrer dans les temps projets.
Il ne faut pas remettre en question uniquement les méthodes des développeurs mais c'est toute la chaine de création d'une application qui doit intégrer un volet sécurité.
pour faire bref et marketing ;)
La sécurité c'est l'affaire de tous
C'est aussi pour cela, que je préfère traduire heap par file(c'est une file particulière).
Pour moi, pile = LIFO et file = FIFO.
pour le reste, je suis tout à fait d'accord avec toi.
Je ne suis pas sûr du côté has been du buffer overflow.
Le sql injection on peut le contrôler un peu plus facilement
Tout à fait d'accord.
Cela fait d'ailleurs une excellent conclusion.
En effet j'ai une lacune au niveau du tas. Il s'agit en fait d'une liste doublement chaînée avec réallocation des espaces libérés. C'est beaucoup plus complexe que je ne l'imaginais. Du coup j'ai trouvé un texte intéressant sur le sujet.
Le coup des BOF c'est has been c'est pour montrer qu'il y a deux écoles (si ce n'est plus). Disons que c'est plutôt old school (même si je risque encore de me faire critiquer :).