This PHP code performs a simple login procedure by ...

44
1

Transcript of This PHP code performs a simple login procedure by ...

Page 1: This PHP code performs a simple login procedure by ...

1

Page 2: This PHP code performs a simple login procedure by ...

65

Page 3: This PHP code performs a simple login procedure by ...

This PHP code performs a simple login procedure by matching a user identifier and a (hashed) password provided by the client as HTTP POST parameters on a database of users. If the user-provided identifier $name and the hashed password $pwdHash do not match any tuple in the ‘users’ table, then an authentication error will be raised. Otherwise, a personalized welcome message will be printed and a new active session will be registered. The query is built by inserting the values of $name and $pwdHash in a skeleton query string.

66

Page 4: This PHP code performs a simple login procedure by ...

The code works normally if the inputs are those expected, but the behavior is unexpected if the input contains SQL symbols. Consider an attacker that sends the above malicious user ID, which contains SQL symbols that are interpreted as code by the victim system. The “’” character closes the string literal in the query string, and the “-- “ (with the trailing space) symbol makes the SQL interpreter ignore the successive query, thus bypassing the password check. The attacker gains access to the system with the privileges of the user “admin”. This is an example of SQL injection attack. From now on, the red dot-underlined text will represent the injected part of the query.

67

Page 5: This PHP code performs a simple login procedure by ...

Despite its simplicity, this is one of the most common and devastating attacks of the web according to OWASP. Bypassing authentication is not the only possible impact of a SQL injection. Other effects include escalating privileges, stealing data, adding or modifying data, partially or totally deleting a database.

68

Page 6: This PHP code performs a simple login procedure by ...

The aforementioned problem is not specific of SQL, but of all the interpretedlanguages, for example LDAP, XPath, etc. Such languages are very prevalent in web applications, especially for interfacing back-end components like databases. In a typicalweb application, user-supplied data is received, manipulated, and then acted on possibly by means of some interpreter. In this case, the interpreter will processinstructions of the web programmer mixed to user-supplied data. If this mix betweeninstructions and tainted data is not done properly, an attacker can send crafted input that breaks out of the data context, usually by injecting some syntax that has a meaning in the interpreted language. As a result, part of the attacker’s input isinterpreted as code (code injection) and executed as legitimate code written by the programmer.

69

Page 7: This PHP code performs a simple login procedure by ...

Note that different SQL servers (MySQL, PostsgreSQL, MS SQL Server, etc.) use differentdialects of the SQL language. The SQL injection techniques described here all refer to MySQL dialect. However, all these techniques can be translated to other dialects in more or less complex ways.

70

Page 8: This PHP code performs a simple login procedure by ...

With the piggybacked query technique, an attacker injects another arbitrary query afterthe legitimate query. With piggybacked queries, it is possible to modify or add data, for example change the administrator password or add a new adversary-controlledadministrator user. It is also possible to delete partially or totally a database, thuscausing a denial of service and a loss of valuable information.

71

Page 9: This PHP code performs a simple login procedure by ...

Query piggybacking is the simplest and most poweful attack method, nevertheless it israrely used in practice. This is because the attack is possible only if the victim website performs vulnerable multi-queries on the SQL database, or if the SQL database isconfigured to accept multi-queries.

72

Page 10: This PHP code performs a simple login procedure by ...

The tautology technique consists in injecting a condition which always evaluates to true(e.g., «1=1» or simply «true» in MySQL) in a WHERE clause in order to bypass itsomehow. Imagine that the WHERE condition of the previous example had the password and the username checks appearing in a different order, like shown in the above slide. In this case, the simple commenting technique cannot be applied. However, the attacker can bypass authentication anyway with the tautology technique, by injecting the following input:$name = admin' OR 'a'='aSince the WHERE clause is always true, then the query will return all the tuples of the ‘users’ table. Thus the attacker can bypass the authentication. Note that here we didnot use a trailing comment symbol (--) but a more «elegant» quote balancingtechnique, which consists in injecting an even number of quotation marks in such a way all string literals are «closed» in the resulting query, thus avoiding syntax errors. The final effect is the same as using the comment symbol, but quote balancing works evenin the case the comment symbol is sanitized by the application.The clause commenting and the tautology techniques can also be used to steal data. For example, a webpage that displays some information of the current user can be forced to display information of all the users by making the WHERE clause evaluatealways to true.

73

Page 11: This PHP code performs a simple login procedure by ...

The most commonly used verb in SQL is SELECT, because it is used to return information, perform a search, or check user-supplied credentials during login. However, SQL injection vulnerabilities can be present in any verb. For example, the INSERT verb creates a new tuple in a table. It is used to create a new user, place a new shipping order, or append a new record in a log. For example, a self-registration functionality could use the following SQL statement: INSERT INTO users (username, pwd, privilege) VALUES ('$input1', '$input2', 1)where privilege is 1 for common users and 0 for administrators. If $input1 is injectable,an attacker could submit the following input: $input1=mrloucipher', '...', 0) --where '…' contains the hash of the attacker’s password.The UPDATE verb modifies one or more tuples in a table. It is used to update user profiles, change passwords, or change items in an order or shopping basket. For example, a password change functionality could use the following SQL statement: UPDATE users SET pwd = '$input1' WHERE user = '$input2' AND pwd = '$input3'where the second clause of the WHERE is to check the knowledge of the old password. If $input2 is injectable, an attacker could submit the following input: $input2=admin' --which skips the old-password check.

74

Page 12: This PHP code performs a simple login procedure by ...

Sometimes, the query is designed to return at most one row (single-row query). In these cases, if the attacker injects SQL code in such a way that the resulting queryreturns multiple tuples, either the application returns an error page or the returnedpage is computed basing only on the first row only. To avoid returning multiple rows, the attacker can inject a LIMIT clause (not present in MS SQL Server). For example, in case of the following query:SELECT * FROM users WHERE name = '$name'the attacker can inject in such a way to get:SELECT * FROM users WHERE name = 'foo' OR 1=1 LIMIT 1 -- 'in order to exfiltrate the information about the first user of the table users. If we wantto exfiltrate the information about all users, we have to repeat the attack several timesusing the LIMIT sintax with two arguments. The first argument specifies the (zero-based) offset of the first row to return, while the second argument specifies the number of rows to return. For example:SELECT * FROM users WHERE name = 'foo' OR 1=1 LIMIT 0,1 -- 'SELECT * FROM users WHERE name = 'foo' OR 1=1 LIMIT 1,1 -- 'SELECT * FROM users WHERE name = 'foo' OR 1=1 LIMIT 2,1 -- 'and so on.

75

Page 13: This PHP code performs a simple login procedure by ...

This PHP code displays the name and other info of all the employees working in a city specified by an HTTP POST parameter. Assume that the ‘employees’ table contains no sensitive information, and that the attacker wants to steal data from a different table, namely ‘creditcards’.

76

Page 14: This PHP code performs a simple login procedure by ...

By leveraging the UNION operator, an attacker can deceive the system into returningdata from a table different from the one specified by the SELECT statement. The attacker injects a UNION operand followed by another query. The UNION operandmerges the tuples resulting from the first and the second query. In the example code, all the tuples of the sensitive table ‘creditcards’ are returned to the attacker. Note that the final «-- » symbol is necessary to comment away the final«'» symbol, which would otherwise cause the query to fail due to syntax error.

77

Page 15: This PHP code performs a simple login procedure by ...

In order for the attacker to inject a UNION operator without errors, the two operands must have the same number of columns and with the same or compatible type. To discover the number and type of the columns of the injectable query, the attacker can employ the NULL literal constant, which is convertible to all the other types. In the previous example, the adversary can iteratively inject:$city=Pisa' UNION SELECT NULL --$city=Pisa' UNION SELECT NULL, NULL --$city=Pisa' UNION SELECT NULL, NULL, NULL --and so on, until the application returns a “normal” message, indicating that no errorshave occurred. The number of injected NULLs will be the number of columns of the injectable query. Note that the NULL values may be not viewable from the browser, since they could be rendered as empty strings on screen. In this case, an inspection of the HTML code could be necessary.

78

Page 16: This PHP code performs a simple login procedure by ...

