Vulnerabilities Explained - Injection

Jul 6, 2020 min read

OWASP Top 10 - Injection

What is an Injection?

Injection vulnerabilities happen anytime untrusted data is used within a system. Commonly this occurs when a user passes some information to a system and the system starts to interpret the input without validation or sanitization.

Examples of Injections

SQL Injection

This example uses a common web application login for to find a user in the database through string concatenation.

Another example using a search bar to find relevant items using a fuzzy SQL “LIKE” search

http://myapplication.com/products?id=1'; DROP DATABASE users --

NoSQL Injection

Example Code - Bad

db.collection('users').find({
  "user": req.query.user,
  "password": req.query.password
});

Let’s look at an example payload and see how this query is vulnerable to injection:

  {
    "user": {"$ne": null},
    "password": {"$ne": null}
  }

By passing in $ne, not equal, we are asking the NoSQL database to find a user where the user and password are not equal to null, should be any user in the database. There are several sanitizing libraries available. For our example we’re using Mongoose to define our schema and communicate with out MongoDB database so we’ll use the Mongo Sanitize library to first sanitize any user input before passing the query to our database.

Example Code - Good

// Mongoose to define schema
const sanitize = require("mongo-sanitize");

const email = sanitize(req.body.email);
const password = sanitize(req.body.password);

db.collection('users').find({
  "user": user,
  "password": password
});

Browser based cookies are another input that the user (or machine) has access to. This is another common area for injection vulnerabilities.

Avoid:

  • Easily guessable cookie names (keys) or values
  • Values that can be iterated user01, user02, user03…
  • Boolean values that you rely on for things like authorization, e.g. { admin: true }

OS Command Injection

Problem:

Solution:

  1. Ask “Do we need this functionality at all?!?”
  2. Create a simple command lookup key, that ensures user is authorized to perform action

This is an example NodeJS/ ExpressJS API endpoint that allows an authorized user to request the execution of an operating system command from an approved list of commands.

const exec = require('child_process').exec;

app.post('/perform-command/:command_id', authorizeUserMiddleware, (req, res) => {
  
  const command_id = req.params.command_id;
  
  if(!command_id) {
    res.status(400).send('Missing or invalid command_id');
  } else {
    const safe_commands = {
      1: "OS Command 1",
      2: "OS Command 2"
    };

    const command_to_execute = safe_commands[command];

    if(!command_to_execute){
      res.status(400).send('Missing or invalid command_id');
    } else {
      exec(command_to_execute, (error, stdout, stderr) => {
        if(error) {
          res.status(500).send('Error executing command, please retry')
        } else {
          res.status(200).send('Successfully executed command')
        }
      })
    }
  }
})

Prevention

Query Parameterization

Never trust unvalidated or un-sanitized data!!! Most database libraries we use to communicate with our databases provide something called “query parameterization”. This allows us to construct a database query and the library with handle escaping and sanitizing input before the query is run by the database engine. This is where it’s far better to use a trusted library than trying to sanitize input on our own.