43.3. Injections - Create a Situation

An obvious target for the hacker in order to try to gain unauthorized access to a system is the login screen. An alarming number of real life login situations are not well protected. We shall look at some issues to illustrate, and we shall see what we, as developers, can do to protect our applications.

The core of any web application is the router. Let us look at an example[33]:

Example 43.1. The Router, vulnerable0/routes/router.js

The router contains a map of url-to-handler combinations. Urls not listed here will not be handled by the application. As outsiders we don't have access to this code, but looking at a site, it is probably not difficult to find the login page.

When we click login, a GET request for the login page is sent to the server.

<xi:include></xi:include>

Example 43.2. The Handler Code, vulnerable0/controllers/handlers.js, (fragment)

When we submit the login form we are issuing a POST request to the server. Please look at lines 25, and 35-36 above. The router will accordingly send us to the verifyLogin function in the following requesthandler code. This can easily be verified by displaying the source code of the form in your browser.

/*
 * handlers.js
 * Requesthandlers to be called by the router mechanism
 */

// ...

const models = require("../models/dbCode");                 // models are datahandlers

// ...

module.exports = {
    // ...
    async verifyLogin (req, res, data) {
        let obj = lib.makeWebArrays(req, data);             // home made GET and POST objects
        let r = await models.verify(obj);
        console.log(`read for login-verify: ${r.length} = number read`);
        if (r.length > 0) {                                 // anybody read
            cookie.set(req, res, '' + r[0].name);           // create login cookie
            res.writeHead(httpStatus.MOVED_TEMPORARILY, {   // write header
                "Location": '/'
            });
            res.end();                                      // send it
        } else {
            res.writeHead(httpStatus.MOVED_TEMPORARILY, {   // write header
                "Location": '/logout'
            });
            res.end();                                      // send it
        }
    },
    // ...
}

Example 43.3.  The Model[34] Code, vulnerable0/models/dbCode.js (fragment)

The verification needs the model code in the verify function of the dbCode.js.

/*
 * models
 * handlers for data manipulation
 */
const maria = require("mariadb");                               // file system access
const dbp = require('./dbParams.js');
const crypto = require('crypto');

// ...

module.exports = {
    // ...
    async verify(obj) {
        const dbh = await maria.createConnection(dbp);
        let email = obj.POST.email;
        let pwd = await crypto.createHash('sha512')
                            .update(obj.POST.password, 'utf8')
                            .digest('hex');
        let sql = `select name, password
                   from user
                   where email = '${email}' and password = '${pwd}'`;
        let rows = await dbh.query(sql);
        return rows;
    }
}

This code connects to the database server, tries to read from the database based on the entered credentials, and returns the result to the controller that invoked it.

In order to verify a hashed password, we must hash the entered clear text password with the algorithm used to hash passwords in the system, and if the two hashes are equivalent, and the user ids match too, login is registered by issuing a cookie as a token.




[33] May be cloned with git from https://phidip@bitbucket.org/phidip/vulnerable0.git

[34] Not as in do it like this and you're safe, but rather as in the Model-View-Controller sense of the term.