Then, the adversary has to discover the type of such columns. Actually, it is sufficient to discover a column of string type by means of which the attacker can steal any other type of data. To do this, assuming that the injectable query has three columns, the attacker can inject:$city=Pisa' UNION SELECT 'a', NULL, NULL --$city=Pisa' UNION SELECT NULL, 'a', NULL --$city=Pisa' UNION SELECT NULL, NULL, 'a' --and note which input returns a “normal” message. The columns injected with ‘a’ will be of string type.

79

Page 17: This PHP code performs a simple login procedure by ...

Finally, the attacker has to know the name of the table and of the table’s columns to steal. To do this, the attacker can use the UNION operator to steal the database metadata from the predefined table ‘information_schema.columns’. For example, assuming that the first two columns of the injectable query are strings, the attacker can inject:$city=Pisa’ UNION SELECT table_name, column_name, NULL FROM information_schema.columns --

80

Page 18: This PHP code performs a simple login procedure by ...

In case the query to inject is single-row, the attacker has to remove from the result allthe rows of the original table. The simplest way to do that is by injecting a value that isnot contained in the original table. For example, in the query:SELECT * FROM employees WHERE name = '$name'the attacker can inject a non-existent name followed by the UNION operator:SELECT * FROM employees WHERE name = 'foo' UNION SELECT * FROM creditcardsLIMIT 0,1 --'Another way to do that is to inject a contradiction, that is a condition which alwaysevaluates to false (e.g., «0=1» or simply «false» in MySQL) in the WHERE clause. For example:SELECT * FROM employees WHERE name = 'Pisa' AND 1=0 UNION SELECT * FROM creditcards LIMIT 0,1 --'

81

Page 19: This PHP code performs a simple login procedure by ...

Let us suppose that the application does not return any query result in the page, but itreturns possible query evaluation errors. Error-based SQL injection is a tecnique by which an attacker can exfiltrate data through the database server’s error messages. The trick is to produce a SQL query which is syntactically correct, but it produces a runtimeerror once evaluated. The runtime error must be provoked by some string, whichcontains the data to exfiltrate and whose value is returned back by the server inside the error message.

82

Page 20: This PHP code performs a simple login procedure by ...

A common technique to perform error-based SQLI in MySQL databases is including the data to exfiltrate into a syntactically wrong XPath expression, and then let the functionupdatexml() evaluate it. The function updatexml() takes three arguments: an XMLTyperepresenting an XML document, a string representing the XPath expression whichidentifies the XML element to update, and a value which the element must be updatedto.In order to produce a syntactically wrong XPath expression, the attacker can prefix the data to exfiltrate with some invalid character, for example the tilde (‘~’), whose ASCII code is 0x7e.

83

Page 21: This PHP code performs a simple login procedure by ...

The following is an example of error-based SQLI using updatexml().$query = "SELECT * FROM employees WHERE city = '$city'";The attacker can inject: $city = "Pisa' OR updatexml(null,concat(0x7e, database()),null) -- ";Then the application will return an error like:Error while executing the SQL query. <!-- XPATH syntax error:'~MyCompanyScheme' -->From which the attacker learns that the current scheme is “MyCompanyScheme”. It is also possible to steal multiple strings at a time from other tables by using nested queries and the GROUP_CONCAT() aggregate function, which concatenates field values separating them by commas:$city = "Pisa' OR updatexml(NULL,concat(0x7e, (SELECT GROUP_CONCAT(password) FROM users)),NULL) -- ";The application will return an error like:Error while executing the SQL query. <!-- XPATH syntax error:'~pa55w0rd,pass1234' -->

84

Page 22: This PHP code performs a simple login procedure by ...

It may be that the error message truncates the XPath that caused the error. In this case it is useful to steal data piece by piece, by using the substring() function:$city = "Pisa' OR updatexml(NULL,concat(0x7e, (SELECT substring(GROUP_CONCAT(password),1,20) FROM users)),NULL) -- ";$city = "Pisa' OR updatexml(NULL,concat(0x7e, (SELECT substring(GROUP_CONCAT(password),21,20) FROM users)),NULL) -- ";And so on.

85

Page 23: This PHP code performs a simple login procedure by ...

