I Know A LOT About Your Web Browser and Computer

Web browser hacking techniques are frequently platform dependent. Creating stable and cross-platform proof-of-concept code is often challenging. So it is helpful for a [malicious] website, such as http://maliciouswebsite/, to learn everything it can about a visiting browser before executing a real-world attack. We can loosely describe this process as “browser interrogation.”

Browser interrogation is important is to understand because it is used pervasively across the Web – it’s what makes browser tracking and device fingerprinting possible. The more someone knows about a browser’s particular configuration, the more accurately tracking companies can follow it from one website to the next — even if the browser’s cookies are deleted. It turns out that a browser’s configuration is often highly unique. The EFF’s Panopticlick project provides some fantastic insights in this area.

For our purposes here, we just want to create stable browser attacks. Below are explanations of many of the basic techniques (and a few advanced examples) of browser interrogation.


Operating System and Browser Type via User-Agent Headers

The easiest way to begin learning to perform browser interrogation is by having a look at the User-Agent header. User-Agent is a header that’s optionally sent with every Web request a browser makes. They reveal to every website — websites like http://maliciouswebsite/ — the distribution and version of your browser and operating system. These are incredibly useful bits of intelligence when attempting to carry out further browser attacks.


User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.89 Safari/537.1

In this case, the visitor’s computer’s operating system is running on an Intel Mac OS X 10.7.5 and the browser being used is Google Chrome version 21.0.1180.89. Of course it is possible for the browser to spoof or suppress this information, that is misinform the website, however the vast majority of people do not do this. Doing so often breaks website whose cross-browser Web code depends on User-Agent data.


Language Setting, ActiveX Support, and the Referer.

Language Setting:

A browser’s language setting is a strong indication of where the visitor is geographically located and how to localize an attack if user interaction is required. There are two places to get the language setting.

1)   The Accept-Language header that’s sent along with each Web request. As we can see, the person is probably English-speaking.


GET / HTTP/1.1

Host: http://maliciouswebsite/

User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.89 Safari/537.1



2) This same information can be obtained in the “navigator.language” property that’s accessible in Javascript space.

<* script>
if (navigator.language) {
<* /script>


ActiveX Support:

Detecting if ActiveX is available (as in Internet Explorer) can prove quite useful as an exploit vector.

 <* script>


     console.log(“ActiveX Unavailable”);

} else {

     console.log(“ActiveX Available”);


<* /script>



And finally, there is the Referer. Yes, “Referer” is purposely misspelled. The reason is that it’s misspelled in the RFC specification. Anyway, a Referer is an optional header sent with each Web request that informs websites where the traffic originated – that is, what Web page the browser was on last. As just one example of their usefulness, Referers can reveal what keywords a visitor used to find a Web page they’ve just landed on.


 GET / HTTP/1.1

Host: http://maliciouswebsite/

User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_5) AppleWebKit/537.1 (KHTML, like Gecko) Chrome/21.0.1180.89 Safari/537.1



Referer data can also be obtained through Javascript by using “document.referrer.”


Virtualization Detection via Screen Dimensions

Javascript also has access to convenient methods for determining the computer’s screen dimensions and color depth. These pieces of information are helpful for browser fingerprinting and for inferring what type of visitor http://maliciouswebsite/ is encountering. A bigger screen may, for instance, indicate a more financially well off or technologically savvy visitor.

Screen dimensions can also be used to detect if the browser is operating in a virtualized environment.  All computer displays use one of a well-known and well-defined list of standard screen size configurations.  If the screen dimensions the browser is presenting are “standard,” then the browser is probably not being virtualized. If the screen dimensions are abnormal, as may be caused by the virtualization application’s window, the there is a good chance the browser is being virtualized.

 <* script>

