130 lines
2.7 KiB
Python
130 lines
2.7 KiB
Python
|
|
"""
|
||
|
|
XXE (XML外部实体注入) 漏洞知识
|
||
|
|
"""
|
||
|
|
|
||
|
|
from ..base import KnowledgeDocument, KnowledgeCategory
|
||
|
|
|
||
|
|
|
||
|
|
XXE = KnowledgeDocument(
|
||
|
|
id="vuln_xxe",
|
||
|
|
title="XML External Entity (XXE) Injection",
|
||
|
|
category=KnowledgeCategory.VULNERABILITY,
|
||
|
|
tags=["xxe", "xml", "entity", "injection", "ssrf"],
|
||
|
|
severity="high",
|
||
|
|
cwe_ids=["CWE-611"],
|
||
|
|
owasp_ids=["A05:2021"],
|
||
|
|
content="""
|
||
|
|
XXE允许攻击者通过XML外部实体读取服务器文件、执行SSRF攻击或导致拒绝服务。
|
||
|
|
|
||
|
|
## 危险模式
|
||
|
|
|
||
|
|
### Python
|
||
|
|
```python
|
||
|
|
# 危险 - lxml默认配置
|
||
|
|
from lxml import etree
|
||
|
|
doc = etree.parse(user_xml)
|
||
|
|
doc = etree.fromstring(user_xml)
|
||
|
|
|
||
|
|
# 危险 - xml.etree (Python < 3.7.1)
|
||
|
|
import xml.etree.ElementTree as ET
|
||
|
|
ET.parse(user_xml)
|
||
|
|
|
||
|
|
# 危险 - xml.dom
|
||
|
|
from xml.dom import minidom
|
||
|
|
minidom.parseString(user_xml)
|
||
|
|
```
|
||
|
|
|
||
|
|
### Java
|
||
|
|
```java
|
||
|
|
// 危险 - DocumentBuilder默认配置
|
||
|
|
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
||
|
|
DocumentBuilder db = dbf.newDocumentBuilder();
|
||
|
|
Document doc = db.parse(userInput);
|
||
|
|
|
||
|
|
// 危险 - SAXParser
|
||
|
|
SAXParserFactory spf = SAXParserFactory.newInstance();
|
||
|
|
SAXParser parser = spf.newSAXParser();
|
||
|
|
parser.parse(userInput, handler);
|
||
|
|
```
|
||
|
|
|
||
|
|
### PHP
|
||
|
|
```php
|
||
|
|
// 危险
|
||
|
|
$doc = simplexml_load_string($xml);
|
||
|
|
$doc = new DOMDocument();
|
||
|
|
$doc->loadXML($xml);
|
||
|
|
```
|
||
|
|
|
||
|
|
## 攻击载荷
|
||
|
|
|
||
|
|
### 文件读取
|
||
|
|
```xml
|
||
|
|
<?xml version="1.0"?>
|
||
|
|
<!DOCTYPE foo [
|
||
|
|
<!ENTITY xxe SYSTEM "file:///etc/passwd">
|
||
|
|
]>
|
||
|
|
<root>&xxe;</root>
|
||
|
|
```
|
||
|
|
|
||
|
|
### SSRF
|
||
|
|
```xml
|
||
|
|
<?xml version="1.0"?>
|
||
|
|
<!DOCTYPE foo [
|
||
|
|
<!ENTITY xxe SYSTEM "http://internal-server/api">
|
||
|
|
]>
|
||
|
|
<root>&xxe;</root>
|
||
|
|
```
|
||
|
|
|
||
|
|
### 拒绝服务 (Billion Laughs)
|
||
|
|
```xml
|
||
|
|
<?xml version="1.0"?>
|
||
|
|
<!DOCTYPE lolz [
|
||
|
|
<!ENTITY lol "lol">
|
||
|
|
<!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;">
|
||
|
|
<!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;">
|
||
|
|
]>
|
||
|
|
<root>&lol3;</root>
|
||
|
|
```
|
||
|
|
|
||
|
|
## 检测要点
|
||
|
|
1. 所有XML解析代码
|
||
|
|
2. 是否禁用了外部实体
|
||
|
|
3. 是否禁用了DTD处理
|
||
|
|
4. 用户输入是否直接解析
|
||
|
|
|
||
|
|
## 安全实践
|
||
|
|
1. 禁用外部实体
|
||
|
|
2. 禁用DTD处理
|
||
|
|
3. 使用JSON代替XML
|
||
|
|
4. 输入验证
|
||
|
|
|
||
|
|
## 修复示例
|
||
|
|
|
||
|
|
### Python
|
||
|
|
```python
|
||
|
|
# 安全 - lxml禁用实体
|
||
|
|
from lxml import etree
|
||
|
|
parser = etree.XMLParser(
|
||
|
|
resolve_entities=False,
|
||
|
|
no_network=True,
|
||
|
|
dtd_validation=False,
|
||
|
|
load_dtd=False
|
||
|
|
)
|
||
|
|
doc = etree.parse(user_xml, parser)
|
||
|
|
|
||
|
|
# 安全 - defusedxml
|
||
|
|
import defusedxml.ElementTree as ET
|
||
|
|
doc = ET.parse(user_xml)
|
||
|
|
```
|
||
|
|
|
||
|
|
### Java
|
||
|
|
```java
|
||
|
|
// 安全 - 禁用外部实体
|
||
|
|
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
|
||
|
|
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
|
||
|
|
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
|
||
|
|
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
|
||
|
|
```
|
||
|
|
""",
|
||
|
|
)
|