Sometimes the application does not return the results of the query nor the errors generated by the database. In these cases, the attacker could extract data indirectly, by inferring it from the application’s behavior or by using side channels. These techniques are collectively called blind SQL injection. An example of blind SQL injection is boolean-based SQL injection, which works by injecting a query that triggers some detectable behavior if and only if the information that the attacker wants to steal satisfies a particular condition. For example, let us suppose a vulnerable login functionality which uses the following query:SELECT * FROM users WHERE username= '$input1' AND pwd='$input2'Suppose that for the attacker is not enough to login as administrator, but she also wants the administrator’s password, which is stored in the clear in the database (without any hash algorithm). Note that there is no way of stealing data with the UNION query method because the query results are not returned by the application.

86

Page 24: This PHP code performs a simple login procedure by ...

An attacker can submit the following crafted input:$input1=admin' AND BINARY SUBSTRING(pwd,1,1) = 'a' --In this way, the attacker can learn whether the first letter of the administrator’s password is ‘a’ by simply checking whether the login succeeded or not. If the login succeeds, then the first letter is ‘a’, otherwise the first letter is not ‘a’. By submitting a large number of such inputs, the attacker can cycle through all the possible values of the first letter, and then through all the letters, eventually discovering the complete password. Note the “BINARY” keyword that makes the following string comparison (“=“) case-sensitive. Without the “BINARY” keyword, SQL performs case-insensitive string comaprisons by default.

87

Page 25: This PHP code performs a simple login procedure by ...

This method is general and works for any type of information stored in clear, for example credit card information. Data can be stolen also from different tables by leveraging subqueries. For example, the attacker can inject a scalar subquery (i.e., a subquery returning a single row and a single column) in such a way to obtain the following query:SELECT * FROM users WHERE name = 'admin' AND '1' = (SELECT SUBSTRING(creditCardNo,1,1) FROM creditcards LIMIT 0,1) -- 'In this way, the attacker can learn whether the first digit of the credit card number of the user ‘JohnDoe’ is 1 or not. Note that, to avoid errors, the subquery must return at most one tuple. So the ‘JohnDoe’ account is supposed to be unique in the ‘creditcards’ table.

88

Page 26: This PHP code performs a simple login procedure by ...

If the query is totally blind, that is it influences nothing in the response page, it ispossible to leverage side channels (for example, the time) to perform inference on the query’s result. In time-based SQL injection, the attacker injects time-consuming SQL functions like «sleep(5)» in such a way that they are evaluated only if a particularcondition is met, for example only if the first character of a «password» field is ‘a’. Then, the attacker can observe the server’s response time to infer whether such a condition is true or not.

89

Page 27: This PHP code performs a simple login procedure by ...

The function «sleep(N)» makes the server wait for N seconds each time it getsevaluated, and then it returns 0. It is only supported by MySQL, but other SQL servershave similar functions. Let us assume that «secrettable» is a single-value table, and thatthe «users» table gets queried in the following way:SELECT * FROM users WHERE name = '$input1'The attacker can inject it in such a way to obtain the following query:SELECT * FROM users WHERE name = 'foo' OR (

SELECT sleep(5) FROM secrettableWHERE BINARY SUBSTRING(secret,1,1) = 'a'

) -- 'Note that the result of the query is completely indifferent to the attacker. Also the operator connecting the outer query to the inner one is indifferent: it could be an OR, an AND, a UNION, etc. The key point is that the response time changes whether the first letter of the secrettable’s value is ‘a’ or not. Indeed, if it is ‘a’, then the nestedquery will return a single row, which leads to a (single) evaluation of «sleep(5)». Otherwise, the nested query will not return any row, so «sleep(5)» will not be evaluated.

90

Page 28: This PHP code performs a simple login procedure by ...

Another powerful function that can be used to perform time-based SQL injection is«IF(cond, then-value, else-value)», which returns «then-value» if cond is true or «else-value» otherwise. The IF functions can be used in the following injection, which is ableto exfiltrate the content of «secrettable» even when it is multi-row.SELECT * FROM users WHERE name=‘foo’ OR IF(

BINARY (SELECT SUBSTRING(secret,1,1) FROM secrettable LIMIT 0,1

) = ‘a’, sleep(5), null

) -- '

91

Page 29: This PHP code performs a simple login procedure by ...