var dimensions = {

‘320, 200′ : ”,

‘320, 240′ : ”,

‘640, 480′ : ”,

‘800, 480′ : ”,

‘768, 576′ : ”,

‘854, 480′ : ”,

‘1024, 600′ : ”,

‘1152, 768′ : ”,

‘800, 600′ : ”,

‘1024, 768′ : ”,

‘1280, 854′ : ”,

‘1280, 960′ : ”,

‘1280, 1024′ : ”,

‘1280, 720′ : ”,

‘1280, 768′ : ”,

‘1366, 768′ : ”,

‘1280, 800′ : ”,

‘1440, 900′ : ”,

‘1440, 960′ : ”,

‘1400, 1050′ : ”,

‘1600, 1200′ : ”,

‘2048, 1536′ : ”,

‘1680, 1050′ : 1,

‘1920, 1080′ : ”,

‘2048, 1080′ : ”,

‘1920, 1200′ : ”,

‘2560, 1600′ : ”,

‘2560, 2048′ : ”


var wh = screen.width + “, ” + screen.height;

if (dimensions[wh] != undefined) {

console.log(“Not virtualized”);

} else {

console.log(“Operating in a virtualized environment”);


<* /script>


Identifying the Default Browser

A visitor’s computer may have several different browsers installed, so there is no guarantee they are using their “Default Browser” at the time they arrive. The Default Browser is the browser that the operating system automatically executes when clicking on links, such as in a desktop email or a calendar application. If the visiting browser is Internet Explorer, due to it’s support for “document.mimeType,” it is possible to detect the Default Browser.

<* script>

var mt = document.mimeType;

 if (mt) {

var msg = “Your default browser is: “;

if (mt == “Safari Document”) { msg += “Safari”; }

if (mt == “Firefox HTML Document”) { msg += “Firefox”; }

if (mt == “Chrome HTML Document”) { msg += “Chrome”; }

if (mt == “HTML Document”) { msg += “Internet Explorer”; }

if (mt == “Opera Web Document”) { msg += “Opera”; }


} else {

console.log(“This proof-of-concept only supports Internet Explorer.”);


<* /script>


Identifying Installed Plug-Ins

Browsers regularly come into contact with rich content, such as videos, PDFs, and so on. To render this kind of content, the browser relies on third-party software like Adobe Flash and Reader — generally referred to as Plug-Ins. The simplest way to see what Plug-Ins a browser has installed is through Javascript’s access to “navigator.plugins,” but not all browsers support it. For a more cross-browser solution, I’ve found nothing better than the “PluginDetect Library” by Eric Gerds.


<* script type=”text/javascript” src=”/plugindetect.js”><* /script>

<* script>


var quicktime = PluginDetect.getVersion(“QuickTime”) || “”;

var java = PluginDetect.getVersion(“Java”) || “”;

var flash = PluginDetect.getVersion(“Flash”) || “”;

var shockwave = PluginDetect.getVersion(“Shockwave”) || “”;

var deval = PluginDetect.getVersion(“DevalVR”) || “”;

var wmp = PluginDetect.getVersion(“WindowsMediaPlayer”) || “”;

var silverlight = PluginDetect.getVersion(“Silverlight”) || “”;

var vlc = PluginDetect.getVersion(“VLC”) || “”;

var adobereader = PluginDetect.getVersion(“AdobeReader”) || “”;

var realplayer = PluginDetect.getVersion(“RealPlayer”) || “”;


if (quicktime) { console.log(‘QuickTime: ‘ + quicktime); }

if (java) { console.log(‘Java:’ +  java); }

if (flash) { console.log(‘Flash: ‘ + flash); }

if (shockwave) { console.log(‘Shockwave: ‘ + shockwave); }

if (deval) { console.log(‘DevalVR: ‘ + deval); }

if (wmp) { console.log(‘Windows Media Player: ‘ + wmp); }

if (silverlight) { console.log(‘Silverlight: ‘ +  silverlight); }

if (vlc) { console.log(‘VLC: ‘ + vlc);    }

if (adobereader) { console.log(‘Adobe Reader: ‘ + adobereader); }

if (realplayer) { console.log(‘Real Player: ‘ + realplayer); }


if (navigator.plugins) {

for (var p = 0; p < navigator.plugins.length; p++) {

var pName = navigator.plugins[p].name;

var known = /(quicktime|java|flash|shockwave|devalvr|windows media player|silverlight|vlc|adobe reader|real player)/i;

if(! pName.match(known)) {





<* /script>


Identifying Installed Extensions and Add-Ons

In Chrome, they are called “Extensions.” In Firefox, they are called “Add-Ons.” Whatever the name, Extensions and Add-Ons are different than Plug-Ins. Plug-ins, generally speaking, are for rendering [rich] content, beyond just basic HTML and images. Extensions and Add-Ons are third-party applications installed into a browser that extend its functionality to improve the user experience. Good examples of the thousands available for download are ad blocking, Web developer tools, downloading of YouTube videos, and so on.

While the ability for http://maliciouswebsite/ to detect what Plug-Ins the browser has installed appears generally accepted, doing the same with Extensions and Add-Ons is not – that is, at least some browser vendors have certain security protections that prevent the enumeration of Extensions and Add-Ons. We have to get hacky to get around those protections. There are generally two techniques for detecting what Extensions and Add-Ons are installed.

1)   Local Protocol and Event Handlers: Chrome supports an internal protocol handler called “chrome-extension://,” which can be used to uniquely reference an installed Extension. Example:


<* script src=”chrome-extension://aknpkdffaafgjchaibgeefbgmgeghloj/manifest.json ” onload=”extensionDetected()”><* /script>


The long string of seemingly random letters is a unique ID given to each Chrome Extension when they are made available for download. It is trivial to create a list of IDs for the thousands of the most popular Extensions by scraping Google’s public repository. (The live demo has such a list.) The “manifest.json” returns JSON formatted data describing what files are contained within the Extension package. Collectively, the ID and manifest.json filename can be combined to create a URL reference for each Extension, as shown in the example above.

By using a SCRIPT tag and an OnLoad event handler, it is possible to detect for the presence of nearly any Chrome Extension. If the OnLoad event handler executes, then the URL exists in the browser, which may inform http://maliciouswebsite/ that the Extension is present. Hundreds, thousands of similar SCRIPT tags can be loaded like this to perform an Extension brute-force style search. This is essentially what the live demo code does.

In the past a similar technique could be employed for Firefox, but it has since been closed. Fortunately, not all is lost, there is another method.

2)   Object Detection: Many Firefox Add-Ons and Chrome Extensions modify the DOM in unique and detectable ways. For example, if AdBlockPlus is present and the Web page attempts to load a blacklisted advertising URL, then obviously that DOM object will not be present. This is a dead give away that some form of ad blocking is being performed. Other Add-Ons, such as Web Developer Tools, Firebug, and Greasemonkey, have been known to include uniquely named objects in the DOM. A quick check for their existence is a sure sign that the Add-On is installed and enabled.

<* script>
if (typeof uniquelyNamedObject != ‘undefined’){
    console.log (“Add-On Present”);
<* /script>

The big drawback of Firefox Add-On detection is that the upfront research is very time consuming and laborious, and it’s not guaranteed you can find a detectable difference it makes in the DOM.

We’ve covered a lot of the standard browser interrogation techniques, at least enough to make all the following attacks possible. For a more complete list of techniques have a look at BrowserSpy.


I Know…

This entry was posted in Web Application Security on by .

About Jeremiah Grossman

Jeremiah Grossman is the Founder and interim CEO of WhiteHat Security, where he is responsible for Web security R&D and industry outreach. Over the last decade, Jeremiah has written dozens of articles, white papers, and is a published author. His work has been featured in the Wall Street Journal, Forbes, NY Times and hundreds of other media outlets around the world. As a well-known security expert and industry veteran, Jeremiah has been a guest speaker on six continents at hundreds of events including TED, BlackHat Briefings, RSA, SANS, and others. He has been invited to guest lecture at top universities such as UC Berkeley, Stanford, Harvard, UoW Madison, and UCLA. Jeremiah is also a co-founder of the Web Application Security Consortium (WASC) and previously named one of InfoWorld's Top 25 CTOs. He serves on the advisory board of two hot start-ups, Risk I/O and SD Elements, and is a Brazilian Jiu-Jitsu Black Belt. Before founding WhiteHat, he was an information security officer at Yahoo! Jeremiah can be found on Twitter @jeremiahg.