Comprendre les vulnérabilités d'injection XPath (2023)

Lorsque les développeurs doivent interroger une base de données XML, ils utilisent XML Path Language (XPath) pour construire ces requêtes. Une requête XPath recherche le document XML pour trouver des nœuds qui correspondent à un modèle spécifié ou qui ont des attributs particuliers. Les bases de données XML restent un moyen courant de stocker les données des utilisateurs. Lorsqu'un utilisateur fournit son ID de connexion et son mot de passe, il déclenche la requête XPath préconfigurée, qui recherche dans la base de données les informations d'identification correspondantes et fournit l'accès si la combinaison fournie existe.

Cependant, la possibilité de déclencher une requête XPath via des informations fournies par l'utilisateur introduit le risque d'attaques par injection XPath. Ces attaques se produisent lorsque des requêtes XPath spécialement conçues accèdent à la structure de données XML. Les acteurs malveillants peuvent profiter des champs de saisie de l'utilisateur pour injecter du code XPath arbitraire qui peut accéder ou modifier les données du document XML. Cela signifie que, même si l'attaquant ne peut pas récupérer les mots de passe (si la base de données ne contient que des valeurs de hachage de mot de passe), il peut toujours utiliser la structure XML découverte pour causer des dommages supplémentaires.

Dans cet article, vous allez voir quelques exemples de code pour découvrir comment fonctionnent les attaques par injection XPath et apprendre quelques bonnes pratiques pour les prévenir et les atténuer.

Les risques de l'injection de XPath

Les attaques par injection XPath sont l'une des vulnérabilités des applications Web les plus répandues et les plus dangereuses. Une attaque réussie peut avoir plusieurs conséquences potentielles, notamment :

  • Accès et exfiltration de données sensibles ou d'informations personnellement identifiables (PII).
  • Suppression, modification ou corruption de données commerciales cruciales.
  • Obtenir un accès root à un système et effectuer des actions qui compromettent l'intégrité du système.
  • Distribution de logiciels malveillants ou d'autres codes malveillants aux utilisateurs internes et externes.

Les conséquences de telles attaques peuvent ruiner la réputation de votre application et de vos utilisateurs. Par conséquent, vous devez être conscient des risques associés aux attaques par injection XPath et prendre les mesures nécessaires pour les atténuer. Dans la section suivante, vous examinerez un exemple d'attaque par injection XPath pour savoir comment vous en défendre au mieux.

Comment fonctionne l'injection XPath

Cette section examine le fonctionnement des requêtes XPath, fournit une démonstration pratique d'une attaque par injection XPath et explique comment atténuer ou prévenir ces attaques.

Fonctionnement des requêtes XPath

Imaginez une application qui permet aux utilisateurs de rechercher des éléments dans un fichier XML. Pour activer cette fonction, l'application utilise l'expression suivante :

//*[contient(text(), $search)]

Dans cette requête, la chaîne fournie par l'utilisateur remplace le$recherchevariable. La requête recherche ensuite dans le document XML toutes les chaînes de texte qui correspondent à cette entrée. Lorsqu'elle s'exécute, l'application fonctionne comme prévu.

Cependant, ce type de requête est vulnérable aux attaquants qui peuvent entrer du code XPath malveillant leur permettant de contourner la hiérarchie des documents XML. Par conséquent, ils peuvent accéder ou même modifier les données XML de manière imprévue et dangereuse.

Par exemple, l'attaquant averti peut utiliser le formulaire de saisie utilisateur pour injecter le code XPath suivant dans la requête.$recherchevariable:

a' ou vrai() ou '

En conséquence, l'application construit et exécute la requête XPath suivante :

//*[contient(text(), 'a' ou true() ou '')]

Une requête de ce type correspondrait à tous les nœuds d'un document XML et, selon le programme, pourrait permettre à l'attaquant d'accéder à toutes les données contenues dans le document et de les modifier.

