Introduction

On June 10, 2016, I published an XSS challenge on the hack.me platform called Small Youtube XSS. If you’re only here for the solution and not the write-up, you can find it here.

Keep reading if you want to understand the rules and hints behind the challenge.

Description

This XSS challenge requires multiple techniques to craft a working payload. It is not overly difficult, but it is far from trivial.

Rules

  • No user interaction is allowed.
  • Use only modern browsers (IE11, FF49, etc.).
  • The payload must trigger an alert box displaying the domain name.

Hints

  • Use (?xss=) as the injection point.
  • Look for missing or weak security configurations in HTTP headers and the HTML source.
  • Consider character length restrictions—sometimes, being “too long” can be a disadvantage.
  • Need motivation? Watch this video: https://www.youtube.com/watch?v=hzBCI13rJmA.

If you solve it, feel free to contact me at a.hussam[at]isecur1ty.org. Enjoy!

The challenge has been running for months, and despite being attempted over 1,100 times, only two people have solved it. Below is the solution.

Solution

I no longer have the original source code, so I’ll attempt to reconstruct the logic from memory. The challenge was designed with multi-step filtering, meaning different security mechanisms were applied in a sequence.

  1. The first step replaced keywords like eval, setInterval, and setTimeout with (xss-event).
  2. The second step removed any occurrences of the script keyword (this was key to the solution).
  3. The third step replaced event handler attributes with (xss-event), except for two.

Additionally, HTML entities were enabled on the XSS parameter, making <, >, and " ineffective.

<video width="450" height="400" controls name=injection_here>
  <source src="http://www.google.com/test.mp4" type="video/mp4">
  Your browser does not support the video tag.
</video>

Understanding the Injection Point

The injection occurs within a video tag. HTML5 video events and APIs provide several event handlers, but in this case, most had been filtered out—except for two:

  • onloadstart
  • onratechange (which requires user interaction, so it was excluded).

xss xss

The domain is filtered, so we must use the script removal trick (scrscriptipt => script. Another problem here is that the payload should be at most 26 characters.

xss

Bypassing the Length Restriction

Another obstacle was the character limit—the payload could be no longer than 26 characters.

xss

<?php
 $_GET['xss'] = substr($_GET['xss'], 0, 26);
?>

The Final Exploit

Since the document.domain payload was too long, I needed a different approach. Using eval() would be ideal, but it was blacklisted. To get around this, I used the script removal trick to create evscriptal(name), which effectively bypassed the filter.

The final payload:

<a href="http://s25504-102604-rmx.tarentum.hack.me/myvideo.php?xss=''onloadstart=evscriptal(name)" 
target="javascript:alert(domain);">click me</a>

Additional Methods

To set the window.name, there are multiple approaches:

  • window.open
  • iframe name attribute (which was allowed despite a frame-busting mechanism that could be bypassed).

Solvers

  • Adam Simuntis (adam.simuntis[at]secforce.com) – submitted a well-structured and expected solution.
  • Lucas Philippe – identified a bug in my original challenge code, which has since been fixed.

Conclusion

I hope you enjoyed both the challenge and the write-up. Stay tuned for more!

For any questions, feel free to contact me on Twitter: @Abdulahhusam.