Secrets box EG-CTF write up

Today I am going to disclose the write-up of one of the most interesting challenges I have been playing recently together with my teammates in the EGCTF 2019.

The challenge was amazing and really challenging, it was only solved twice by our team and another team and today I add the full write up.
OK, let’s start.

Reconnaissance Phase

Once I launched the challenge, I see the following:

I tried to launch many bypass authentication payloads like ‘ or 1=1– and similar payloads but all my attempts failed.

Launching verb tampering attacks to bypass the firewall also resulted in a dead-end, at that point I decided to extend my recon phase, so I launched Dirbuster to search if there are more hidden endpoints and I clearly noticed a newly discovered endpoint.

Assessment phase

Now a new hidden endpoint is discovered which is “api.php”, by opening the page we can observe the following.

OK, no need this time for brute-forcing the acceptable parameters as the page itself printed the needed parameter which is ‘msgid’.

I added ‘msgid’ parameter in the GET request and I was able to observe the following.

Cool enough, I started different types of SQL injection attacks on ‘msgid’ parameter and launched different types of SQL payloads for different database schemas, I noticed the behavior of the API is really weird as it was launching ‘and 1=1’ towards the input results in successful response while extending the attack with more SQL statements results in an error message, I even tried to manually exploit blind SQL injection but every tries results in the following error message.

In the error message, I noticed that the backend is possibly using XPATH, thus, I shot an XPATH payload and sent the following to extract the next message.

OK, now it is obvious that it is an XPATH injection so we launch the following payloads to extract all the messages.

Notice that the mark ‘!=’ means not equal, therefore, I was able to discover the following messages.

Please have a look at the third message regarding id:81, it is a private message and it is forbidden to view this message directly through the API endpoint because it is a private message, then we will need to do XPATH injection and retrieve the contents of this secret message.

We already know the path to the messages discovered through the printed error message which is as follow:’//message[id=81]’, that’s why I started to inject using the following payload “api.php?msgid=81][//message[content=*]” and we receive a true response. The next step is to launch a blind XPATH injection to retrieve character by character.

The headshot arrived when I sent the next payload to check the first character as I sent a payload to ask the XPATH backend if the first character of the secret message is ‘a’ or not. but I received the following error.

As you can see, the input is filtered against a single quote and double quotations. WHAT!!!!

Filtering any single quote and double quotations for XPATH injection is something that you really don’t want to face.
Injecting any strings or characters will result in failure because of the quotes filter in addition to using functions to encode the string or changing the result into ASCII is not an option in XPATH first version.

So we can only retrieve numbers!! but of course the flag is not only numbers.

Exploitation Phase

If you didn’t bring your coffee or smoke your cigarette yet, then please do as the challenge is about to start now.

Since we are not allowed to use a single quote or double quotations then we will use the old school technique and start to gather the data using XPATH 1.0 simple functions.
A quick search for XPATH functions that deal with strings, I landed on the following page: https://www.w3.org/TR/1999/REC-xpath-19991116/#section-String-Functions
In my scenario, I will use the substring function to compare a single character that I already know with every single character in the secret data needed to be extracted.
The contents that I will use to extract the characters needed for the blind injection attack are found in the following message for id=1

Since I am able to compare each character with numbers then I will start my testcase with a number, using my burp I launched the following request in intruder:

I also added a payload list contains numbers from 1 to 150 and added the error word to be marked to be able to distinguish between the true response and the failure response. The intruder resulted in the following.

There was only one successful response which is payload 70, this indicates that the character located in position 70 in the secret message is 2.
Yes, it is an intruder attack for every single character!!.

I was able to extract all the numbers within the secret message using the same way but what about the characters!!
My idea was to extract a specific character using the same function substring and compare it with the remaining characters in the secret message using the same way.

The challenging part for me was “how to exactly know the character that I am extracting”
Don’t forget that the characters will be extracted from the contents of the first message as we mentioned before.
If we made attention to the first message we can easily identify unique numbers used only once.

My idea was to retrieve the location of number 3 in the word ‘s3crets’ because it is not repeated and through it I will be able to identify the location of the remaining characters.
using the same intruder way I search for the location of number 3 in id 1, here is the request sent to the intruder.

Bypassing a character by character and compare it if it is equal to 3 or not, I see the following in the intruder result.

The payload 102 was the only one that didn’t print the error, now we know that number 3 is located exactly in position 102 in the retrieved string of the content of the public message id=1
Again I will mention the string that we are extracting data from.

Since 3 is in position 102 and we already know the message, that means we are able to extract any single character from the message depending on how far the needed character from 3 in position 102.
For example, if we need to extract the ‘f’ character it will be in position 99 as it is located before our number with three characters and so on.
Therefore, if we need to search for the ‘f’ character in our secret message id 81, then we will use the substring function to extract the character number 99 from the first message content and compare it with every single character in the secret message.
An example to the intruder to search for the ‘f’ character.

We compare each single character located in the secret message with the following: substring(//message[id=1],99,1) -> this will retrieve the ‘f’ character.
Adding the numbers to our payload list and here is the result.

The intruder shows that the character ‘f’ is located multiple times in positions 59,71,79,86,90 and 98.

Coding Phase

The next part is to create a list of each character and its location in the public message, using the list, I can create a tool to do the remaining job for us and scan for each character and its position in the secret message.

First I created a simple PHP tool to get all the unique characters for me and its location.

Here is our list for the location of each character after launching the tool:

Then we need to create a function that receives the location of the character needed to be extracted from the secret message and compare it with all the characters within our list and then return the correct character if found (return the character that didn’t print any error message).

We should not forget about the numbers also, the numbers don’t need a list, just a loop.

Combining all together in one tool to create the list, send the list to the function in addition to the location for each character one by one and then print the live results.

After launching the tool

BINGOOOOOOOO!!!!
Now I successfully received the data content of the secret message and I can observe an email and md5 hash.
Cracking the md5 hash:

Finally, I used the credentials to login to the main page.

I really forgot all the pain after hitting the 400 points for my team.

Leave a Reply


The reCAPTCHA verification period has expired. Please reload the page.