De plus, un attaquant peut vérifier la structure d'un document XML, ce qui peut potentiellement lui permettre de naviguer entre plusieurs couches de données contenues. Lorsque ce type d'accès est l'objectif, les acteurs malveillants ont tendance à utiliser l'une des deux méthodes d'injection XPath suivantes :

  • Booléanisation: Les requêtes booléennes généreront des comportements différents selon qu'elles se résolvent envraiouFAUXconditions. Un attaquant pourrait injecter une requête booléenne qui renvoie vrai si une demande de connexion aboutit etFAUXsi la connexion échoue. Cela permet à l'attaquant de récupérer un seul bit d'information (succès ou échec) avec chaque requête. La répétition de ce processus permet à un attaquant d'avoir un aperçu du contenu du document XML.
  • Exploration XML: Les attaquants peuvent injecter des requêtes spécialement conçues qui leur permettent de découvrir la structure d'un document XML. Ces requêtes permettent à l'attaquant de « ramper » dans un document XML sans connaître sa structure au préalable. En envoyant à plusieurs reprises de telles requêtes au document XML et en examinant les réponses, l'attaquant peut progressivement découvrir la structure du document et les éléments qu'il contient. Finalement, ils peuvent reconstituer les informations recueillies pour reconstruire l'ensemble du document. Cette approche peut être un moyen efficace pour découvrir des informations sensibles ou des vulnérabilités exploitables dans la structure du document.

Exemples de vulnérabilités d'injection XPath

Pour voir comment les injections XPath émergent et fonctionnent, vous allez créer une application de démonstration vulnérable à ces attaques. Vous allez créer une application de démonstration qui vérifie l'entrée fournie par l'utilisateur pour renvoyer les données d'un document XML.

Supposons que vous travaillez avec une plateforme de commerce électronique et que vous maintenez une liste de vos clients (utilisateurs), chacun étant identifié à l'aide d'un nom d'utilisateur. Pour connecter vos commandes à leurs acheteurs, vous utilisez une application pour rechercher le nom d'utilisateur pour renvoyer les commandes auxquelles elles sont associées, comme indiqué sur la page d'état de la commande.

Ci-dessous se trouve une construction de données XML appeléedonnées_commandes.xml, qui représentera ce scénario.


johndoe
Article Xbsg personnalisé #3668
1671301351
HS0282
gwr23d2has3fa13gs24


michael_read
Archep Noyaux Item#668
1671301351
HS0282
gwr23d2has3fa13gs24


adammrray
Partial CoSum Item#92623
1671301351
HS0282
gwr23d2has3fa13gs24

Vous utiliserez JavaScript pour exécuter les données ci-dessus et créer une application de base qui permet aux utilisateurs d'interroger les données à l'aide des entrées qu'ils fournissent.

Dans le même répertoire, exécutez la commande suivante pour initialiserNode.js,un environnement d'exécution JavaScript :

npm init-y

Ensuite, vous devrez utiliser les éléments suivants pour exécuter XML. Notez qu'ils sont tous les deux inclus dans Node.js :

XPath—Pour l'implémentation DOM et l'assistant pour JavaScript qui prend en charge les chaînes de requête XPath
XMLDOM—Pour l'implémentation JavaScript de DOM pour Node.js qui prend en charge l'interface XML Parser

Ouvrez un terminal dans le répertoire de votre application et exécutez la commande suivante :

npm je xpath xmldom

Dans le même répertoire, créez unindex.jsfichier et exécutez les données XML comme suit :

Tout d'abord, importez les dépendances requises :

const fs = require('fs');
const xpath = require('xpath');
const dom = require('xmldom').DOMParser;
const util = require('util');
const readline = require('readline').createInterface({
entrée : process.stdin,
sortie : process.stdout
});

Ensuite, créez un module readline simple pour autoriser les entrées fournies par l'utilisateur :

fonction asynchrone enterOrder(){
let question = util.promisify(readline.question).bind(readline);
essayer{
const order = await question("Entrez le nom d'utilisateur");
ordre de retour ;
}attrape (erreur){
se tromper;
}
}

Créez une fonction pour exécuter la requête XML et renvoyer les données de l'entrée à l'aide du code ci-dessous :

fonction asynchrone xpath_injection_example(){

const xml = fs.readFileSync('orders_data.xml','utf-8');
const doc = new dom().parseFromString(xml);

var ordre = attendre enterOrder();
si (commande){
évaluateur const = xpath.parse(`/users/orders[username = '${order}']/order`);

caractère const = évaluateur.select1({
noeud : doc,
variable : {
commande
}
});
si(caractère){
console.log(character.textContent);
}autre{
console.log("L'utilisateur n'existe pas");
}
}
}

// exécute cette fonction
xpath_injection_example()

Dans l'exemple ci-dessus, la requête/utilisateurs/commandes[nom d'utilisateur = '${commande}']/commandesera exécuté. Les éléments de commande sont des enfants de commandes avec un élément de nom d'utilisateur, où la valeur est égale à la variable fournie dans l'entrée utilisateur.

