Upload
globe-telecom
View
45
Download
0
Embed Size (px)
Citation preview
Understanding SQLBY: JOHN PATRICK LITAINFORMATION SECURITY CONSULTANT – GLOBE TELECOM
ONLINE BANK
Email Address
PasswordLog in
Our website is secure, almost never get hacked
ONLINE BANK
passwordLog in
Our website is secure, almost never get hacked
Lets assume the attacker trying to guess what is the password of tcon
user
Unknown username and password
An error message prompted
ONLINE BANK
password’Log in
Our website is secure, almost never get hacked
By adding a single quote (‘) at the end of the password, lets see the behavior of
the application
An unexpected Error occuredAn error message
prompted
The logs show aSQL Syntax error.This indicates that The quote characterMessed something upIn an unexpected way
SELECT *FROM usersWHERE email = ‘?’AND pass = ‘?’ LIMIT 1
This is what the application code looks
like behind the scenes. Let’s see how
the SQL code gets built as you enter your login details
ONLINE BANK
password’Log in
Our website is secure, almost never get hackedAn unexpected Error occurred
"'password'' limit 1" LINE 1: ...ers where email = ‘[email protected]' and
password = 'password'... ^ : select * from users where email =
‘[email protected]' and password = 'password'' limit 1.Unable to login this
user due to unexpected error.
Unexpected Error
SELECT *FROM usersWHERE email = ‘[email protected]’AND pass = ‘password’’ LIMIT 1This is what the
application code looks like behind the
scenes. Let’s see how the SQL code gets built as you enter your login details
Authentication Bypass 1
ONLINE BANK
Email Address
PasswordLog in
Our website is secure, almost never get hacked
Enter the following credentials and click “Log In”:
Email:
Password:
‘ or 1=1--
Authentication Bypass 1
ONLINE BANK
‘ or 1=1--Log in
Our website is secure, almost never get hacked
Rendering login page.Checking supplied authentication details for [email protected] user in database.Authentication details confirmed, establishing session for this user.
Authentication Bypass 1
ONLINE BANKBank Accounts
Account Available Balance Present BalanceChecking PHP 80,260.56 PHP 80,260.56Savings PHP 95,895.96 PHP 95.895.96
Transfer Funds!
Authentication Bypass 1
SELECT *FROM usersWHERE email = ‘[email protected]’AND pass = ‘1 or 1=1--’ LIMIT 1
The - - characters you entered cause the database to ignore the rest of the SQL
statement, allowing you to be authenticated without having to supply the real password
Code walkthroughHACKTHENORTH.ORG
Code walkthroughstring email = request.getParameter("Email");String password = request.getParameter("password");
String sql = "select * from users where (email='" + email +"' and password='" + password +"')";
Connection connection = pool.getConnection();Statement statement = connection.createStatement();ResultSet result = statement.executeQuery(sql);
if (result.next()) {LoggedIn = true;
#Successfully logged in and redirect to user profile page} else {
#Authentication failure - Redirect to login page}
Code walkthroughstring email = request.getParameter("Email");String password = request.getParameter("password");
String sql = "select * from users where (email='" + email +"' and password='" + password +"')";
Connection connection = pool.getConnection();Statement statement = connection.createStatement();ResultSet result = statement.executeQuery(sql);
if (result.next()) {LoggedIn = true;
#Successfully logged in and redirect to user profile page} else {
#Authentication failure - Redirect to login page}
To validate user credentials, the request.getParamenter()
method is first called to extract tcon’s email (from HTTP request parameter)
which is assigned to the email variable
Code walkthroughstring email = request.getParameter("Email");String password = request.getParameter("password");
String sql = "select * from users where (email='" + email +"' and password='" + password +"')";
Connection connection = pool.getConnection();Statement statement = connection.createStatement();ResultSet result = statement.executeQuery(sql);
if (result.next()) {LoggedIn = true;
#Successfully logged in and redirect to user profile page} else {
#Authentication failure - Redirect to login page}
Similarly, the request.getParameter()
method is called to extract tcon’s password value and
assigned to password variable
Code walkthroughstring email = request.getParameter("Email");String password = request.getParameter("password");
String sql = "select * from users where (email='" + email +"' and password='" + password +"')";
Connection connection = pool.getConnection();Statement statement = connection.createStatement();ResultSet result = statement.executeQuery(sql);
if (result.next()) {LoggedIn = true;
#Successfully logged in and redirect to user profile page} else {
#Authentication failure - Redirect to login page}
The string variable sql is then declared which represents the SQL query used to authenticate tcon’s
credentials.
Note, the tcon’s email and password value are concatenated to build the
final query
Code walkthroughstring email = request.getParameter("Email");String password = request.getParameter("password");
String sql = "select * from users where (email='" + email +"' and password='" + password +"')";
Connection connection = pool.getConnection();Statement statement = connection.createStatement();ResultSet result = statement.executeQuery(sql);
if (result.next()) {LoggedIn = true;
#Successfully logged in and redirect to user profile page} else {
#Authentication failure - Redirect to login page}
The SQL query in defined in sql string variable is then executed by invoking the executeQuery method. This method executes our query against the backend SQL server and returns a result as
ResultSet object which is on result.next through the if/else block
Finally, should tcon’s credentials match the loggedIn variable is set to true and tcon is redirected to its profile page.
Simplify the Code
Code walkthroughstring email = request.getParameter("Email");String password = request.getParameter("password");
String sql = "select * from users where (email='" + email +"' and password='" + password +"')";
Connection connection = pool.getConnection();Statement statement = connection.createStatement();ResultSet result = statement.executeQuery(sql);
if (result.next()) {LoggedIn = true;
#Successfully logged in and redirect to user profile page} else {
#Authentication failure - Redirect to login page}
Code walkthrough//string email = request.getParameter("Email");//String password = request.getParameter("password");
String sql = "select * from users where (email='" + email +"' and password='" + password +"')";
//Connection connection = pool.getConnection();//Statement statement = connection.createStatement();//ResultSet result = statement.executeQuery(sql);
//if (result.next()) {//LoggedIn = true;// #Successfully logged in and redirect to user profile page//} else {// #Authentication failure - Redirect to login page//}
Now that we have simplified our authentication logic code, lets analyze the SQL query generated by Bank to validate tcon’s
authentication credentials
Understanding Injection
Step 1: Enter the password [email protected] and watch the code widow. Notice how the single quote (‘) you appended is interpreted by the SQL server as a string delimiter.
However, when the query is processed, the last quote does not have a closing/matching (‘) character, which cause a SQL Syntax Error, resulting in the HTTP 500 Internal server Error
Step 2: Now try logging with a password followed by two single quotes e.g. password’’ Interestingly the application does nor error in this case
Action:1
ONLINE BANK
Email Address
PasswordLog in
Our website is secure, almost never get hacked
Action:1
ONLINE BANK
password’Log in
Our website is secure, almost never get hacked
Action:1
ONLINE BANK
Our website is secure, almost never get hacked
Action:1
ONLINE BANK
Our website is secure, almost never get hacked
500 Internal Server Error.
The server encounter an internal error or misconfiguration and was unable to complete your
request. Please contact your handsome administrator and inform them of the time the error occurred, and anything might have done that may have caused the
error.Also by them a coffee or burger so that they will fix
your problem
Action:2
ONLINE BANK
password’’Log in
Our website is secure, almost never get hacked
Action:2
ONLINE BANK
passwordLog in
Our website is secure, almost never get hacked
ERROR: Invalid username and password
Bypassing Authentication
At this point we know that injecting characters interpreted by the database server is known as SQL injection
How ever, it’s not just (‘) characters that can be injected, entire strings can be injected, entire strings can be injected. What if this could be used to alter the purpose of the SQL Statement Entirely?
Bypassing Authentication
ONLINE BANK
Password ‘ 1 or 1=1)#
Log in
Our website is secure, almost never get hacked
Note in MySQL the (#) character is used for code comments. Keep an eye on the code, everything to the right of the (#) character is commented our, including the extra (‘) and ) character.
Note: the provided SQL payload is the one must use
Bypassing Authentication
ONLINE BANK
Our website is secure, almost never get hacked
Bypassing Authentication
ONLINE BANKBank Accounts
Account Available Balance Present BalanceChecking PHP 80,260.56 PHP 80,260.56Savings PHP 95,895.96 PHP 95.895.96
Transfer Funds!
Authentication was bypass, but why?
The credentials we provide on the login resulted in the following SQL statement:
SELECT *WHERE (email = ‘[email protected]’)AND password = ‘ ‘ OR 1=1)#
Because the statement is both syntactically valid and OR 1=1 always return true, the authentication mechanism was bypassed. Let’s now analyze the Vulnerability from a code perspective
Code walkthroughstring email = request.getParameter("Email");String password = request.getParameter("password");
String sql = "select * from users where (email='" + email +"' and password='" + password +"')";
Connection connection = pool.getConnection();Statement statement = connection.createStatement();ResultSet result = statement.executeQuery(sql);
if (result.next()) {LoggedIn = true;
#Successfully logged in and redirect to user profile page} else {
#Authentication failure - Redirect to login page}
To quickly recap, the request.getParameter() method is first called to
extract tcon’s username and password values which are assigned to the email and
password variable
Code walkthroughstring email = request.getParameter("Email");String password = request.getParameter("password");
String sql = "select * from users where (email='" + email +"' and password='" + password +"')";
Connection connection = pool.getConnection();Statement statement = connection.createStatement();ResultSet result = statement.executeQuery(sql);
if (result.next()) {LoggedIn = true;
#Successfully logged in and redirect to user profile page} else {
#Authentication failure - Redirect to login page}
The string variable sql is then declared, which represents the SQL query used to
authenticate tcon’s credentials
Code walkthroughstring email = request.getParameter("Email");String password = request.getParameter("password");
String sql = "select * from users where (email='" + email +"' and password='" + password +"')";
Connection connection = pool.getConnection();Statement statement = connection.createStatement();ResultSet result = statement.executeQuery(sql);
if (result.next()) {LoggedIn = true;
#Successfully logged in and redirect to user profile page} else {
#Authentication failure - Redirect to login page}
Notice that tcon’s email and password input (retrieved using the request.getParameter() method) are concatenated within the variabl sql , without any input validation checks.
Input Validation
Because there is no input validation (i.e. no checking of legal characters, minimum/maximum string lengths, or removal of “malicious” characters) TCON has the ability to inject raw SQL syntax within the username and password input fields to alter the meaning of the underlying SQL query responsible for authentication, resulting in a bypass of the application’s authentication mechanism
A SQL Injection Attack!
RemediationHACKTHENORTH.ORG
Remediation
Prepared Statements (A.K.A parameterized queries) are the best mechanism for preventing SQL injection attacks
Prepared statements are used to abstract SQL statement syntax from input parameters. Statement templates are first defined at the application layer, and the parameters are then passed to them
In java this can be achieved using PreparedStatement class for sending SQL statements to the backend database
Aside from a better security posture against SQL injection attacks, prepared statements offer improved code quality from a legibility and maintainability perspective due to separation of SQL logic from inputs
Code walkthroughstring email = request.getParameter("Email");String password = request.getParameter("password");
//String sql = "select * from users where (email='" + email +"' and password='" + password +"')";String sql = “select * from users where email = ? and password = ?”;
Connection connection = pool.getConnection();//Statement statement = connection.createStatement();PreparedStatement preparedStatement = connection.prepareStatement(sql);
//ResultSet result = statement.executeQuery(sql);
preparedStatement.setString(1, email);preparedStatement.setString(2, password);
ResultSet result = preparedStatement.executeQuery();
if (result.next()) {LoggedIn = true;
#Successfully logged in and redirect to user profile page} else {
#Authentication failure - Redirect to login page}
In our modified code example, we first declared the authentication query string and assign it to the sql string variable. Notice that the email and password variable have now been replace with (?) symbol which act as a place holder for java’s PreparedStatement class.
Code walkthroughstring email = request.getParameter("Email");String password = request.getParameter("password");
//String sql = "select * from users where (email='" + email +"' and password='" + password +"')";String sql = “select * from users where email = ? and password = ?”;
Connection connection = pool.getConnection();//Statement statement = connection.createStatement();PreparedStatement preparedStatement = connection.prepareStatement(sql);
//ResultSet result = statement.executeQuery(sql);
preparedStatement.setString(1, email);preparedStatement.setString(2, password);
ResultSet result = preparedStatement.executeQuery();
if (result.next()) {LoggedIn = true;
#Successfully logged in and redirect to user profile page} else {
#Authentication failure - Redirect to login page}
The sql string variable is then passed as an argument to the preparedStatement() method, which precompiles the SQL query and creates a PreparedStatement object for sending parameteized SQL statements to the back end SQL Server
Code walkthroughstring email = request.getParameter("Email");String password = request.getParameter("password");
//String sql = "select * from users where (email='" + email +"' and password='" + password +"')";String sql = “select * from users where email = ? and password = ?”;
Connection connection = pool.getConnection();//Statement statement = connection.createStatement();PreparedStatement preparedStatement = connection.prepareStatement(sql);
//ResultSet result = statement.executeQuery(sql);
preparedStatement.setString(1, email);preparedStatement.setString(2, password);
ResultSet result = preparedStatement.executeQuery();
if (result.next()) {LoggedIn = true;
#Successfully logged in and redirect to user profile page} else {
#Authentication failure - Redirect to login page}
Similarly, the setString() method is then called to pass the password parameter value to our prepared statement.
Code walkthroughstring email = request.getParameter("Email");String password = request.getParameter("password");
//String sql = "select * from users where (email='" + email +"' and password='" + password +"')";String sql = “select * from users where email = ? and password = ?”;
Connection connection = pool.getConnection();//Statement statement = connection.createStatement();PreparedStatement preparedStatement = connection.prepareStatement(sql);
//ResultSet result = statement.executeQuery(sql);
preparedStatement.setString(1, email);preparedStatement.setString(2, password);
ResultSet result = preparedStatement.executeQuery();
if (result.next()) {LoggedIn = true;
#Successfully logged in and redirect to user profile page} else {
#Authentication failure - Redirect to login page}
Finally, we execute our authentication query by invoking the preparedStatement.executeQuery() method. The SQL used by prepareStatement is precompiled ensuring that all parameters sent to underlying database are treated as literal value and not SQL statement/query language, ensuring that no SQL code can be injected using an untrusted parameter.
Ultimately, the security payoff with using prepared statements is that the database will ensure that parameters are automatically escaped
END OF THE SLIDEHACKTHENORTH.ORG
References:
HackplainingOWASP FoundationCodeBashing