Other advanced blind SQL injection techniques are possible that leverage other side channels. For example, in some SQL dialects, it is possible to instruct the server to perform requests to some attacker-controlled URL using the query results as parameter, so that the attacker can capture them. Sometimes it is also possible to writethe query results on some file, that can be stolen afterwards. If the attacker is able to write arbitrary files on the server through SQL injection, she can also upload a webshellinside the document root of the web server. A webshell is a remote shell script, typically written in the PHP language, which allows the attacker to execute remote commands on the server using her browser.

92

Page 30: This PHP code performs a simple login procedure by ...

An attacker can leverage multiple attack vectors to carry out a SQL injection. Apartfrom POST/GET parameters, other common attack vectors are cookies, and server variables for example HTTP header fields like the browser name and version (useragent). Injection attacks through server variables are particulary common in log operations, for example if a website stores in a log database the user agent and the date of each client (see slide above). The database and other server-side variables can be an injection vector, too. Some applications correctly sanitize data when they first receive and store it, but then they retrieve it again and use it to unsafely build SQL queries. The attacker thus can submit malicious input that is correctly escaped whenreceived and stored in the database, and then retrieved again and injected to SQL queries. This is called second order injection. All these infection vectors must be carefully examined and sanitized for SQL injection bugs.

93

Page 31: This PHP code performs a simple login procedure by ...

Countermeasures against SQL injection are of two types: filters and preparedstatements. Filters are a very broad category, and they can be whitelist-based or blacklist-based, string-oriented or character-oriented, and finally blocking filters, removing filters, and escaping filters. Such a categorization is of course non exaustive, and other kinds of filters may be possible.

94

Page 32: This PHP code performs a simple login procedure by ...

String-oriented filters recognize entire substrings or words inside inputs, and they are generally easy to circumvent. The following one is an example of string-orientedremoving filter, which tries to recognize the dangerous «SELECT» statement and removes it from the input:$input = str_replace("SELECT", "", strtoupper($input));Such a filter can be easily bypassed by embedding a filtered word inside anotherfiltered word, for example: «SELSELECTECT». In MySQL it is also possible to embedcomments in the middle of words, for example «SEL/*foo*/ECT», to bypass such filters.This is an example of string-oriented blocking filter, which blocks the execution in case «SELECT» is found in the input:if(strpos($input, "SELECT") !== false) die("Error");The attacker can bypass such a filter by changing the case of the word, for example«select», «SeLeCt» or similar. The «SEL/*foo*/ECT» trick can be also used here.

95

Page 33: This PHP code performs a simple login procedure by ...

