SQL Injection
SQL Injection
1 Overview
SQL injection is a code injection technique that exploits the vulnerabilities in the interface between web
applications and database servers. The vulnerability is present when user’s inputs are not correctly checked
within the web applications before being sent to the back-end database servers.
Many web applications take inputs from users, and then use these inputs to construct SQL queries, so
the web applications can get information from the database. Web applications also use SQL queries to store
information in the database. These are common practices in the development of web applications. When
SQL queries are not carefully constructed, SQL injection vulnerabilities can occur. The SQL injection attack
is one of the most common attacks on web applications.
In this lab, we have created a web application that is vulnerable to the SQL injection attack. Our web
application includes the common mistakes made by many web developers. Students’ goal is to find ways to
exploit the SQL injection vulnerabilities, demonstrate the damage that can be achieved by the attack, and
master the techniques that can help defend against such type of attacks.
2 Lab Environment
You need to use our provided virtual machine image for this lab. The name of the VM image that supports
this lab is SEEDUbuntu12.04.zip. If you happen to have an older version of our pre-built VM image,
you need to download the most recent version, as the older version does not support this lab. Go to our
SEED web page (http://www.cis.syr.edu/˜wedu/seed/) to get the SEEDUbuntu VM image.
Starting the Apache Server. The Apache web server is also included in the pre-built Ubuntu image and
is started by default. The following command is used to start the web server manually.
Configuring DNS. We have configured the following URL needed for this lab. To access the URL, the
Apache server needs to be started first:
URL: http://www.SEEDLabSQLInjection.com
Folder: /var/www/SQLInjection/
The above URL is only accessible from inside of the virtual machine, because we have modified
the /etc/hosts file to map the domain name of each URL to the virtual machine’s local IP address
(127.0.0.1). You may map any domain name to a particular IP address using /etc/hosts. For exam-
ple, you can map http://www.example.com to the local IP address by appending the following entry
to /etc/hosts:
127.0.0.1 www.example.com
If your web server and browser are running on two different machines, you need to modify /etc/hosts
on the browser’s machine accordingly to map these domain names to the web server’s IP address, not to
127.0.0.1.
Configuring Apache Server. In our pre-built VM image, we have used Apache server to host all the web
sites used in the lab. The name-based virtual hosting feature in Apache could be used to host several web
sites (or URLs) on the same machine. A configuration file named default in the directory "/etc/
apache2/sites-available" contains the necessary directives for the configuration:
1. The directive "NameVirtualHost *" instructs the web server to use all IP addresses in the ma-
chine (some machines may have multiple IP addresses).
2. Each web site has a VirtualHost block that specifies the URL for the web site and directory
in the file system that contains the sources for the web site. For example, to configure a web site
with URL http://www.example1.com with sources in directory /var/www/Example_1/,
and to configure a web site with URL http://www.example2.com with sources in directory
/var/www/Example_2/, we can use the following blocks:
<VirtualHost *>
ServerName http://www.example1.com
DocumentRoot /var/www/Example_1/
</VirtualHost>
<VirtualHost *>
ServerName http://www.example2.com
DocumentRoot /var/www/Example_2/
</VirtualHost>
You may modify the web application by accessing the source in the mentioned directories. For example,
with the above configuration, the web application http://www.example1.com can be changed by
modifying the sources in the directory /var/www/Example_1/.
1. Go to /etc/php5/apache2/php.ini.
The bootstrap.sh script creates a new database named Users in our existing SEEDUbuntu VM,
loads data into the database, sets up the virtual host URL, and finally modifies the local DNS configuration.
If you are interested in doing the setup manually, please refer to the Appendix section for details.
1. How to use the virtual machine, Firefox web browser, and the LiveHTTPHeaders extension.
2. Brief introduction of SQL. Only need to cover the basic structure of the SELECT, UPDATE, and
INSERT statements. A useful online SQL tutorial can be found at http://www.w3schools.
com/sql/.
3. How to operate the MySQL database (only the basics). The account information about the MySQL
database can be found in the user manual of the VM, which can be downloaded from our SEED web
page.
4. Brief introduction of PHP. Only need to cover the very basics. Students with a background in C/C++,
Java, or other language should be able to learn this script language quite quickly.
3 Lab Tasks
We have created a web application, and host it at www.SEEDLabSQLInjection.com. This web ap-
plication is a simple employee management application. Employees can view and update their personal
SEED Labs 4
information in the database through this web application. There are mainly two roles in this web applica-
tion: Administrator is a privilege role and can manage each individual employees’ profile information;
Employee is a normal role and can view or update his/her own profile information. All employee infor-
mation is described in the following table.
User Employee ID Password Salary Birthday SSN Nickname Email Address Phone#
Admin 99999 seedadmin 400000 3/5 43254314
Alice 10000 seedalice 20000 9/20 10211002
Boby 20000 seedboby 50000 4/20 10213352
Ryan 30000 seedryan 90000 4/10 32193525
Samy 40000 seedsamy 40000 1/11 32111111
Ted 50000 seedted 110000 11/3 24343244
After login, you can create new database or load an existing one. As we have already created the Users
database for you, you just need to load this existing database using the following command:
mysql> use Users;
To show what tables are there in the Users database, you can use the following command to print out
all the tables of the selected database.
mysql> show tables;
After running the commands above, you need to use a SQL command to print all the profile information
of the employee Alice. Please provide the screenshot of your results.
Figure 1. The authentication is based on Employee ID and Password, so only employees who know their
IDs and passwords are allowed to view/update their profile information. Your job, as an attacker, is to log
into the application without knowing any employee’s credential.
To help you started with this task, we explain how authentication is implemented in our web application.
The PHP code unsafe credential.php, located in the /var/www/SQLInjection directory, is
used to conduct user authentication. The following code snippet show how users are authenticated.
$conn = getDB();
$sql = "SELECT id, name, eid, salary, birth, ssn,
phonenumber, address, email, nickname, Password
FROM credential
WHERE eid= ’$input_eid’ and password=’$input_pwd’";
$result = $conn->query($sql))
The above SQL statement selects personal employee information such as id, name, salary, ssn etc from
the credential table. The variables input eid and input pwd hold the strings typed by users in
the login page. Basically, the program checks whether any record matches with the employee ID and
SEED Labs 6
password; if there is a match, the user is successfully authenticated, and is given the corresponding employee
information. If there is no match, the authentication fails.
• Task 2.1: SQL Injection Attack from webpage. Your task is to log into the web application as the
administrator from the login page, so you can see the information of all the employees. We assume
that you do know the administrator’s account name which is admin, but you do not know the ID
or the password. You need to decide what to type in the Employee ID and Password fields to
succeed in the attack.
• Task 2.2: SQL Injection Attack from command line. Your task is to repeat Task 2.1, but you need
to do it without using the webpage. You can use command line tools, such as curl, which can send
HTTP requests. One thing that is worth mentioning is that if you want to include multiple parameters
in HTTP requests, you need to put the URL and the parameters between a pair of single quotes;
otherwise, the special characters used to separate parameters (such as &) will be interpreted by the
shell program, changing the meaning of the command. The following example shows how to send an
HTTP GET request to our web application, with two parameters (SUID and Password) attached:
curl ’www.SeedLabSQLInjection.com/index.php?SUID=10000&Password=111’
If you need to include special characters in the SUID and Password fields, you need to encode them
properly, or they can change the meaning of your requests. If you want to include single quote in those
fields, you should use %27 instead; if you want to include white space, you should use %20. In this
task, you do need to handle HTTP encoding while sending requests using curl.
• Task 2.3: Append a new SQL statement. In the above two attacks, we can only steal information
from the database; it will be better if we can modify the database using the same vulnerability in the
login page. An idea is to use the SQL injection attack to turn one SQL statement into two, with the
second one being the update or delete statement. In SQL, semicolon (;) is used to separate two SQL
statements. Please describe how you can use the login page to get the server run two SQL statements.
Try the attack to delete a record from the database, and describe your observation.
$conn = getDB();
$sql = "UPDATE credential SET nickname=’$nickname’,
email=’$email’,
address=’$address’,
phonenumber=’$phonenumber’,
Password=’$pwd’
WHERE id= ’$input_id’ ";
$conn->query($sql))
SEED Labs 7
• Task 3.1: SQL Injection Attack on UPDATE Statement — modify salary. As shown in the Edit
Profile page, employees can only update their nicknames, emails, addresses, phone numbers, and
passwords; they are not authorized to change their salaries. Only administrator is allowed to make
changes to salaries. If you are a malicious employee (say Alice), your goal in this task is to increase
your own salary via this Edit Profile page. We assume that you do know that salaries are stored in a
column called salary.
• Task 3.2: SQL Injection Attack on UPDATE Statement — modify other people’ password. Us-
ing the same vulnerability in the above UPDATE statement, malicious employees can also change
other people’s data. The goal for this task is to modify another employee’s password, and then demon-
strate that you can successfully log into the victim’s account using the new password. The assumption
here is that you already know the name of the employee (e.g. Ryan) on whom you want to attack.
One thing worth mentioning here is that the database stores the hash value of passwords instead of the
plaintext password string. You can again look at the unsafe edit.php code to see how password
is being stored. It uses SHA1 hash function to generate the hash value of password.
To make sure your injection string does not contain any syntax error, you can test your injection string
on MySQL console before launching the real attack on our web application.
Execution
Compilation Phase
Execution Phase
Query Optimization In this state, the SQL statement is
Phase pre‐compiled into binary. Only
placeholders for data are included in
the prepared statement, not the
Cache actual data. Data will be binded to
this statement later as pure data (so
no more compilation will be
conducted).
developers. To solve this problem, it is important to ensure that the view of the boundaries are consistent in
the server-side code and in the database. The most secure way is to use prepared statement.
To understand how prepared statement prevents SQL injection, we need to understand what happens
when SQL server receives a query. The high-level workflow of how queries are executed is shown in
Figure 3. In the compilation step, queries first go through the parsing and normalization phase, where a query
is checked against the syntax and semantics. The next phase is the compilation phase where keywords (e.g.
SELECT, FROM, UPDATE, etc.) are converted into a format understandable to machines. Basically, in this
phase, query is interpreted. In the query optimization phase, the number of different plans are considered to
execute the query, out of which the best optimized plan is chosen. The chosen plan is store in the cache, so
whenever the next query comes in, it will be checked against the content in the cache; if it’s already present
in the cache, the parsing, compilation and query optimization phases will be skipped. The compiled query
is then passed to the execution phase where it is actually executed.
Prepared statement comes into the picture after the compilation but before the execution step. A pre-
pared statement will go through the compilation step, and be turned into a pre-compiled query with empty
placeholders for data. To run this pre-compiled query, data need to be provided, but these data will not go
through the compilation step; instead, they are plugged directly into the pre-compiled query, and are sent
to the execution engine. Therefore, even if there is SQL code inside the data, without going through the
compilation step, the code will be simply treated as part of data, without any special meaning. This is how
prepared statement prevents SQL injection attacks.
Here is an example of how to write a prepared statement in PHP. We use a SELECT statment in the
following example. We show how to use prepared statement to rewrite the code that is vulnerable to SQL
injection attacks.
$conn = getDB();
$sql = "SELECT name, local, gender
FROM USER_TABLE
WHERE id = $id AND password =’$pwd’ ";
$result = $conn->query($sql))
SEED Labs 9
The above code is vulnerable to SQL injection attacks. It can be rewritten to the following
$conn = getDB();
$stmt = $conn->prepare("SELECT name, local, gender
FROM USER_TABLE
WHERE id = ? and password = ? ");
// Bind parameters to the query
$stmt->bind_param("is", $id, $pwd);
$stmt->execute();
$stmt->bind_result($bind_name, $bind_local, $bind_gender);
$stmt->fetch();
Using the prepared statement mechanism, we divide the process of sending a SQL statement to the
database into two steps. The first step is to only send the code part, i.e., a SQL statement without the actual
the data. This is the prepare step. As we can see from the above code snippet, the actual data are replaced
by question marks (?). After this step, we then send the data to the database using bind param(). The
database will treat everything sent in this step only as data, not as code anymore. It binds the data to the
corresponding question marks of the prepared statement. In the bind param() method, the first argument
"is" indicates the types of the parameters: "i" means that the data in $id has the integer type, and "s"
means that the data in $pwd has the string type.
For this task, please use the prepared statement mechanism to fix the SQL injection vulnerabilities
exploited by you in the previous tasks. Then, check whether you can still exploit the vulnerability or not.
4 Guidelines
Test SQL Injection String. In real-world applications, it may be hard to check whether your SQL injec-
tion attack contains any syntax error, because usually servers do not return this kind of error messages. To
conduct your investigation, you can copy the SQL statement from php source code to the MySQL console.
Assume you have the following SQL statement, and the injection string is ’ or 1=1;#.
You can replace the value of $name with the injection string and test it using the MySQL console. This
approach can help you to construct a syntax-error free injection string before launching the real injection
attack.
5 Submission
You need to submit a detailed lab report to describe what you have done and what you have observed.
Please provide details using screen shots and code snippets. You also need to provide explanation to the
observations that are interesting or surprising.
Step 2: In the SEEDUbuntu VM, we use Apache to host all the web sites used in the lab. The name-based
virtual hosting feature in Apache can be used to host several web sites (or URLs) on the same machine. A
configuration file /etc/apache2/sites-available/default contains the neccessary directives
for the configuration. We can add a new url to /etc/apache2/sites-available/default file as
follows:
<VirtualHost *>
ServerName http://www.SeedLabSQLInjection.com
DocumentRoot /var/www/SQLInjection/
</VirtualHost>
Step 3: We need to modify the local DNS file /etc/hosts to provide an IP address (127.0.0.1) for the
host name www.SeedLabSQLInjection.com.
127.0.0.1 www.SeedLabSQLInjection.com