Exploiting Out Of Band XXE using internal network and php wrappers

Hello hackers,
A couple of weeks ago I tweeted about exploiting an out of band XXE vulnerability with a firewall blocking all outgoing requests including DNS lookups, so here is the full story:
This is a private bug bounty program so I won't be mentioning who the vendor is.

As usual during a hacking night while navigating the target application I came across an endpoint that took a parameter called xml but its value was encrypted. Later I found out that XML data sent to the backend is encrypted in the client side before sent in HTTP requests which means that XML data might not be properly validated in the backend, so I wanted to modify it to be able to inject my own XXE payload. So what I first tried was to find the JavaScript function used to encrypt the XML and do the same for my custom XML payload, however, the application's JavaScript was minimized with WebPack which made it very hard to read and trace functions. To avoid the hassle of finding the JavaScript encrypting function, I decided to add a break-point using chrome's developer tools that would allow me to modify the XML data before it's sent to the encryption function.

Thus, I was able to send my own custom XML data. So I started listening on a port on my server and began sending some normal XXE payloads to see if the parser will try to fetch anything from my server. However, the endpoint took too much time to load then returned an error saying "Error while parsing XML", but I when I tried to set the external entity URL to `http://localhost/` the server responded quickly without returning anything. With that said, I realized that there must be a firewall blocking requests to external servers so the first thing that came to my mind is to try different ports but nothing worked, I also tried to see if it does DNS lookups but DNS queries were also blocked and I got nothing on my listener.

So now I have an XXE but I can do nothing with it except for scanning the internal network for open ports which makes it a valid XXE but not very impactful due to the firewall blocking outgoing requests. However, since the firewall doesn't block requests to the internal network and the application was actually accessible internally because when I added its URL `http://target/` as the external entity URL the server responded fast, I had an idea to find an endpoint that doesn't require cookie authentication and uses GET parameters to change or add something that I can see publicly through the application. And that fitted perfectly with how the application was working because most of the endpoints didn't actually use cookie authentication and used SID parameter (which is the user's session ID) to authenticate users.

With that in mind, I kept looking for an endpoint and found one that takes three parameters sid, key and val then it will save both key and val parameters to the user's account assigned to the session ID and we can access these values later by visiting the endpoint.

So now the idea is to create an external entity that sends a GET request to http://target/endpoint.php?sid=[session_id]&key=xxe&val=test then check the same endpoint and see if xxe and test values were added. So I simply sent the following XXE payload:

Then when navigating to http://target/endpoint.php?sid=[session_id] I found that the values were actually added which means that server internally fetched the entity and sent a GET request to the endpoint provided.

Things began to become clearer as I got a working proof of concept that XXE exists, however, I wanted to take it a little further and see if I can read local files.

To read local files we need to create a parameter entity that fetches the file then another entity that uses the first parameter entity as the value of val parameter and in order to do this I have to use an external DTD file, however, due to the fact that there is a firewall blocking any outgoing requests it wasn't possible for the XML parser to fetch the external DTD from my server.

I kept thinking of a way around the firewall, one of the ideas I got was to find an endpoint in the application that allows me to upload files then upload my own custom DTD, but the application had no features for file upload. I almost gave up at this point, but then I remembered that the application was built using PHP so I could use php:// wrapper to fetch a resource from a data:// URI that would return my custom DTD file.

So here is how my external DTD URL would look like:

And when the parser tries to fetch that, it will get:
PS: I also used php://filter/convert.base64-encode/ to convert the content of index.php file to base64 to make it easier to fetch the file
So the final payload would look like:
Then when I navigated to http://target/endpoint.php?sid=[session_id] I was shocked to find the base64 of the content of index.php file!!

Aaaand That's it, if you have any questions, feel free to drop me a tweet @Zombiehelp54


  1. This comment has been removed by the author.

  2. Leo Oscar
    Thank you so much for this useful information. looking more from your side to update us on more updates and advancements

  3. Aw, this was an exceptionally nice post. Spending some time and actual effort to make a superb article… but what can I say… I procrastinate a lot and don't manage to get nearly anything done.
    Click here to get More information.

  4. This comment has been removed by the author.

  5. The New Modern JavaScript Boot camp Course (2020) ProgrammingFree course

  6. When I originally commented I seem to have clicked on the -Notify me when new comments are added- checkbox and now every time a comment is added I recieve four emails with the same comment. There has to be an easy method you are able to remove me from that service? Thanks a lot!
    CLick here for information.


Post a Comment

Popular posts from this blog

Handlebars template injection and RCE in a Shopify app

SQL Injection and A silly WAF