Pourquoi les injections SQL existent-elles toujours ?

Encore dans la tête du classement de l’OWASP des dix vulnérabilités les plus courantes en 2020. Les injections SQL (aussi abrégées « SQLi » dans le domaine de la sécurité informatique) représentent, 23 ans après leur apparition au grand public, toujours une menace bien réelle sur les applications web. Comment expliquer leur persistance alors que l’utilisation de Framework embarquant des ORM (object-relational mapping, interface entre l’applicatif et la base de données), se démocratise, que PHP implémente PDO et ses requêtes préparées depuis 2004. Alors comme se fait-il qu’il soit possible d’injecter en 2021 ? Mauvaise formation des développeurs ? Applications non mises à jour ? Défaillances techniques ?

Au commencement

Le principe des injections SQL commence à être évoqué publiquement au cours de l’année 1998. Un article du magazine phrackl relate très clairement la méthodologie d’une attaque SQL sur un serveur MS-SQL 6.5. Durant la décennie suivante, ces exploitations se multiplient et commencent à faire les gros titres des médias spécialisés en sécurité informatique. En 2002 Jeremiah Jacks dérobe les coordonnées et identifiants bancaires de 200 000 personnes grâce à une injection SQL sur le site de Guess.com. En 2005 une faille de sécurité dans un site d’information taiwanais permet à un étudiant de dérober des informations sensibles des clients.

Un exemple simple d’injection pourrait se présenter ainsi. Une requête sélectionnant l’intégralité des disques appartenant à une catégorie définie par une variable provenant d’une entrée utilisateur.

//la variable est définie ainsi :
$category = "jazz";
$sql = "SELECT * FROM disques WHERE dispo = 1 AND category = ".$category;
// Après sa generation la requête se présente ainsi
$result = mysql_query($sql) ;
SELECT * FROM disques WHERE dispo = 1 AND category = 'Jazz'

Si on modifie la chaîne de caractères ‘Jazz’ on peut modifier la requête pour obtenir plus que la simple liste des disques.

//la variable est redéfinie ainsi :
$category = "jazz ' UNION SELECT username,password FROM USERS --";
$sql = "SELECT * FROM disques WHERE dispo = 1 AND category = ".$category;
// Après sa génération la requête se présente ainsi
SELECT * FROM disques WHERE dispo = 1 AND category = 'Jazz' UNION SELECT username, password FROM USERS --

Le résultat de cette requête sera effectivement la liste des disques de la catégorie Jazz, mais également la liste des utilisateurs et leurs mots de passe.

À la fin de la décennie 2000, cette méthode est bien connue et continue de faire davantage de dégâts. Avec la professionnalisation des groupes de cybercriminels, les cibles sont maintenant de véritables consortiums. À l’instar de Sony en 2011, victime d’une attaque par injection, attribuée au groupe LulzSec, pas moins d’un million d’informations clientes seront dérobées, comprenant entre autres mot de passe ou des clefs d’activation.

Comment expliquer leur persistance ?

‘Parce que ça marche’ déclarait Tim Erlin directeur de la sécurité informatique et de la stratégie des risques pour Tripwire. En effet, l’injection est systématiquement recherchée par un attaquant, car si son exploitation est possible sur la cible elle est souvent d’une efficacité redoutable pour un temps de travail relativement court. Au-delà, de l’explication légèrement évidente de Tim Erlin, il existe plusieurs réalités.

Des raisons techniques

Le piège de l’ORM

L’ORM pour le développeur Web est la sacro-sainte certitude d’éviter les injections SQL dans son application. Encore faut-il que son utilisation soit correcte et l’outil maintenu à jour dans le temps. En 2016, la possibilité d’injection de requête SQL dans un ORM des bibliothèques NPM, « Sequelize », pour NodeJS a été découverte. Rapidement patchée, la vulnérabilité reste présente sur toutes les architectures n’ayant pas mis à jour leurs paquets.

Le fondateur de Snyk (entreprise de Cybersécurité spécialisée dans le développement) Guy Podjarny rappelle deux règles de la sécurité applicative, tester les variables provenant d’une entrée utilisateur même si on utilise un ORM et l’application d’un modèle positif, c’est-à-dire en appliquant une liste d’autorisation à une variable et non une liste d’exclusion, celle-ci n’étant jamais exhaustive.

