Timestamps and weird emails— A solution for Intigriti’s 0321 challenge

Intigriti is back at it again! This month’s challenge is yet another from the amazing Inti. Let’s dive right into it!

The rules are as follows:

The solution…
- Should work on the latest version of Firefox or Chrome
- Should
alert() the following flag: flag{THIS_IS_THE_FLAG}.
- Should leverage a cross site scripting vulnerability on this page.
- Shouldn’t be self-XSS or related to MiTM attacks
- Should be reported at
go.intigriti.com/submit-solution

The challenge seems to revolve around this interesting component, found at the bottom of the page:

Inti has decided to give us the possibility of writing and storing our own notes! Cool, huh? Well, let’s exploit that!

Intercepting the request with Burp Suite

Upon saving our notes, we can use Burp Suite to see that a POST request is made. The request uses a CSRF-token, so it looks like we will have some difficulties turning a self-XSS into something exploitable… But let’s not worry about that for now, and instead focus on finding an XSS vulnerability in the notes component.

By inspecting the page, we can see that the value of our notes is displayed in a paragraph tag, using the contenteditable attribute. Let’s try to include some HTML code in our notes, and save it!

Well, sadly it wasn’t that simple. As we can see, our HTML code was properly escaped…

Look at that! A hint ticked in from Intigriti’s twitter. But what are they hinting at? What should we add to our notes? Well, it’s a bit weird they provided the URL to the challenge page yet again in this tweet. Maybe we should actually try to add the URL to our notes?

Interesting! The URL was transformed into an anchor tag! Maybe we can just include a " in the URL to break out of the href attribute?

Nope, that did not work. As seen in the screenshot above, our input was only interpreted as a URL up until the " char. Well, let’s give it a go again with a more complex URL! Let’s try something like this and see if it breaks something: https://a"b@lol.com?a=b"c

Well, that was unexpected! Besides interpreting https://a as a URL, b@lol.com was interpreted as an email, and got converted into an anchor tag using the mailto scheme! Interesting! Give me a minute and I’ll try to break out of the href attribute once again, but now using ‘email payloads’!

*Some intense testing*

I’m back, but I sadly didn’t succeed… What to do now?

Yay, a tip to the rescue! If you don’t know about RFC (Request for comments), you can read about it here. Hmm, maybe we should read up on the email formats supported by the mailto scheme.

After some reading and searching, I finally found RFC 3696, which had a very interesting section:

In addition to quoting using the backslash character, conventional double-quote characters may be used to surround strings. For example

"Abc@def"@example.com

"Fred Bloggs"@example.com

Double quotes in emails can be totally valid!! Let’s try to use the following email: "hihi"@a.b

Hype! It worked! We successfully broke out of the href attribute! <> -chars are still escaped, so we are limited to attributes inside the anchor tag. But let’s try to create a simple PoC that will alert the flag! We could e.g. use the onmouseover event handler: "onmouseover='alert(flag.innerText)'"@a.b:

Great! Now we have a simple PoC for a self-XSS. But why have a simple PoC when you can have a 1337-no-user-interaction-cool-PoC TM? Let’s head over to this cool XSS cheat sheet by PortSwigger, to see what we can come up with.

Combining the id, tabindex, and onfocus attributes seems very promising (though it won’t work in firefox)! To get such a payload to fire, we just need to include the hash #<SOME_ID> in the URL. And just like that, we can circumvent the need for user-interaction!

Payload: “id=’x’tabindex=’1'onfocus=’alert(flag.innerText)’”@a.b

Let’s bypass the CSRF protection

Ok, now it’s time to bypass the CSRF protection. Looking at the source of the page, we get an important hint:

Hmm, providing the time that the page was generated seems like weird info to give. Could this have something to do with the CSRF token? A token looks something like this: 1dba20398a370db0f129bc8f1b9154ce. This looks a lot like an MD5 hash. But what could it be a hash of? Maybe something to do with the time?

At this point, it seems like a good idea to try and think like the developer who made this. If we want to make a CSRF token by creating an MD5 hash of something to do with the time, how could we achieve that? Assuming that PHP is used on the server-side, let’s try googling how to get a timestamp in PHP.

The very first result leads us to the time() function. As described in the image above, this function returns the number of seconds since the Unix Epoch. Getting an MD5 hash in PHP can easily be achieved by using the md5() function. So by combining the two, we would get:

md5(time())

Well cool, but how do we know if this is actually how the CSRF token is generated? We don’t! But what we can do now, is to put our hypothesis to the test. Let’s open up a PHP shell and try to execute the code above at the same time we load the challenge page:

WOW! It worked! We just cracked the hash and are now able to generate our own CSRF tokens! We can now craft an exploit, chaining the CSRF vulnerability and the self XSS together to achieve a stored XSS vulnerability! When creating our exploit, we need to remember how the CSRF protection implemented on the challenge page works:

When the page is loaded, a CSRF token is created. This, and only this token is valid until you:
a. Use the token by saving your notes
b. Load the page again

So when creating our exploit, we need to make sure the page is loaded (again) at a time we control, so that we can predict the CSRF token. You can see one suggestion on how this can be done at the bottom of this post. But for now, let’s see how the full exploit works:

Cool, right? We finally solved the challenge!

Thanks for reading along and happy hacking!

@holme_sec

PoC-code:

Bug Bounty Hunter

Bug Bounty Hunter