Chapter 16. SQL Injection

Having addressed Unix and Windows attacks in general, we will now briefly touch on the exciting, multi-platform area of attacking databases via SQL injection. This chapter covers various database attack methods and defense approaches and culminates in a real-life SQL injection attack against PHP-Nuke, a database-driven[1] open source web site framework that has displayed many of the flaws we describe.

Introduction to SQL

According to Merriam-Webster, a database is “a usually large collection of data organized especially for rapid search and retrieval (as by a computer).” In other words, a database is a structured collection of records. Without delving into types of databases, we will note that when most people talk about databases they mean relational databases, exemplified by such commercial products as Oracle, Microsoft SQL Server, Sybase, MySQL, or PostgreSQL. Relational databases store data in the form of related tables of records. The relationship between tables is manifested in the form of linked records. So, a value in one table might be linked to a value in some other table, which is then called a foreign key.

Such tables of data can be accessed or “queried” using specially formatted request statements. The standard for this formatting is called Structured Query Language (SQL). SQL first came into being as SEQUEL, designed by IBM in 1974. SEQUEL quickly found its way into commercial database systems (such as Oracle, in 1979) and became widespread soon after.

SQL was standardized by the American National Standards Institute (ANSI) in 1991. Most modern databases support both the SQL standard (such as SQL 92) and various vendor-specific extensions, sometimes developed to optimize performance and allow better interoperability with other products of the vendor.

Thus, a relational database is a data storage solution queried using SQL statements. Obviously, databases find innumerable uses in modern information technology. With the advent of the Internet, databases became used to drive web sites and various web applications. That is how SQL injection attacks achieved notoriety. And that is where we start our journey into SQL injection.

SQL Commands

The following section provides a few SQL basics. Table 16-1 shows some of the popular SQL commands with examples of their uses. SQL includes much more than these, but almost every database application uses some of these commands.

Table 16-1. Common SQL commands

SQL command

Functionality

Example

SELECT

Extract data from the database.

SELECT * FROM user_table;

UNION

Combine the results of several SELECT queries together, removing duplicate records.

SELECT first, last FROM customers WHERE city = `NYC’ UNION SELECT first, last FROM prospects WHERE city = `NYC’

INSERT

Put new data in the database table, add a new row to the table.

INSERT INTO itemfeatures VALUES (130012, 4);

UPDATE

Change the records in the database.

UPDATE items SET description = `New Honeypot’ WHERE item_id = 150002;

DELETE

Delete specific records from a table.

DELETE FROM alerts WHERE devicetypeid = 13 AND alarmid NOT IN (1,2,5) ;

CREATE

Create new data structures (such as tables) within the database.

CREATE TABLE high as SELECT * FROM events WHERE name = 2;

DROP

Remove the table from the database.

DROP TABLE user_table;

ALTER

Modify the database table by adding columns.

ALTER TABLE user_table ADD address varchar(30);

In addition to the commands in Table 16-1, there are some command modifiers that we use throughout this chapter. Table 16-2 shows some of the important ones.

Table 16-2. SQL command modifiers

SQL command

Functionality

Example

WHERE

Used to define the fields to be processed by the SELECT, INSERT, DELETE, and other commands

SELECT * FROM user_table WHERE username ='anton’;

LIKE

Facility used to do approximate matching within the WHERE clause; the `%' indicates the wildcard

SELECT * FROM user_table WHERE username LIKE ‘anton%';

AND, OR, NOT

Binary logic operators used, for example, within WHERE clauses

SELECT * FROM user_table WHERE username ='anton’ AND password='correcto’;

VALUES

Used to specify the inserted or changed values for the INSERT and UPDATE commands