Exemple d’une vulnérabilité de Sequelize

Comme indiqué plus haut, plusieurs possibilités d’injections SQL furent découvertes dans l’ORM Sequelize. Un exemple de vulnérabilité sur cet ORM était la concaténation directe de l’instruction « IN » avec ses valeurs associées.

Ici, l’instruction recherche les utilisateurs possédant un « username » présent dans un tableau. Le problème est qu’il est possible d’injecter du code dans une des valeurs du tableau passé en paramètre de la requête.

db.query('SELECT id, username FROM Users WHERE Username IN (:names)', {  replacements: {
names: ["Bobby", "') UNION SELECT email, password FROM Users WHERE Username = 'admin';--')"]
}
} ) ;

Cette vulnérabilité découverte en 2016 a été patchée très rapidement. Cependant, rien n’indique que les ORM que nous utilisons aujourd’hui ne seront pas affectés par une telle découverte dans le futur. Protéger ses variables d’entrée est donc nécessaire.

Mauvaise utilisation de l’ORM

Au-delà d’une vulnérabilité présente au niveau de l’ORM dans la formation de la requête, ce qui n’est en soi pas de la responsabilité du développeur l’utilisant, il est possible de voir une mauvaise utilisation des outils de l’ORM. Pire, se sentant protégé par l’outil magique contre les injections, le développeur écrit son code, nonobstant de protéger ses variables d’entrées.

Par exemple, avec Doctrine, utilisée comme ORM de Symfony, l’« Entity Manager » implique d’utiliser les méthodes natives, find(), findById(), where().

Cependant, il est possible d’utiliser la méthode createQuery() utilisant la syntaxe « Doctrine Query Language » (DQL). Cette dernière, plus proche de la syntaxe SQL est plus facile à lire et plus simple d’utilisation pour des requêtes complexes. Cependant elle ouvre la porte au risque d’injection si elle n’est pas correctement utilisée.

Nous partons du principe que $id proviens d’une donnée saisie par un utilisateur (un paramètre d’URL, formulaire, etc.).
Pour une entité « IP » ne possédant qu’une seule entrée d’ID 1.

// première méthode

$id = « 2 OR 1 = 1 »;
$em = $this->getDoctrine()->getManager();
$query = $em->createQuery(
       ‘SELECT i
       FROM App\Entity\Ip i
       WHERE i.id = :id’
   )->setParameter(‘id’, $id);
$ret1 =  $query->getResult();
var_dump($ret1);


// deuxième méthode

$queryb = $em->createQuery(
      « SELECT i
       FROM App\Entity\Ip i
       WHERE i.id = « .$id
   );
$ret2 =  $queryb->getResult();
var_dump($ret2);


Le paramètre étant préparé sur la première méthode, l’injection n’est ici pas possible. Le résultat du var_dump de la méthode 1 renvoi correctement :

array(0) { }

