XXExternalXX was a challenge that formed part of the 2020 SharkyCTF competition. We're told that a file named
flag.txt has been placed at the server root, and we need to find a way to get at it. We're also given a link to a webpage.
If we go onto the "News" tab of that webpage, we get shown this:
Look closely at the URL - the query string is
?xml=data.xml. This seems like it's a file that's being read from on the webserver. If we request this file directly, we get shown this:
<root> <data> 17/09/2019 the platform is now online, the fonctionnalities it contains will be audited by one of our society partenairs </data> </root>
If we add some garbage to the query string, like
?xml=hfdoluagjsfagdhjkasfdgkjhl, a bunch of errors are spat out of the application.
These list off some of the functions that are in use inside of the web app, namely
simplexml_import_dom(). If we look up the PHP documentation for each function, we can get a better understanding of what each function does and how we might be able to exploit them.
The manual page for
file_get_contents is the most interesting (found here). As expected, it will return the contents of a file provided as parameters to the function, but it has one interesting example.
<?php $homepage = file_get_contents('http://www.example.com/'); echo $homepage; ?>
We can see that the function will accept URLs and read from them, so if no input validation is being done on the webserver, we should be able to make the app load our own XML as long as we put it on the internet.
At this point, it becomes a case of writing an XML External Entity injection payload (you can read more about this here) in order to get the contents of the remote file,
/flag.txt. My payload looked like this:
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///flag.txt"> ]><root><data>&xxe;</data></root>
It mimics the format of the original XML used by the web app, so the contents of the file will still be shown to us when the page loads.
I uploaded this to my webserver, and set the URL as the query string parameter, which gave me the flag.
It's worth noting that you could also have done this with a service like Github Gist or Pastebin in order to get your XML payload on the internet.