[nom d'utilisateur = '${commande}']spécifie une condition de prédicat qui doit être satisfaite par les éléments sélectionnés. Dans ce cas, le prédicat spécifie que l'élément username doit avoir une valeur égale à la valeur de la variable order.

De cette façon, l'élément order est sélectionné en tant qu'enfant de l'élément orders qui satisfait le prédicat. Exécutez maintenant la commande suivante pour exécuter ce programme :

index de nœud.js

Cela vous permettra d'entrer le nom d'utilisateur, tout comme un utilisateur aurait utilisé une entrée fournie par la recherche.

Entrez un nom d'utilisateur dans votredonnées_commandes.xmlfichier, comme indiqué ci-dessous. Cela devrait afficher la commande associée. Sinon, un message "L'utilisateur n'existe pas" s'affichera si le nom d'utilisateur n'existe pas.

Entrez le nom d'utilisateur michael_read
Archep Noyaux Article#668

Explorer les vulnérabilités d'injection XPath

Cette application fonctionne comme il se doit. Cependant, un attaquant avec des intentions malveillantes peut exécuter des requêtes XPath arbitraires en utilisant l'entrée utilisateur fournie pour obtenir un accès sans avoir besoin d'un nom d'utilisateur valide.

L'application est vulnérable à l'injection de code malveillant. Le prédicat[nom d'utilisateur = '${commande}']est la cible de l'attaquant ici. Un attaquant peut construire une requête qui évalue cette expression pour satisfaire sa condition. En utilisant le code injecté, la requête sera évaluée comme vraie et permettra à l'attaquant d'accéder sans fournir le nom d'utilisateur correct.

Voici quelques requêtes arbitraires qui peuvent permettre aux attaquants de contourner la hiérarchie des données à l'aide de l'entrée fournie par l'utilisateur :

  • 'ou'1'='1
  • texte' ou '1' = '1
  • ' ou 1=1 ou 'a'='a
  • ' ou ''='
  • a' ou vrai() ou '

Voici comment exécuter toutes les requêtes arbitraires ci-dessus en utilisanta' ou vrai() ou 'comme exemple :

Entrez le nom d'utilisateur a' ou true() ou '
Archep Noyaux Article#668

Atténuation des injections XPath

Comme vous pouvez le voir dans l'exemple ci-dessus, des injections correctement construites signifient qu'un attaquant peut trop facilement accéder à des données restreintes. Ainsi, cette section explore comment vous pouvez corriger les vulnérabilités courantes et atténuer les risques associés aux injections XPath.

Désinfection des entrées

Cette attaque tire parti d'un manque de liaison appropriée des paramètres variables dans le code de l'application. L'application concatène l'entrée fournie par l'utilisateur directement dans une requête XPath sans valider ou nettoyer de manière adéquate l'entrée. C'est là que l'attaquant peut insérer des instructions XPath malveillantes dans la requête pour accéder aux informations sensibles de la base de données XML.

Pour atténuer cela, la meilleure stratégie consiste à utiliser la liaison de paramètres pour empêcher l'injection. Pour ce faire, vous pouvez utiliser une expression régulière qui supprime tous les caractères qui ne sont ni des lettres ni des chiffres. Cette méthode empêche les attaquants potentiels de construire des requêtes arbitraires.

Pour nettoyer et empêcher les vulnérabilités d'injection XPath dans cet exemple, utilisez le code suivant :


fonction asynchrone enterOrder(){
let question = util.promisify(readline.question).bind(readline);
const regex = /[^a-z0-9]/g ;
essayer{
const order = await question("Entrez le nom d'utilisateur ");
si(regex.exec(commande)){
console.log("Caractères invalides non autorisés");
}
autre{
ordre de retour ;
}

}attrape (erreur){
se tromper;
}
}

fonction asynchrone xpath_injection_example(){

const xml = fs.readFileSync('orders_data.xml','utf-8');
const doc = new dom().parseFromString(xml);

var ordre = attendre enterOrder();
si (commande){
évaluateur const = xpath.parse(`/users/orders[username = '${order}']/order`);

caractère const = évaluateur.select1({
noeud : doc,
variable : {
commande
}
});
si(caractère){
console.log(character.textContent);
}autre{
console.log("Le numéro de commande n'existe pas");
}
}
}

// exécute cette fonction
xpath_injection_example()

Le code ci-dessus utilise regex pour détecter et filtrer les caractères non alphanumériques. Si l'entrée fournie contient de tels caractères, l'application arrêtera toute exécution ultérieure et affichera le message « Caractères non valides non autorisés ». Cependant, si l'entrée réussit ce test, l'application continuera et exécutera la requête avec l'entrée fournie. Vous pouvez tester le code avec les requêtes arbitraires décrites dans la section ci-dessus.

Utilisation de requêtes XPath paramétrées

Bien que vous puissiez nettoyer les entrées de l'utilisateur, un attaquant pourrait toujours utiliser d'autres techniques pour contourner ce filtre.

Il est pratiquement impossible d'échapper à tous les caractères potentiellement exploitables à l'aide d'expressions régulières. Dans des cas comme l'authentification de l'utilisateur, l'application demande aux utilisateurs de fournir des mots de passe pouvant contenir de tels caractères. Cela signifie que la désinfection des entrées de l'utilisateur n'est pas entièrement fiable.

Une autre alternative consiste à utiliser des requêtes XPath paramétrées, comme indiqué ci-dessous :

évaluateur const = xpath.parse(`/users/orders[username = $order]/order`);

caractère const = évaluateur.select1({

noeud : doc,
variable : {
commande : commande
}
});

Cependant, cette approche contient une expression XPath dynamique construite à l'aide d'une interpolation de chaîne, qui peut également être construite à partir de données fournies par l'utilisateur. Par conséquent, cette méthode peut ne pas être suffisante pour protéger complètement contre l'injection de XPath.

Utilisation de requêtes XPath précompilées

Vous pouvez utiliser une requête XPath précompilée pour éviter l'expression XPath dynamique. Ceci est réalisé en définissant l'expression XPath en tant que variable distincte, puis en la transmettant lorsque cela est nécessaire.

La requête XPath précompilée utilise une variable pour représenter l'entrée fournie par l'utilisateur. Cela garantit qu'ils ne sont pas construits à partir de données fournies par l'utilisateur. Ainsi, un attaquant ne peut exécuter aucun code arbitraire pour y accéder. Voici un exemple d'utilisation d'une requête XPath précompilée :


fonction asynchrone xpath_injection_example() {
const xml = fs.readFileSync('orders_data.xml', 'utf-8');
const doc = new dom().parseFromString(xml);

// Définir la requête XPath précompilée
const xpathQuery = `/users/orders[username = $order]/order` ;

commande const = attendre enterOrder();
si (ordre) {
// Utilise la requête XPath précompilée
évaluateur const = xpath.parse(xpathQuery);

caractère const = évaluateur.select1({
noeud : doc,
variable : {
commande : commande
}
});
si (caractère) {
console.log(character.textContent);
} autre {
console.log("Le numéro de commande n'existe pas");
}
}
}

// Exécute la fonction
xpath_injection_example();

Cela permet de garantir que l'entrée fournie par l'utilisateur est traitée comme distincte de la requête XPath plutôt que comme faisant partie de la requête elle-même.

Conclusion

Vous avez maintenant appris certaines stratégies courantes pour exécuter des attaques par injection XPath et vous avez un aperçu de leurs conséquences potentielles. Heureusement, vous avez également découvert des moyens d'atténuer les risques.

Cependant, votre application peut toujours être vulnérable à l'injection XPath même après avoir implémenté les mesures de sécurité que vous avez explorées. Pour optimiser la sécurité des applications, le recours à des outils tels que les pare-feu d'applications Web (WAF) ou la protection des applications Web et des API (WAAP) peut combler les lacunes que les meilleures pratiques de codage ne peuvent pas combler. Visitez Trend Micro dès aujourd'hui pour commencer à évaluer la sécurité de votre application.

Top Articles
Latest Posts
Article information

Author: Lidia Grady

Last Updated: 07/12/2023

Views: 5235

Rating: 4.4 / 5 (45 voted)

Reviews: 84% of readers found this page helpful

Author information

Name: Lidia Grady

Birthday: 1992-01-22

Address: Suite 493 356 Dale Fall, New Wanda, RI 52485

Phone: +29914464387516

Job: Customer Engineer

Hobby: Cryptography, Writing, Dowsing, Stand-up comedy, Calligraphy, Web surfing, Ghost hunting

Introduction: My name is Lidia Grady, I am a thankful, fine, glamorous, lucky, lively, pleasant, shiny person who loves writing and wants to share my knowledge and understanding with you.