La deuxième méthode concatène la variable ID, et le DQL se comporte comme une simple requête SQL, non préparée, non sécurisée. Le var_dump retourne l’intégralité de la table (ici une seule entrée).
array(1) { [0]=> object(App\Entity\Ip)#664 (1) { [« id »: »App\Entity\Ip »:private]=> int(1) [« ip »: »App\Entity\Ip »:private]=> string(9) « 127.0.0.1 » [« tmstmp »: »App\Entity\Ip »:private]=> string(10) « 1582310418 » } }

Un audit de code permet de vérifier que les bonnes pratiques en matière de sécurité sont respectée.

Des défauts de configuration de système de gestion de base de données

Au-delà de leur persistance, il faut également noter les dégâts désastreux qu’engendrent les SQLi. Randall Agee, CEO de Allshore Global Resources pointe du doigt l’architecture mise en place. En effet, l’absence de cloisonnement entre les différentes bases de données présentes sur un même serveur peut permettre une escalade de privilèges.

En démonstration, nous pouvons imaginer plusieurs sites hébergés sur une même machine de type Unix, utilisant les services Apache et MySQL. Il arrive parfois qu’il n’existe qu’un seul utilisateur MySQL gérant l’intégralité des bases de données. Ainsi, nous avons une couche application bien développée, l’ORM à jour et des entrées externes vérifiées.

Cependant, imaginons un autre site sur la même machine. Il peut s’agir d’une ancienne interface, utilisant des versions de code obsolète et vulnérable, ou d’environnements de développement exposés. Les exigences de sécurité sur de tels environnements sont généralement moindres et peuvent préjudicier les données en production si l’architecture, la configuration du serveur et la gestion des secrets sont défaillantes. Une injection réussie sur le site vulnérable compromet l’intégrité des données de l’application correctement développée.

L’attractivité de la méthode

Des données facilement monétisables

Ce constat sur les défauts de configuration amène à penser, que non seulement les injections SQL existent encore, mais qu’elles sont souvent très efficaces. Ce qui rend la technique attractive pour tout cybercriminel. Là où une faille CSRF peut demander, pour être efficace, de nombreux efforts stratégiques, un seul défaut permettant l’injection SQL est à même d’exfiltrer les données (souvent sensibles) de l’application voir d’interagir avec le système d’exploitation du serveur. Sandra Carielli, Cheffe de produit Senior de l’accès et de la protection des données chez RSA va plus loin et explique, dans son article « SQL Injection and Distributed Security » que l’absence de chiffrement des données enregistrées dans les bases, incite grandement les attaquants à tenter ce type d’exploitation. La possible monétisation des données enregistrées sur les serveurs poussera toujours un groupe de cybercriminel à tenter d’exfiltrer ces dernières.

Cas récents d’injection SQL

Le cas Standford août 2020

En 2020 le site Web « Link », site de rencontre destiné aux étudiants de Stanford était vulnérable à une injection SQL. Quelques jours après le lancement du site, un mail fût envoyé au Standford Daily avec les données des étudiants qui s’étaient inscrits sur l’application, ainsi que la méthode utilisée lors du vol de données, une injection SQL. Après enquête, le fondateur du site Ishan Gandhi a confirmé l’existence de la vulnérabilité sur l’application. Il affirme qu’au moins 1000 comptes enregistrés auraient pu être dérobés, sans toutefois confirmer clairement de son côté, le vol des données.

Il y a quelques jours un pentester d’Obrela labs (service de cybersécurité londonien), Anastasios  Stasinopoulos  a révélé une vulnérabilité impactant le CMS Kentico. Développé en .NET, Kentico est un CMS utilisé pour les sites Web d’entreprises ou les applications e-commerce.

Dans son rapport, Anastasios explique avoir détecté un paramètre « tagname », modifiable depuis l’URL, n’étant pas correctement vérifié avant son interaction avec la base de données. D’après le pentester, il est possible de dérober des données confidentielles, altérer ces dernières ou encore augmenter ses privilèges sur l’infrastructure.

Kentico a depuis publié un correctif dans la version 6.0 du CMS.

8,3 Milions d’utilisateurs de Freepik impactés en août 2020

Freepik, plateforme de ressources de renommée mondiale a été victime d’une fuite de 8,3 millions d’adresses mail, ainsi que 3,7 millions de hashes de mots de passe associés. Deux algorithmes de hachages auraient été utilisé. Bcrypt pour 3,55 millions de mot de passe, et MD5 pour 229,000 d’entre eux. Ce dernier étant réputé obsolète. Selon John Callahan, consultant en sécurité des applications de la société nVisium, un défaut de mise à jour ou un code obsolète et vulnérable aurait permis l’attaque. 

Freepik aurait annoncé travailler avec des experts en sécurité afin de mieux se préparer à ce type d’évènements dans le futur et revoir leurs méthodes de travail en matière de sécurité informatique.

Au-delà du Web

L’injection SQL est souvent considérée à tort comme appartenant exclusivement au Web. Cependant, n’importe quel domaine applicatif incorporant une interaction homme machine peut en être victime.

Sur des produits SCADA

En 2012, deux chercheurs en cybersécurité découvrent plusieurs vulnérabilités dans un produit SCADA (système de contrôle et d’acquisition de données) destiné à la gestion des centrales solaires photovoltaïques. Le produit eSolar Light de Sinapsi aurait contenu de nombre failles critiques, parmi elles, des injections SQL.  Ces dernières permettaient de récupérer ou corrompre mots de passe, comptes utilisateurs, à noter que les mots de passes étaient stockés en clair dans les tables. Cela peut offrir la possibilité à un attaquant de modifier l’acheminement correcte du courant,  dérégler l’appareil voire l’endommager.

Sur des routeurs

Les routeurs peuvent aussi être affectés par des SQLi. En septembre 2019 ISE, une agence spécialisée dans la cybersécurité, a recensé 125 failles de sécurité dans pas moins de 13 routeurs et NAS. Parmi, ces vulnérabilités des injections SQL sont présentes sur deux types de routeurs, le TerraMaster F2-420, NAS de la marque TerraMaster et le Seagate STCR3000101 NAS de la marque Seagate.

Le rapport publié sous le nom de SOHOpelessly Broken 2.0 relate également des possibilités de dépassement de mémoire, de XSS (sur les interfaces clientes), de téléversement de fichier, d’injection de commande.  Les répercussions peuvent être dramatiques pour une entreprise utilisant un NAS pour stocker des données de sauvegardes et/ou sensibles. Plus encore, si ces machines peuvent offrir un accès privilégié à un réseau interne.

Conclusion

Les injections SQL vont bientôt fêter leurs vingt-cinq années d’existences (connues) pourtant elles sont loin de disparaître du paysage de la cybersécurité. Les raisons sont multiples, efficacité redoutable en cas de réussite donc attrait particulier pour des cybercriminels, mauvaises pratiques de développement et de configuration, données non chiffrées.

 Cependant, des règles simples à appliquer protègent contre ce type d’attaque. Au niveau applicatif, toujours vérifier les entrées utilisateurs, pour se protéger des SQLi, mais également des injections de code, d’inclusion de fichier. Utilisation stricte des requêtes préparées ou des ORM pour communiquer avec la base de données.  Associer ces pratiques avec la mise en place d’un pare-feu applicatif (WAF) ne peut que renforcer la sécurité la sécurité de l’application. Organiser un test d’intrusion sur ses applications peut déceler d’éventuelles injections et renforcer sa sécurité.

Au niveau de l’architectures cloisonner les bases et leurs utilisateurs associés, restreindre les droits de ces derniers et chiffrer les données, applique une couche supplémentaire de protection, ainsi si un maillon de la chaîne de sécurité cède il n’entraine pas forcément la chute complète de l’application. 

Sources :
The Atlantic
Find any answer
Hubspot.net
Snyk blog
White source software CVE-2019-10749
White source software CVE-2019-10748
White source software CVE-2019-10752
Snyk blog Sql injection orm vulnerabilities 
Dark reading
Stanford daily
Ports wigger
Mitre CVE-2021-27581
Bank info security
Ise casestudies

Je partage

Derniers articles

Analyse des Métriques XSS : comprendre l’Impact des injections de code côté client

Lors des tests d’intrusion, l’injection de code côté client est généralement plus aisée à découvrir qu’une injection côté serveur. Le nombre de paramètres dynamiques transitant du back au front, la difficulté d’échapper correctement à l’entrée et à la sortie et la multitude d’encodage liés à l’affichage peuvent être des vrais casse-têtes pour qui souhaite faire la chasse à la XSS. Le JavaScript malveillant semble ainsi avoir de beaux jours devant lui. Cependant, il n’est pas rare qu’à l’issu de l’audit, la criticité d’une telle injection découle directement de la configuration des cookies présents sur l’application. En effet, l’absence de l’attribut HttpOnly majore irrémédiablement les risques liés à ce type d’attaque. Néanmoins, cela signifie-t-il que la présence de cet attribut doive absolument amenuiser la criticité d’une injection ?

Lire l'article

Angular, N’Tier et HttpOnly

Avec l’apparition au cours de la décennie 2010 des environnements de travail Javascript de plus en plus puissants, l’architecture N’Tiers, si elle était déjà une norme dans le contexte d’application d’entreprises au cours des années 2000, a pu voir son modèle s’étendre à de nombreuses solutions Web. Ce modèle repose sur l’utilisation de technologies exécutées par le navigateur. Or, il arrive parfois que cette couche doive gérer une partie de l’authentification de l’utilisateur, pourtant une recommandation courante sur l’authentification est qu’elle ne doit jamais être côté client. Aussi, les cookies devraient toujours posséder l’attribut HttpOnly, empêchant leur lecture par une couche Javascript et ce afin d’empêcher tout vol de session lors d’une attaque de type XSS. Pourtant, cet attribut empêche littéralement l’application front-end de travailler avec ces éléments. Comment gérer au mieux ces questions sur ce type de déploiement ?

Lire l'article