Grammar / hosaka: 08:57 08/01/2020 / Category: Infosec  


The caption for this CTF reads "When we access this page we get a Forbidden error. However we believe that something strange lies behind... Can you find a way in and retrieve the flag?"

After starting the Docker instance and browsing to we are greeted by

"(403) Forbidden, You don't have permission to access / on this server

Apache/2.4.18 (Ubuntu)"


As with all web pages, the content rendered by the browser is the tip of the ice berg in terms of the actual data exchanged by the client and server. It is my personal preference to utilise two separate browsers simultaneously, this is a practice I have used for a number of reasons. One of these reasons is that the content which browsers display may vary both because of the design of that browser but also the server may serve content bespoke for each browser (This is determined in the user-agent request header). The two browsers I primarily use are Chrome and Firefox, as a personal preference I prefer using Firefox for quickly customising requests.

Prod and Poke

My standard go-to for any development / testing "Open developer tools and a second window with the page source". Nothing in the response headers appeared out of the ordinary, the page source was your standard Apache 403 message, no hidden breadcrumbs in either place. Next up, manually test:

  • (Used for exclusion lists for crawlers).
  • (Directory traversal).
  • Google for "Apache 2.4.18" exploits (Of which there are many however as this is a CTF I presumed this was not the desired path and kept this in my back pocket after exhausting all other possibilities).


After a cursory "prod and poke" (spending no more than 2 minutes) I first looked to DirBuster for further testing as much of next set of tests would be repetitive and time consuming if done manually. Starting with the shortest wordlist of the most common words and "GET" and "POST" methods. Immediately a 200 OK hit returned for (POST)

Back to Browser

Using Firefox developer tools (see previous) I sent a POST request to the index.php page. Firefox displayed a form with "Change Username:" and "not an admin (yet)". The page source revealed a comment in the form

<input type="text" name="fuckhtml" placeholder="notimportant">

<!-- HTB hint:really not important...totaly solvable without using it! Just there to fill things and to save you from some trouble you might get into :) -->

<input type="submit" value="Change">

On typing "admin" and clicking the "Change" button it appeared that the form was either broke in some way or had no functionality. To confirm this I tried with cURL:

  • curl -X POST 'fuckhtml=admin'
  • curl -X POST -F 'fuckhtml=admin'
  • curl -X POST -d -F 'fuckhtml=admin'

Response Headers

In the response headers one line in particular stood out:

Set-Cookie: ses=eyJVc2VyIjoid2hvY2FyZXMiLCJBZG1pbiI6IkZhbHNlIiwiTUFDIjoiZmY2ZDBhNTY4ZDYxZTVhMDNiY2RiMDQ1MDlkNTg4NWQifQ%3D%3D

the last 6 characters of this string "%3D%3D" were of particular interest %3D is the URL encoded representation of = this looked liked a Base64 string with a "==" padding suffix. Lets decode that:

echo eyJVc2VyIjoid2hvY2FyZXMiLCJBZG1pbiI6IkZhbHNlIiwiTUFDIjoiZmY2ZDBhNTY4ZDYxZTVhMDNiY2RiMDQ1MDlkNTg4NWQifQ== | base64 --decode


The "Admin":"False" key seemed a good starting point and after changing "False" to "True" and rehashing as Base64 I had the string (worth noting this could not be done via echo then piping to Base64 on the command line to encode as the JSON contained quotation marks which need to be escaped. I used an online tool to encode this string):


In Firefox developer tools I re-sent the POST request with the "Cookie: ses=...." now set to the new string and the previous message of "not an admin (yet)" now read "what are you trying to do huh?"


The next value to attempt to tamper was the Message Authentication Code "MAC" field. A few cursory probes at this resulted in capturing the flag, however, I wasn't exactly sure how this result came about (the values tested were a NULL value and then variants of letters or numbers both inside and outside of quotes, e.g. -1 "-1" "a" a). So I went to Google to investigate ...

PHP Type Juggling

I immediately ran into other write-ups for this CTF and a wealth of information on PHP type juggling (a strange behavior of PHP where "==" is a "loose comparison" operator and "===" would be a strict comparison, there is a lookup table available online to show how which loose comparisons would return True, for example array() == NULL. String to integer conversion in PHP also has strange results, if the string starts with a letter or the number 0 then that string will have an integer value of 0 (e.g. "abcde1337" would be int(0)). Some other examples (taken from OWASP):

  • "7a5c2...72c933" == int(7)
  • "68f66...8229bb" == int(68)
  • "092d1...c410a9" == int(92)


So, fumbling around fuzzing input and semi-educated poking and prodding helped me capture the flag. More importantly some lessons were learned ...

  • PHP is weird, the OWASP "PHP Magic Tricks" PDF had a wealth of interesting information on the subject plus a real world example of a bypass of Laravels' Message Authentication Code (MAC).
  • echo and cat don't play nice with quotation marks and "echo {"a":"b"} | base64" will not encode quotes
  • curl might have broke something:
    curl -X POST -v --cookie "ses=VXNlcjp3aG9jYXJlcyBBZG1pbjpUcnVlIE1BQzpmZjZkMGE1NjhkNjFlNWEwM2JjZGIwNDUwOWQ1ODg1ZAo="
    To which the server responded:
    * Connection #0 to host left intact you've fucked something up
  • Developer tools supplied me with the correct curl command:
    curl '' -H 'User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:71.0) Gecko/20100101 Firefox/71.0' -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' -H 'Accept-Language: en-GB,en;q=0.5' --compressed -H 'Connection: keep-alive' -H 'Cookie: ses="eyJVc2VyIjoid2hvY2FyZXMiLCJBZG1pbiI6IlRydWUiLCJNQUMiOjB9"' -H 'Upgrade-Insecure-Requests: 1' -H 'Origin:' -H 'Pragma: no-cache' -H 'Cache-Control: no-cache' --data ''
    And the server returned the flag:
    well done! flag is: TypejugAlingSOulS

Firefox Developer Tools


Customise request headers and HTTP verb


Directory Traversal Attacks


200 OK


Response to POST request made to



URL Encoding


PHP Type Juggling

Message Authentication Code

JSON Deserialization Attacks