Mobile Me Madness

Mon 4th July 11

I recently released my Bucket Finder script and Darren featured it on and episode of Hak5. I got some feedback pointing out that Mobile Me works in the same way allowing users to access their public accounts through the following style of URL https://public.me.com/<account name>. Knowing Mobile Me stores personal info rather than business and it links in with the desktop I figured that it would give some pretty rich pickings. Unfortunately Mobile Me no longer accepts new sign ups so all the analysis I've done is based on existing data.

I found an account with a number of public files and started looking through the source, the first thing I noticed is that none of the files shown on the screen are in the source so I figured we must be looking at some kind of AJAX call to retrieve the file listings. Using Firebug I spotted the following URL being called and returning the data I was after:

https://public.me.com/ix/XXXX?protocol=roap&item=properties&repfmt=swjson&depth=1&reqid=1234566778888&lang=en

Hitting this URL gives a nice directory listing in JSON format, I can handle JSON but would rather deal with XML as I've already got the framework in place for it so I started manipulating the querystring. I found that I can drop the reqid and lang fields and nothing changes, changing depth to 2 gave a directory listing to a depth of 2 but changing it 3 or above gave an error message so while it would be nice it wouldn't be possible to set it to 99 and dump the whole listing in a single go.

The most important change was when I dropped the repfmt field, the data returned magically changed to XML. This is much better! This leaves me with the URL:

https://public.me.com/ix/XXXX?protocol=roap&item=properties&depth=1

and the following XML which I've cut down to show a file and directory:

<?xml version="1.0" encoding="utf-8" ?>
<multistatus xmlns="DAV:">
<D:response xmlns:D="DAV:">
 <D:href>/ix/hank/
 <D:propstat>
  <D:prop>
   <D:modificationdate>2011-03-28T15:39:25Z
   <D:getlastmodified>Mon, 28 Mar 2011 15:39:25 GMT
   <D:resourcetype>
    <D:collection />
   </D:resourcetype>
   <D:creationdate>1969-12-07T23:08:01Z
   <D:getetag>1
  </D:prop>
  <D:status>HTTP/1.1 200 OK
 </D:propstat>
</D:response>
<D:response xmlns:D="DAV:">
 <D:href>/ix/XXXX/file.mp4
 <D:propstat>
  <D:prop>
   <D:modificationdate>2009-12-09T02:33:00Z
   <D:getcontentlength>118727222
   <D:getlastmodified>Wed, 09 Dec 2009 02:33:00 GMT
   <D:resourcetype />
   <D:creationdate>2009-12-09T02:12:10Z
   <D:getetag>"u-1abcdefn-5hp-gbsyk1134-6p8vze7o0"
  </D:prop>
  <D:status>HTTP/1.1 200 OK
 </D:propstat>
</D:response>
<D:response xmlns:D="DAV:">
 <D:href>/ix/XXXX/folder/
 <D:propstat>
  <D:prop>
   <D:modificationdate>2011-02-13T19:46:51Z
   <D:getlastmodified>Sun, 13 Feb 2011 19:46:51 GMT
   <D:resourcetype>
    <D:collection />
   </D:resourcetype>
  </D:prop>
  <D:status>HTTP/1.1 200 OK
 </D:propstat>
</D:response>
</multistatus>

Looks like WebDav to me which gives the choice, parse it as XML or find and learn a WebDav library. Seeing as I already understand XML and have no idea about WebDav I've gone with parsing the XML. Its pretty simple, if the D:resourcetype contains a D:collection then it is a directory otherwise it is a file. For files dump the URL and associated information. If it is a directory then change the URL to point at that directory and recurse.

That should be it, its simple XML, parse it and move on, but something I noticed when doing my initial recon with a browser is that the JSON included what *nix calls hidden files and directories, those which start with a dot. The main one I spotted was .Trashes, the OS X recycle bin. When I looked at the output from my script the .Trashes directory was missing for my test user.

My first thought was it was the difference between JSON and WebDav but changing back to JSON didn't make the hidden items reappear. There must be a difference in the two requests so I loaded up Burp and had it proxy both Firefox and my script then started fiddling with fields till I finally found the key difference, the user agent string. Turns out, using the default Ruby one I don't get hidden files but if I switch to a Firefox one then they appear.

I've no idea why that would be the case, especially as the web interface then goes and hides these files so they are never actually used even when they are returned. Anyway, adding the new UA to the script and re-running pulled down all files, including hidden ones.

I figure the trash can is quite an important directory to get access to as people might put files into their public folder but then realise what they have done and delete them without realising they are still available to be undeleted in the trash. Other files, such as .DSStore can also contain useful information so they are well worth checking.

The script is called Me Finder and you can download it from its project page.

As with the Bucket Finder I've ran through a couple of word lists and done some analysis, you can read about that here - Analysing Mobile Me.