Les audits de codes sont un exercice souvent peu apprécié des pentesters ou des auditeurs. En effet, pourquoi chercher à comprendre le code d’une application lorsqu’il est beaucoup plus simple d’effectuer directement des attaques sur celle-ci ? Ces audits permettent en réalité à un pentester d’obtenir une vision beaucoup plus approfondie du périmètre de tests et par conséquent de fournir un travail plus pertinent.
Mes débuts dans le monde de la sécurité
J’ai effectué mon premier audit de code bien avant d’intégrer Advens, en 2013, au tout début de ma vie professionnelle. À cette époque, mon travail consistait à évaluer la résistance de carte à puces, par exemple des cartes bancaires, face à certains types d’attaques.
Les tests réalisés sur ces cartes sont malheureusement un peu trop compliqués à expliquer en quelques lignes, et ne sont de plus pas le sujet qui nous intéresse ici. Mais pour résumer de manière très simplifiée, une carte contient des données qui sont secrètes et qui doivent le rester si l’on veut éviter la fraude. Le but des attaques était alors de tenter de retrouver ces données à l’aide d’oscilloscopes, et de divers outils qu’il n’est pas nécessaire d’expliquer ici.
Ce qu’il est néanmoins important de mentionner, c’est que les attaques ainsi réalisées nécessitaient des heures d’analyses, de préparation, et des jours de tests pour espérer retrouver au moins une petite partie de ces données secrètes tant convoitées. Mais surtout, ce qu’il faut retenir ici est qu’une mauvaise préparation pouvait mener à des résultats négatifs même si la cible était vulnérable.
Mais du coup, comment pouvait-on savoir si le périmètre de test était bel et bien robuste, ou si notre préparation n’était tout simplement pas adéquate ?
Et bien, un audit était systématiquement réalisé sur le code source de l’application installée sur la carte, en amont des tests. Ainsi les vulnérabilités liées au code étaient connues des analystes, et même si les résultats des attaques dépendaient d’autres paramètres, cela permettait de mieux les préparer.
Mon premier audit de code
Pour être honnête, ce premier audit était pour moi une source d’extrême appréhension. En effet, je voyais mal comment réussir à comprendre le code qu’une personne avait passé des mois, des années à implémenter, en quelques jours et de surcroît y trouver des défauts.
Et pour compliquer les choses, le code était en assembleur. Pour ceux qui ne sont pas familiers avec l’assembleur, je peux seulement vous dire que vous avez de la chance. Auditer un code dans un langage non familier peut déjà être un exercice difficile, mais auditer un code en assembleur est un tout autre problème si on n’en a pas l’habitude.
Heureusement j’étais accompagnée par une personne plus expérimentée lors de cet audit, et le code était bien commenté. Le client était de plus honnête lors de ses explications et compréhensif, ce qui a finalement rendu l’analyse surmontable.
Malgré la réussite de cette mission, l’appréhension et la peur de ne pas réussir à comprendre le code ou de ne pas retrouver de vulnérabilités est restée pendant un moment. Mais à force d’effectuer ce type d’exercice, je me suis rendu compte qu’il existait de nombreuses similarités entre les différents codes, et après quelques années d’expérience, l’exercice est devenu de plus en plus simple.
Les leçons tirées de ces premiers audits
En vérité, même si les attaques réalisées sur des cartes à puces sont très différentes d’un test d’intrusion sur une application plus classique, ou un autre périmètre, l’état d’esprit est exactement le même. Le but ultime est de retrouver des vulnérabilités qu’un attaquant pourrait exploiter afin de pouvoir renforcer la sécurité sur le périmètre ciblé.
Comme mentionné précédemment, les attaques réalisées dans le cadre des évaluations sur les cartes à puces nécessitent un temps de préparation non négligeable, une bonne partie étant passé à essayer d’obtenir le meilleur signal possible sur l’oscilloscope et à retrouver la zone où se trouve la cible. En réalité, sans connaissance du code, cette étape indispensable de la préparation des tests est presque impossible. Il est en effet compliqué de tenter de cibler une toute petite zone théoriquement vulnérable sans comprendre ce qui est affiché sur l’oscilloscope.
Aujourd’hui, grâce à ces audits de codes réalisés dans une vie antérieure, je peux voir un parallèle entre cette préparation extrêmement sensible et dépendante d’une connaissance approfondie du code, avec certaines des attaques que l’on réalise régulièrement en tant que pentester.
Pourquoi auditer le code d’une application web
Prenons l’exemple d’une application web. À première vue, contrairement aux cartes à puce, il est très facile de comprendre ce que l’on a en face de soi lorsque l’on commence un test. Tout le monde a déjà navigué sur un site web, tout est normalement fait pour que l’utilisateur puisse facilement comprendre ce qu’il peut réaliser comme action dessus. Un pentester n’aura donc en théorie aucune difficulté à explorer le site ciblé et à en définir les possibilités d’attaques.
Oui, mais voilà, la réussite de certaines attaques dépend fortement de la manière dont sont codées les applications. En fonction du langage utilisé, des fonctions favorisées par les développeurs, une même attaque pourra ne pas fonctionner, ou au contraire, permettre au pentester d’obtenir un accès complet aux données confidentielles manipulées par l’application.
Sans connaissance du code, le pentester pourra lancer des attaques génériques, ou tenter différentes actions spécifiques à plusieurs langages ou fonctions différentes, et obtenir de temps en temps des résultats. Car il est vrai que les tests d’intrusion seuls, n’étant par définition pas exhaustifs, permettent parfois de retrouver des vulnérabilités critiques sur un site web, ceci n’est pas contestable. Mais les résultats des tests peuvent être davantage pertinents lorsque ceux-ci sont accompagnés d’un audit de code.
De la même manière que ces audits me permettaient d’interpréter ce que j’observais sur l’oscilloscope, dans le cadre de l’évaluation de carte à puces, ceux-ci aident le pentester à comprendre ce qu’il a devant lui, pas seulement la partie visible du site web, mais tout le mécanisme derrière celui-ci. Ainsi, il pourra fournir un travail beaucoup plus exhaustif en ciblant plus précisément les zones réellement vulnérables.
Mais les pentesters ne sont pas les seuls à bénéficier de la réalisation de ces deux types de missions conjointement. En effet, les auditeurs peuvent aussi gagner en confiance vis-à-vis de la compréhension du code, qui est une étape primordiale afin de pouvoir retrouver des vulnérabilités pertinentes dans le contexte applicatif. Aussi, la possibilité de vérifier si une vulnérabilité est réellement exploitable, dans des conditions réelles, permet de mieux juger du niveau de criticité de la faille et ainsi d’adapter les recommandations faites aux clients.
De plus, les connaissances techniques qu’apportent les audits de code à ceux qui les réalisent sont non négligeables. Il est aussi extrêmement enrichissant de pouvoir observer l’envers du décor, d’apprendre comment fonctionnent réellement les applications que l’on peut utiliser dans la vie de tous les jours.
Même si les audits de code ne sont à première vue pas attirants, les bénéfices liés à la réalisation de tels audits conjointement aux tests d’intrusion sont réels, tant pour les auditeurs que pour les pentesters. Cette approche complète est notamment intéressante pour des périmètres critiques, exposés sur internet et manipulant des données sensibles. Ces audits permettent de mieux accompagner les clients dans leurs démarches de sécurisation de leurs applicatifs, en leur soumettant des résultats pertinents prenant en considération l’intégralité du contexte de l’application.