SQL Injection Is Still An Issue (Part 2 of the SQL Series)

Alex Archondakis

Managing Consultant

Alex is one of our managing consultants here at Pentest People. Focusing mainly on web application penetration testing. Alex has spoken at many key events while with us, including BSides London and even DSS ITSEC Latvia.

SQL Injection Is Still An Issue (Part 2 of the SQL Series)

SQL Injection

SQL Injection, somehow is still the top vulnerability in the OWASP Top 10. Here at Pentest People, SQL injection is one of the most high risk vulnerabilities we see. With so many people aware of this vulnerability, how is it that SQL Injection is still common? I think it’s most likely that people rely on built in features too much.

Many php applications and APIs are built using some kind of framework such as Laravel, Phalcon, Symfony and so on. These types of frameworks will have their own SQL query builder built in, which in term use PDO to handle SQL queries.

PHP Data Objects (PDO), provide a simple ‘interface to interface’ for accessing databases. This interface will allow us to prepare statements that we send to the database. Many developers believe the the use of prepared statements via a frameworks’ query builder will prevent SQL injections.

Although a framework can help, it is still your responsibility to validate and sanitise any user inputs and outputs that will be used in a query. At the end of the day, you can not rely on somebody else’s code to keep your code safe.

Sometimes with queries, it’s not ideal to (or not possible to) use a query builder, so raw SQL may have to be written. This is rare, but it happens, especially with long queries using multiple joins and subqueries etc. This is where SQL injection is likely to happen.

If we look at a very simple example of using a raw SQL statement in Laravel, this query is safe:

public function getStatusCount(){  ‘$count = DB::table('users')  ->select(DB::raw('count(*) as user_count, status'))  ->where('status', '=', ‘verified’)  ->groupBy('status')  ->get();  return $count;}

Now, this is a very simple example, but could easily be made exploitable through lazy development or inexperience. Let’s update this admin function to take in a status:

public function getStatus($status){  users = DB::table('users')  ->select(DB::raw('count(*) as user_count, status'))  ->where('status', '=', $status)  ->get();  return $count;}

What is $status? This is potentially dangerous, although as mentioned this is an admin function, a lazy developer might believe this ok to leave in. You trust your colleagues right? (Don’t btw).

What could be more dangerous, is if this function at some point becomes open to the public, again through lazy development or another vulnerability is exploited. Such as Second Order SQL Injection, that we still need to discuss in a future blog.

Even the Laravel documentation warns against this ‘Raw statements will be injected into the query as strings, so you should be extremely careful to not create SQL injection vulnerabilities.’

So how do we protect ourselves when using raw SQL statements through a framework? Again this answer is simple and has been repeated many many times, validate, validate validate!

Next time we will look into Second Order Injection in detail.

Click here to find out more about our Web Application Testing Services.

Video/Audio Transcript