String-oriented filters can also produce false positives and incorrectly block/sanitizelegitimate field values. For example the name «Randy» contains the SQL operator «and».Filters oriented to single characters are typically more effective and precise, but some bypass techniques are possible anyway. Filtering the quote (') character is maybe the most common sanitization method, because in case of string injection (e.g., «SELECT * FROM users WHERE name='$input'») it prevents the attacker to introduce the quote character to close the injected string.

96

Page 34: This PHP code performs a simple login procedure by ...

However, it is not secure in all cases. For example, if the injection is numerical (e.g., «SELECT * FROM users WHERE nid=$input», or it involves parts of the query differentfrom literal strings (e.g., «SELECT * FROM users ORDER BY $input») quote filtering iscompletely uneffective. Note that, in these cases, the attacker can perform the attackbut she is prevented to use literal strings in the injected query. However, this can be bypassed by constructing literal strings by concatenation of single characters, each of which is expressed by its ASCII code. For example, instead of injecting «'foo'» the attacker can inject the equivalent expression«CONCAT(CHAR(102),CHAR(111),CHAR(111))», which does not contain quotes.

97

Page 35: This PHP code performs a simple login procedure by ...

In case of string injection, removing or blocking quotes may produce false positives, for example the name «O'Brian» contains a legitimate quote character. A more suitableapproach against string injection is thus escaping quotes.

98

Page 36: This PHP code performs a simple login procedure by ...

The PHP function addslashes() adds a backslash character («\») before each characterinterpreted as a string symbol in the PHP language, that is: «'», «"», «\», and the 0x00 character. Although addslashes() is often used also for escaping SQL strings, using it to defend against string injection is considered a bad security approach. This is becausethe SQL server may interpret the query string with a different character set than the one used by addslashes() to interpret its input (charset mismatch).

99

Page 37: This PHP code performs a simple login procedure by ...

For example, let us suppose that the SQL server accepts GBK-string queries. The can be done for example by calling the mysql_set_charset('gbk') function. The GBK (GuojiaBiaozhun Kuozhan) character set is a superset of ASCII extended for Simplified Chinesecharacters, and it is the second most used one in China. GBK interprets <0x80 bytes asASCII characters, and >=0x80 bytes as the first byte of a byte couple representing a single character. For example, the byte couple 0xE946 represents the 镕 (róng) character.

100

Page 38: This PHP code performs a simple login procedure by ...

Since GBK is ASCII-compatible, with the majority of the legitimate inputs the charsetmismatch will not produce any errors. However, if the attacker injects an (invalid) 0xBF character followed by a quote (0x27), addslashes() will insert a backslash (0x5C) in between. Such a backslash, once interpreted in GBK, will pair with the preceding 0xBF byte thus forming the valid GBK character 0xBF5C (縗). As a result, the quote characterwill not be effectively escaped, and the injection attack will succeed.

101

Page 39: This PHP code performs a simple login procedure by ...

A more secure escaping method is the mysql_real_escape_string() function, because ituses the same character set that will be used by mysql_query() to perform the query. However, the problem raises again if the programmer wrongly change the SQL server’scharacter set through a query, for example with «SET NAMES gbk», which istransparent to the mysql module. In this case, the mysql_real_escape_string() willcontinue to assume ASCII character, and will incorrectly escape the character as in the previous example.

102

Page 40: This PHP code performs a simple login procedure by ...

A more definitive solution are prepared statements, which is a technique by which the query is built in two separate stages: SQL code first and then input parameters. Prepared statements were originally introduced for improving the performance of executing many times the same query with different parameters. As a secondary effect, prepared statements also make SQL injection attacks infeasible. Prepared statementsare available only from PHP 5.0, as part of the «improved» MySQL APIs (mysqli_*()).This code snippet shows an example of prepared statement in PHP language with MySQL. The function mysqli_prepare() prepares a SQL query defined up to twoparameters, indicated by two «?» symbols in the query string. The parameters are inserted in the prepared query afterwards, with the functionmysqli_stmt_bind_param(), where 'ss‘ stands for «two parameters, both of stringtype». The mysqli_stmt_bind_param() function correctly escapes the parameters in such a way that no SQL injection attack is possible. The followingmysql_stmt_execute(), mysqli_stmt_get_result(), and mysqli_stmt_close() functionsrespectively executes the query, retrieves the result, and deallocates the preparedstatement.

103

Page 41: This PHP code performs a simple login procedure by ...

SQL is not the only language subject of injection. Other examples are LDAP filters (LDAP injection), shell commands (OS command injection), Hibernate queries (Hibernateinjection), XPath expressions (XPath injection), etc.LDAP (Lightweight Directory Access Protocol), which is a protocol for accessing and maintaining a directory service, which is a sort of hierarchical non-relational database that binds names to resources. LDAP databases are less powerful than relationaldatabases as they cannot process complex transactions. However, they offer high performances when reading data. This makes LDAP very used to maintain databases of users and credential, which are often read and seldom updated. LDAP databases are queried by means of LDAP search filters.

104

Page 42: This PHP code performs a simple login procedure by ...

An LDAP database simply associates names (e.g., a user name) to resources (e.g., a password hash). It can be queried with an LDAP search operation, which takes a searchfilter as a parameter. An LDAP search filter is specified in a particular string format, which could be subject to injection (LDAP injection) if not properly protected.In the above example, an LDAP search filter is used to check if a given user with given a password is present in the database. It follows a Polish notation (i.e., first the operator «&», followed by a list of operands), and it reads as follows: «cn (common name) ismyuser and pwdhash is […] and pin is 1234».

105

Page 43: This PHP code performs a simple login procedure by ...

The above slide shows a possible LDAP injection attack by tautology technique, afterwhich the search filter always evaluates to true. Note the injected OR operator and the bracket balancing technique.

106

Page 44: This PHP code performs a simple login procedure by ...

This PHP code snippet shows how to correctly escape LDAP filter arguments beforeusing them.

107