Reply Challenge 2020 - That’s what server says
This is the Writeup for the 300 points Web challenge for Reply Challenge CTF. During the CTF I and my team achieved first blood on this challenge. The challenge consists of finding a service endpoint on a web page, with a login API. Then you have to exploit an XXE (XML External Entities) Injection to get an LFI (Local File Inclusion) to get the sysadmin credentials to login on the service and get the flag.
Service discovery
Fist we land on a page with just a <h1> title and an <img>. The title talks about robots and
in the image there are some blackberries. So as they hinted we navigate to the /robots.txt files
to find if there are some disallowed entries. We are greeted by the character Michael from The
Office saying “You’re not my friend Barry”.
User Agent
Since the roots.txt file is blocked and there is anything else on the main page, we have to
circumvent the check on this file. They hinted to us something about berries or blackberries. So we
can try to access the robots.txt as a BlackBerry phone. This can be done by changing the
User-Agent header of your HTTP request. We can find a list of valid User-Agent string on
this website. After we
changed the User-agent we revisit the page and now we can see a disallowed entry
/file_upload.php.
File Upload
The file_upload.php API permits us to upload a [png, jpg, jpeg, gif] file to the machine and
will return where the file was uploaded.
Spoiler: we never use the uploaded file (rev shell or other) probably was a rabbit hole.
There are two curious facts about this API. The first is that the POST request has sent three
values:
- fileToUpload: The file to upload and its filename
- req: A string that represents an endpoint on the server
- submit: A request method (POST)
The second one is when you send the request without uploading a file, you get a message to contact
the sysadmin to use the API /services and set the authorized.xml file.
Exploitation
We can not access the /services from our machine, so we can try to use file_upload.php to
communicate with this API. First, we can try to change the req value to /services and check what
we get back. Sending an image we get that the page doesn’t support this method. Then we change the
submit value to GET. The page responds with an HTML/XML body. This is XML WSDL a standard
for Web Services Description Language, it is used to describe web services.
We can see that the services have an endpoint at /services/perform_login requires as input a
user and a pwd that is probably the one in the authorized.xml referenced before.
XXE Injection
We can now try to send the file to the login API. If we send an image the endpoint returns
XML Format Error, so we know that the page requires an XML file. Unfortunately, file_upload.php
only accepts certain extension, we need to craft or XML payload and rename the file to a valid
extension like .jpg.
From the XML WSDL, we know the arguments that are required, and with a bit of trial and error, we can find the right format of the payload.
<user>test</user>
When we send the post we get an error saying:
test is not a register user
Now we have a value user that can output on the response. This means we can make an XXE Injection
to get the authorized.xml file as the user value and make the response print it as an error for
profit. We can guess the position of the file because the response includes where our image was
uploaded, or we could try and get the entire directory, or a known file like /etc/passwd.
The final payload is the following.
<!DOCTYPE root [!ENTITY test SYSTEM 'file:///var/chall300_web/authorized.xml'>]>
<user>&test;</user>
If you want to read more about XXE here PayloadAllTheThings/XXE Injection