Chapter 8. Content Rendering with Browser Plug-ins

Browser plug-ins come in many forms and shapes, but the most common variety give the ability to display new file formats in the browser, as if they were HTML. The browser simply hands over the retrieved file, provides the helper application with a rectangular drawing surface in the document window, and essentially backs away from the scene. Such content-rendering plug-ins are clearly distinguished from browser extensions, a far more numerous bunch that commonly relies on JavaScript code to tweak how the already-supported, in-browser content is presented to the user.

Browser plug-ins have a long and colorful history of security flaws. In fact, according to some analysts, 12 out of the 15 most frequently exploited client-side vulnerabilities in 2010 could be attributed to the quality of plug-in software.[161] Many of these problems are because the underlying parsers were originally not meant to handle malicious inputs gracefully and have not benefited from the intense scrutiny that the remainder of the Web has been subject to. Other problems stem from the unusual security models devised by plug-in developers and the interference between these permissions, the traditional design of web browsers, and the commonsense expectations of application developers.

We will review some of the security mechanisms used by popular plug-ins in the next chapter of this book. Before taking this dive, it makes sense to look at the ways plug-ins integrate with other online content and the common functionality they offer.

Content-rendering plug-ins can be activated in a couple of ways. The most popular explicit method is to use <embed src=...> or <object data=...> markup in a “host” HTML document, with the src or data parameter pointing to the URL from which the actual plug-in-recognized document is to be retrieved. The dimensions and position of the drawable area allocated for the plug-in can be controlled with CSS (or with legacy HTML parameters).

In this scenario, every <embed> or <object> tag should be accompanied by an additional type parameter. The MIME type specified there will be compared to the list of MIME types registered by all the active plug-ins, and the retrieved file will be routed to the appropriate handler. If no match is found, a warning asking the user to download a plug-in should be theoretically displayed instead, although most browsers look at other signals before resorting to this unthinkable possibility; examining Content-Type or the apparent file extension spotted in the URL are two common choices.

Additional input to the plug-in is commonly passed using <param> tags nested inside the <object> block or through nonstandard additional parameters attached to the <embed> markup itself. The former, more modern approach may look like this:

<object data="app.swf" type="application/x-shockwave-flash">
  <param name="some_param1" value="some_value1">
  <param name="some_param2" value="some_value2">
  ...
</object>

In this content-inclusion mode, the Content-Type header returned by the server when retrieving the subresource is typically ignored, unless the type parameter is unknown to the browser. This is an unfortunate design, for reasons that will be explained shortly.

The other method for displaying plug-in content involves navigating directly to a suitable file. In this case, and in the case of <embed> or <object> with a missing type parameter, the Content-Type value obtained from the server is honored, and it will be compared with the list of plug-in-recognized MIME types. If a match is found, the content is routed to the appropriate component. If the Content-Type lookup fails or the header is missing, some browsers will examine the response body for known content signatures; others just give up.

As noted in the previous section, in certain scenarios the Content-Type parameter on a retrieved plug-in-handled file is ignored, and the type parameter in the corresponding markup on the embedding page is used instead. While this decision is somewhat similar to the behavior of other type-specific content-inclusion tags (say, <img>), as discussed in Type-Specific Content Inclusion in Frames, it has some unique and ultimately disastrous consequences in the plug-in world.

The big problem is that several types of plug-ins are essentially full-fledged code execution environments and give the executed applications (applets) a range of special privileges to interact with the originating domain. For example, a Flash file retrieved from fuzzybunnies.com would be granted access to its originating domain (complete with a user’s cookies) when embedded on the decidedly rogue bunnyoutlet.com.

In such a scenario, it would seem to be important for fuzzybunnies.com to be able to clearly communicate that a particular type of a document is indeed meant to be interpreted by a plug-in—and, consequently, that some documents aren’t meant to be used this way. Unfortunately, there is no way for this to happen: The handling of a retrieved file is fully controlled by the embedding site (in our example, by the mean-spirited bullies who own bunnyoutlet.com). Therefore, if the originating domain hosts any type of user-controlled content, even in a nominally harmless format (such as text/plain or image/jpeg), the owners of bunnyoutlet.com may instruct the browser to disregard the existing metadata and route that document to a plug-in of their choice. A simple markup to achieve this sinister goal may be

<object data="http://fuzzybunnies.com/avatars/user11630.jpg"
        type="application/x-shockwave-flash">

If this turn of events seems wrong, that’s because it is. Security researchers have repeatedly demonstrated that it is quite easy to construct documents that are, for example, simultaneously a valid image and a valid plug-in-recognized executable. The well-known “GIFAR” vulnerability, discovered in 2008 by Billy Rios,[162] exploited that very trick: It smuggled a Java applet inside a perfectly kosher GIF image. In response, Sun Microsystems reportedly tightened down the Java JAR file parser to mitigate the risk, but the general threat of such mistakes is still very real and will likely rear its ugly head once more.

Interestingly, the decision by some developers to rely on Content-Type and other signals if the type parameter is unrecognized is almost as bad. This decision makes it impossible for the well-intentioned fuzzybunnies.com to safely embed a harmless video from the rogues at bunnyoutlet.com by simply specifying type="video/x-ms-wmv", because if any of the visitors do not have a plug-in for that specific media type, bunnyoutlet.com will suddenly have a say in what type of plug-in should be loaded on the embedding site instead. Some browsers, such as Internet Explorer, Chrome, or Opera, may also resort to looking for apparent file extensions present in the URL, which can lead to an interesting situation where neither the embedding nor the hosting party has real control over how a document is displayed—and quite often only the attacker is in charge.

A much safer design would require the embedder-controlled type parameter and the host-controlled Content-Type header to match (at least superficially). Unfortunately, there is currently no way to make this happen. Several individual plug-ins try to play nice (for example, following a 2008 overhaul, Adobe Flash rejects applets served with Content-Disposition: attachment, as does the built-in PDF reader in Chrome), but these improvements are few and far between.