INSERT INTO user_table (username, password) VALUES (`anton', ‘correcto'),

The commands in Table 16-1 may be executed on a database system in many different ways. The simplest is the database shell. Here’s how to run some of the above commands using the MySQL database shell called “mysql” on a Linux system.

#mysql
$ use FPdb;
$ select count(*) from events;
74568576

The commands above first specify a database to use (called “FPdb”) and then query the table called “events” for a total number of records, which is returned on the next line. For most databases, the command needs to be terminated by a “;” character.

Other commands may also be run from a shell, and the results are captured in a file. In the case of a database-driven web site or web application, the commands are likely run on a database through some sort of an API, such as JDBC[2] or ODBC.[3]

Before we delve into attacks, we will show how relational databases and SQL are used in modern applications, using examples from database-driven web sites deployed on Windows and Unix.

Use of SQL

A modern, database-driven web site is characterized by a conspicuous lack of the classic *.html or *.htm extensions for files, preferring instead the newer extensions *.asp, *.php, or many others. Such extensions indicate the use of scripting languages with embedded database commands. The *.asp (which stands for Active Server Pages) extension is common on Windows as it is a Microsoft format. *.php (which uses the PHP language; see http://www.php.net) is common on all *.php platforms.

Each file, such as index.php, contains scripting language commands and usually at least some SELECT queries. These queries are used to combine the content taken from the database with some site-specific formatting performed by the script.

For example, the PHP-Nuke’s web site framework builds various types of web site content (user forums, polls, news, ads, and others) using PHP and a SQL database. The user is responsible for populating the database with content, while the scripting language code builds the actual site structure. Ultimately, the dynamically generated HTML is sent to a visiting user’s browser for display without being stored on a disk on the server.

The database scripting PHP code is full of statements such as the following:

SELECT main_module from ".$prefix."_main
SELECT * FROM ".$prefix."_referrer
SELECT pwd FROM ".$prefix."_authors WHERE aid='$aid'
SELECT user_password FROM ".$user_prefix."_users WHERE user_id='$uid'
SELECT active FROM ".$prefix."_modules WHERE title='$module'
SELECT topicname FROM ".$prefix."_topics WHERE topicid='$topic'
SELECT mid, title, content, date, expire, view FROM ".$prefix."_message WHERE 
active='1' $querylang

Without going into specifics of the PHP scripting language and the details of the application, we can say that most such commands extract various pieces of data from the database and then pass this data to other parts of the application for display. Some others (most likely those mentioning $password) [4] refer to user authentication. These likely extract user credentials from the database and compare them with user input supplied through the web site.

There are many other ways that SQL is used to drive the frontend application (that is, the part of the application visible to the user—the opposite of “backend” components such as the database), but web site frameworks provide the most graphic and familiar example. Thus, we use them as examples throughout the chapter.

SQL Injection Attacks

We can define SQL injection as an abuse of a database-connected application by passing an untrusted and unauthorized SQL command through to an underlying database.

Let us step back and study this definition in more detail. The first thing to notice is that SQL injection is not an attack against a database. It is an attack against the application using the database. In some sense, the database makes the attack possible by simply being there. While one might argue (and people do, if flames on the corresponding security mailing lists are an indication) that certain steps taken on the database level can prevent SQL injection, the attack is ultimately an abuse of a poorly written application. Thus, most SQL injection defenses are focused on the application and not on the database.

Second, the attacks consist of passing untrusted SQL statements to the database. In a way, the application flaws allow these statements to be passed to the database, with one of several results (to be discussed below) occurring as a result.

Third, you might notice that since SQL is a standard and is used by most databases, the attacks are multi-platform. In fact, the attacks are not only multi-platform, but also multi-application and multi-database. As we will see, many different applications and databases fall victim to these attacks. The vulnerabilities are by no means limited to web applications and web sites; it is just that those are the most common database-driven applications.

A brief look at history is appropriate here. The first public description of a SQL injection attacks was the exciting “How I hacked PacketStorm,” by Rain Forest Puppy (posted in February 2000 at http://www.wiretrip.net/rfp/txt/rfp2k01.txt). It is also obvious that the attack was known in the hacking underground well before this account became public. Now, let’s look at SQL injection attacks in more detail.

Attack Types

We will first categorize SQL injection attacks by their results to the attacker (see Table 16-3). We will then further refine the categories by the type of SQL statement used.

Table 16-3. SQL injection types

Attack type

Results

Unauthorized data access

Allows the attacker to trick the application in order to obtain from the database data that is not supposed to be returned by the application or is not allowed to be seen by this user

Authentication bypass

Allows the attacker to access the database-driven application and observe data from the database without presenting proper authentication credentials

Database modification

Allows the attacker to insert, modify, or destroy database content without authorization

Escape from a database

Allows the attacker to compromise the host running the database application or even attack other systems

As you can see from Table 16-3, SQL injection attacks are not to be taken lightly. Databases form the core of many online businesses and play crucial roles in other business transactions. Allowing attackers to view, modify, or penetrate databases can pose a catastrophic risk to your organization. Even without breaking out of the database application, the range of attacks that are possible is staggering. With this in mind, let’s look at unauthorized data access first.

Unauthorized data access

How does one trick an application into revealing more database content than it was originally designed to reveal?

The key is a SQL statement containing variables. For example, if the application runs the following SQL statement:

SELECT first,last,preferences FROM main_table;

then SQL injection is impossible, as there is no variable input passed to the query.

Now consider the following:

SELECT first,last,preferences FROM main_table WHERE $user = $good_guy;

This statement has a potential vulnerability. However, the mere presence of variable input within the query does not make the statement vulnerable to SQL injection, as there might be no way for the user to influence the value of such a variable.

Admittedly, the example below is highly artificial, but it does drive the point home:

$user="anton"
$good_guy="anton"
SELECT first,last,preferences FROM main_table WHERE  $good_guy=$user;

The above statement is not vulnerable to SQL injection, no matter how poorly the rest of the application is coded. Now, consider the following example:

$good_guy="anton"
SELECT first,last,preferences FROM main_table WHERE $good_guy=$user;

where $user is passed from the web page input. Does it seem as safe as the previous one? No, nothing could be further from the truth. Imagine that the value of $user is set to “whatever OR 1=1”. Now, the statement becomes:

SELECT first,last,preferences FROM main_table WHERE $good_guy=whatever OR 1=1;

Suddenly, the WHERE clause matches every record in the database! The first condition (“anton=whatever”) is not fulfilled, but the second (“1=1”) is always true; thus, the SELECT statement runs across every username in the system, potentially revealing this information to the attacker.

We considered a simplistic case to show how SQL injection may be performed. The important thing to note is that the attack succeeded, since we were able to embed our own SQL code to pass to the database. The attack does not rely on any database vulnerabilities and will in fact succeed with just about every database, provided the access permissions allow the web user to see all the records in the table (which is likely, as it is required for the application to function). The application that allowed us to pass SQL in the variable is the one to blame, not the database.

It is true that application programmers are not prone to coding such elementary mistakes—at least, not anymore. Thus, applications will not likely allow simple attacks; rather, attackers will have to rely on inadvertent mistakes caused by design decisions made by the developers.

Let us consider some more complicated scenarios for SQL injection. These involve abusing various other queries and possibly getting more out of the database. For example, the above WHERE manipulation allowed us to access more data from the table used by the original query. What if we want to look at some other table? In this case, the UNION abuse technique comes to the rescue. As we mentioned above, UNION is used to merge the results of two separate queries and to show them together.

Let’s look back at the query from above:

SELECT first,last,preferences FROM main_table WHERE $good_guy=$user;

Suppose we want to look at another table, called “admin_users”. The following SQL statement will help:

SELECT first,last,preferences FROM main_table WHERE $good_guy=$user UNION ALL SELECT 
first,last,preferences FROM admin_users

Obviously, we should inject the following into $user:

$user="whatever UNION ALL SELECT first,last,preferences FROM admin_users"

“whatever” should not coincide with any real value in the database; otherwise, this entry will be removed from the results. Additionally, the columns in the above queries should be the same.

So far, we’ve omitted a couple of points on how to make these attacks a reality. Now, it is time to bring them into the discussion. One of these points is related to the use of quotes. In real life, the queries passed to the database have the following form:

SELECT first,last,preferences FROM main_table WHERE username = 'whatever'

or

SELECT first,last,preferences FROM main_table WHERE  'whatever' = 'compare_with'

The quotation marks are needed to tell the database application that a string is being passed. Thus, when we inject we have to take care of the quotes, which isn’t always easy.

Authentication bypass

We can look at the data in the database, which is already a considerable breach of security, but how else can we use our newfound powers? We can try to trick the application into authenticating us without having the proper credentials, such as a username and password. SQL injection again helps us. Here is a SQL query that verifies the login name and password.

SELECT login FROM admin_users WHERE login = $login_in AND password=$password_in

How is the above query used? The user submits a login name and password through the web application. This data is then placed into the variables $login_in and $passwdord_in by the web application. The above SELECT query is run with the provided parameters. If there is a row in the database with the same login name and password as provided by the user, the query returns them. The “admin_users” database is depicted in Table 16-4.

Table 16-4. Database table used for authentication

login

password

john

ubersecure

admin

imlametoo

anton

correcto

If such data is unavailable—say, due to an incorrect login, incorrect password, or both—nothing is returned. If the data is present, the application then makes a decision on whether to let the user in

Thus, the goal of our SQL injection attack is to make the query return something. We suspect that it is already obvious to the reader that “users” such as “OR 1=1” have a free ticket to use this application.

The following query:

SELECT login FROM admin_users WHERE login = $login_in AND password=$password_in OR 1=1

will always return some data, provided the table is populated.

Thus, by injecting data, we can trick the application into making an access control decision on our behalf.

Database modification

By now, it should be painfully obvious that SELECT statements may be manipulated by a malicious user. But can we do more, such as INSERT or DELETE data? Inserting data requires finding a part of the application where a legitimate INSERT is made. For example, the web site might provide free registration for all interested users. INSERTs may be manipulated in a similar fashion to SELECTs. For example, the following somewhat unwieldy query is used in PHP-Nuke to insert a new user entry:

INSERT INTO ".$user_prefix."_users (user_id, username, user_email, user_website, 
user_avatar, user_regdate, user_password, theme, commentmax, user_lang, user_
dateformat) VALUES (NULL,'$name','$email','$url','$user_avatar','$user_
regdate','$pwd','$Default_Theme','$commentlimit','english','D M d, Y g:i a')

Depending upon from where the data is coming (and some is bound to come from untrusted input), we might be able to INSERT something unauthorized.

Manipulating INSERTs is more complicated for the attacker, but it also provides advantages to the attacker. For example, if the application itself does not let you see the data, abusing SELECT is worthless. However, an attacker can tamper with the database for fun and profit (e.g., by adding an account to the system) without seeing any output (known as “blindfolded SQL injection”).

In some cases, the attacker might also get a “free ride” if the database allows her to pass several SQL statements in a single command. Thus, a relatively innocuous command such as:

$user='anton'
$pwd='correcto'

INSERT INTO users (username, password) VALUES ('anton','correcto'),

becomes an evil:

INSERT INTO users (username, password) VALUES ('anton','correcto'), INSERT INTO users 
(username, password, is_admin) VALUES ('evil','thouroughly','yes')

If an attacker can set the $pwd value to be as follows:

$pwd='correcto'; INSERT INTO users (username, password, is_admin) VALUES 
('evil','thouroughly','yes')'

Insertion may often be thwarted by proper database access controls and other factors, and overall it is considered to be less reliable than various SELECT abuses.

Escape from a database

Up to this point, most of our SQL injection activities centered on the database application itself. However, can we dream of breaking out of the confines of the database onto the underlying computing platform, be it Unix or Windows? In certain cases, this is indeed possible. However, most such techniques are fairly advanced and utilize weaknesses (or, at least, features) of specific database solutions.

Most of the documented “escape from the database” attacks center around Microsoft SQL server and its powerful stored procedures functionality. Such procedures allow attackers to execute commands on the machine itself, to connect to other servers, and even to scan ports using the built-in server tools.

For example, Microsoft SQL Server contains an extended stored procedure called “xp_cmdshell” that allows execution of arbitrary commands on the server. If an attacker manages to inject a call to this procedure (provided it is not removed or disabled), she can control the operating system and other applications. Thus, if you see a URL similar to the following[5] being accessed on your web application:

http://www.examples.com/ecom/bad.asp?';xp_cmdshell+'nmap+10.11.12.13'+;--

then trouble is near.

Looking for Errors

We have looked at some of the goals and possibilities of SQL injection. But how does we actually go and look for the errors that allow them in real-life web applications? There are two possible approaches. First, you can browse through the source code of the application to find potential instances where untrusted user input is passed to the database. This approach is only applicable to open source solutions. Looking for SELECTs, INSERTs, UPDATEs and other statements utilizing input from the web user, and then figuring out a way to influence such input, will go a long way toward finding more SQL injection vulnerabilities. We will illustrate some of these techniques in the later section on PHP-Nuke hacking.

The second (and by far most common) approach is “black-box” testing of the real deployed application. While full web penetration testing is beyond the scope of this book, we can identify some of the simple but effective steps one might try with a web application. The application is probed through a browser by modifying the access URLs, appending parameters to them, and so on. Such attacks can only succeed on a database-driven web site, and no amount of “index.html?whatever=SELECT” will get you the desired result.

The basic things to try on a new web application are shown in Table 16-5.

Table 16-5. Basic SQL “attack strings”

String

Expected result

'

Checking whether the application escapes quotes is the first step to learning its flaws and its vulnerability to the simplest of SQL injection attacks.

‘OR 1=1

This is a part of a common attack tactic (described above) where the WHERE clause is bypassed by being set to `true', thus increasing the amount of data extracted from a database.

‘OR 1=1’

Another version of the above.

;

Checking whether the application escapes the semicolon character helps to determine its vulnerability to multiple query attacks (described above for the INSERT case).

Keep in mind that in such tests using the URL, spaces and some other characters need to be escaped. For example, a space becomes a “%20” character, based on its ASCII code.

Looking for a flaw using black-box methods might take a long time, might not succeed anyway, and might be highly visible to the site owners. However, if preliminary tests (such as the quote test) show that the application is indeed coded incorrectly and contains flaws, exploitation is just be a matter of time.

SQL Injection Defenses

As a side note, the usual packet-filtering firewalls won’t protect you from SQL injection attacks. They simply lack the application intelligence to know what is going on beyond opening port 80 for web traffic. This is the case for many application-level attacks, such as SQL injection. Network intrusion detection will help, but it will not serve as magic “silver bullet” in this case. There are too many different forms and strings of such attacks to be encoded as an effective signature set. Additionally, if a target site is running SSL, you can evade the IDS by simply moving all the attack activities to TCP port 443 from port 80, which will likely hide all malfeasance.

We will categorize defenses into three main types, as described in Table 16-6.

Table 16-6. SQL injection defenses

Defensive approach

Description

Examples

Counterattacks

Obfuscation

Complicating the attacks by not providing the attacker with any feedback needed (or rather desired) for locating the SQL injection flaws

Generic error messages, limiting database output

“Blind” SQL injection[6]

Using stored procedures instead of dynamically built queries

Trying to avoid building queries from SQL commands and user input by replacing them with database stored procedures (conceptually similar to subroutines)

Use of sp_get_price( ) instead of “SELECT * from price”

Recent advanced SQL injection techniques can inject parameters into stored procedures

External filtering

Trying to only allow legitimate requests to the database (SQL shield) or the web application itself (web shield)

Web firewalls such as Kavado, Sanctum AppShield, etc.

Innovative injection types are not caught by the filter

Correcting the code flaws

Sanitizing the user input so that no SQL can be injected

Use of PHP routine is_numeric( ), aimed at checking the input

Not possible, provided the input is sanitized well

[6] A SQL injection type where the user receives no feedback from the application but still manages to accomplish the attack goal.

We will start by covering the relatively less effective defenses, which involve trying to sweep the problem under the carpet rather than solving it.

Obfuscation Defenses

Security by obscurity, or trying to make the controls opaque and hard to understand, is demonized by most security professionals. The important aspect to understand is that security by obscurity is not inherently evil; it is simply poor practice to make it the only defense against the adversary. It’s obviously a “good security practices” if the application does not provide unnecessary information to the attacker in addition to being coded correctly.

Unfortunately, skilled attackers have successfully penetrated obfuscation defenses against SQL injection. Such defenses will easily foil simple attacks, such as by adding an apostrophe to the web application URL. The probing methodology of such attacks relies on seeing a response from a web application or even, in some cases, directly from the database. The application might therefore be coded to always provide a generic error page or even to redirect the user back to the referring page. In this case, searching for holes and determining whether an attack succeeded becomes a nightmarish pursuit for the attacker. However nightmarish it is, though, it can be done. Attackers have developed sophisticated probing techniques (such as relying on timing information from a query or a command) to indirectly determine the response of the new injection strings.

Overall, the specific tips for thwarting obfuscation by “blindfolded SQL injection” lie outside of the scope of this book. Some excellent papers on the subject are listed in Section 16.5 at the end of this chapter.

External Defenses

The legend of a “magic firewall,” a box that just needs to be turned on to make you secure, continues to flourish. However, there are certain solutions that can protect you from poorly written database-driven applications that are vulnerable to SQL injection. Remember that the attacker interacts with a web application through a browser via a remote connection. Next, the application sends a request for data to the database.

You can try to block the attacks between the attacker and the web application, between the application and the database, or even on the database itself. The conspicuously missing defense—fixing the application—is covered in the next section. Possible defense methods are provided in Table 16-7.

Table 16-7. Application blocking

External defenses

Position

Description

Counterattacks

Web shields

Between the client and the web application

Try to filter out the suspicious URL requests to the web application in order to block the attack before it reaches the application.

As with all signature-based technology, one can try to sneak through by crafting yet another URL after a thousand failed attempts; it just might work.

Web scanners

Between the client and the web application

Run the attacks against the application, check their status, and reconfigure the web shield to block them more effectively.

Same as above.

SQL shields

Between the application and the database

Similar to web shields, this defense looks at all the SQL traffic and analyzes it using signature- and anomaly-based techniques.

As with web shields, such a filter may probably be bypassed by patiently trying various attack strings.

Database access controls

On the database

Only allow the minimum needed privileges to the web applications so that no extraneous tables and other structures can be accessed.

Usually, the database access controls cannot be granular enough to block all attacks.

Overall, trying to fix the application problem by dancing around the issue with various tools works to a certain extent. Filters, scanners, and stringent access controls do make the web application harder to hit by SQL injection. These solutions are cost-effective (and may be the only available option) if there is no way to modify the application. Additionally, they provide the needed in-depth defense for database-driven applications. After all, bugs happen, and even the best applications are known to contain errors.

Coding Defenses

The only true defense against SQL injection is “doing things right.” As we mentioned in the very beginning of this chapter, SQL injection attacks are successful when the user input is allowed to unduly influence the SQL query, such as by adding parameters or even entire queries to the command. Thus, the user input need to be cleaned. But what are the available options?

First, if the type of user input is well known, the application should only allow that sort of data in the input. For example, if a required field is numeric, the application should not allow anything but a number. The options include rejecting anything else or trying to convert the input to the appropriate format. This is the “default deny” policy, which is always a good security decision.

Second, if the user-input type is not well known, at least what should definitely not be there might be known. In this case, you will have to resort to the “default allow” policy by filtering quotes, commands, or other metacharacters.[7] Some of the filtering decisions can be made for the entire application (never pass quotes to the database) and some depend upon the input type (no commas in the email address).

While writing an in-house, database-driven application, or when deploying an open source application, it makes sense to pay attention to such issues and to design the proper input verification. This measure alone will help protect you from SQL injection attacks so that you won’t end up as an example in some security book, like PHP-Nuke did (see below).

In order to make life simpler, small snippets of code exist for many of the web application languages. Here is a blurb of PHP code, reported on the mailing list (http://www.securityfocus.com/archive/107/335092/2003-08-24/2003-08-30/0), which can check whether a variable is a number. The code rejects all non-numeric input.

function sane_integer($val, $min, $max) 
{ 
   if (!is_numeric($val)) 
     return false; 
   if (($val < $min) or ($val > $max)) 
     return false; 
   return true; 
}

Being aware of coding defenses is important even if you are deploying a commercial application. Just keep in mind that the developers likely made errors and that you will have to take steps to compensate. Such a practice is prudent even if there are no publicly reported vulnerabilities in the application.

Conclusion

Overall, it makes sense to combine several of the above techniques. For example, a well-designed and properly deployed application will do the following:

  • Not return any informative error pages; a redirect or a generic page is sufficient

  • Sanitize input as much as possible, preferably not allowing any input directly in queries, even if sanitized

  • Have a database configured based on a least-privilege principle, with no extraneous access

  • Be penetration tested and scanned by a web application scanner on a regular basis

  • Be protected by a web shield for layered security

The above might sound like overkill, and we admit that it probably is overkill for a personal site. However, if your business depends solely on a web site, then those excessive measures and the extra expense suddenly start to sound more reasonable.

PHP-Nuke Examples

This section covers some of the example attacks against PHP-Nuke, a free, open source web site framework written in PHP. The application runs on many platforms (Windows, Linux, Unix) and can interface with multiple databases (MySQL, MS SQL, Oracle, etc). It can be downloaded from http://www.phpnuke.org.

In order to follow along, please install the application on your system; Linux installation directions are provided for convenience. Keep in mind that it should not be used for any production purposes.

Installing PHP-Nuke

We assume that you have a modern Linux system. PHP-Nuke requires that MySQL, PHP, and Apache are installed. You might also need to install the following RPM packages, if you are using Red Hat Linux (all of these are included in the distribution; some other prerequisites might need to be satisfied):

  • mysql

  • httpd

  • php

  • php-mysql

The application is surprisingly easy to install and configure and will produce a flexible database-driven web site, complete with all the latest SQL injection vulnerabilities, in minutes.

Follow these steps to get the application up and running:

  1. Download the application:

    $ wget http://umn.dl.sourceforge.net/sourceforge/phpnuke/PHP-Nuke-6.5.tar.gz
  2. Unpack the resulting archive:

    $ tar zxf PHP-Nuke-6.5.tar.gz
  3. Start the database server:

    # /etc/init.d/mysql start
  4. Create the database using the MySQL administrator tool:

    # mysqladmin create nuke
  5. Create all the required database structures using the included “nuke.sql” tool:

    # cd sql ; mysql nuke < nuke.sql
  6. Copy the unpacked files to a location “visible” to the web server (such as /var/www/html/nuke).

  7. Start the Apache web server:

    # /etc/init.d/httpd start
  8. Browse http://127.0.0.1/nuke/html/. This should show the site up and running.

  9. Go to http://127.0.0.1/nuke/html/admin.php. Now, create an administrator password to configure the application.

Attacks

We are ready to hit PHP-Nuke with everything we have. If you search Google for “PHP-Nuke SQL hack” you will find dozens of different holes and attack URLs. Here we will demonstrate an attack that saves confidential data into a file.

Launch a browser and access the following URL:[8]

http://127.0.0.1/nuke/html/banners.php?op=Change&cid=`%20OR%201=1%20INTO%20OUTFILE%20'/tmp/secret.txt

Now, check the system where PHP-Nuke is running. In the /tmp directory, a file is created which contains the passwords needed to update the banners on the site. Note that those are not the default passwords for site access but rather are the banner passwords, which might not exist by default. In this case, the file will end up empty. The file will be owned by the user “mysql”.

Let’s look at the above attack URL in more detail. We will split it into parts and explain each of them, as in Table 16-8.

Table 16-8. The attack URL

Part of the attack URL

Explanation

http://127.0.0.1/

The site IP address.

/nuke/html/banners.php

A PHP script that is being executed.

?

Separator between the script and the parameters.

op=Change&cid=

Part of the legitimate request including the invoked command to the script (change banner URL).

`%20OR%201=1%20INTO%20OUTFILE%20’

The actual attack SQL. This actually means: ' OR 1=1 INTO OUTFILE ', since %20 characters are translated into spaces.

/tmp/secret.txt

Filename to hold the data.

This URL contains some of the attack elements we have studied. There is an evil quote character, an “OR 1=1” blast, and a SQL command. Note that we do not use any UNIONs or SELECTs but instead go for the less common INTO OUTFILE.

So we could see what we’ve accomplished, we started the “mysql” database in logging mode (using the “—log” flag), which logs all the executed SQL queries in a file (usually /var/lib/mysql/query.log). In the case of this attack, we find the following statement in the log:

SELECT passwd FROM nuke_bannerclient WHERE cid='' OR 1=1 INTO OUTFILE '/tmp/secret.txt'

This command runs on the “mysql” server and dumps the output into a file, just as desired by the attacker. It can be loosely divided into the legitimate part (“SELECT passwd FROM nuke_bannerclient WHERE cid='’”) and the injected part (“OR 1=1 INTO OUTFILE `/tmp/secret.txt'’”).

There are dozens of other possible attacks against this application; look for them and try them on your system (for educational purposed only, of course). Run SQL in debug mode to observe the malicious queries.

Defenses

The code was fixed to patch some of the vulnerabilities used above after they were disclosed. Let’s look at some applied fixes.

The above exploit was caused by the following PHP code within the “banners.php” module, in the change_banner_url_by_client( ) function:

$sql = "SELECT passwd FROM ".$prefix."_bannerclient WHERE cid='$cid'";

The function is called from another location within the same script:

case "Change":
change_banner_url_by_client($login, $pass, $cid, $bid, $url, $alttext);
break;

The unfortunate variable $cid is populated by the client’s request, which leads to the SQL injection.

This bug can be easily fixed by making sure that $cid contains only numbers (as it should). The PHP function is_numeric( ) can be used to accomplish this. Another fix, suggested by the original researcher of this bug, is also valid. It uses the PHP command $cid=addslashes($cid) to escape any special characters and thus neutralize attacks. It was such an easy thing to fix, but sadly was slow to be done. At least three subsequent versions of PHP-Nuke came out with the same vulnerability.

References



[1] “Database-driven” is used to specify an application linked to a backend database for data storage, authentication, and other purposes.

[2] According to Sun, “JDBC technology is an API that lets you access virtually any tabular data source from the Java programming language. It provides cross-DBMS connectivity to a wide range of SQL databases” (http://java.sun.com/products/jdbc/).

[3] ODBC (Open DataBase Connectivity) is Microsoft API that allows abstraction of a program from a database.

[4] $password (or anything else with a $ sign) indicates a variable used within the PHP script. Those familiar with Perl will recognize the similarity. While we are not talking specifically about PHP or Perl here, we will use a convention of $variable indicating a value changed within the application and passed to the database.

[5] Here, for illustrative purposes, we disregarded the fact that some characters, such as the apostrophe, might need to be escaped in the URL string.

[7] Metacharacter is a common term for a nonalpahnumeric symbol: i.e., `, #, $, /, etc.

[8] This attack was first publicized by Frogman in this post: http://archives.neohapsis.com/archives/vulnwatch/2003-q1/0146.html.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset