diff --git a/webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/plugin/advanced/SqlInjectionChallenge.java b/webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/plugin/advanced/SqlInjectionChallenge.java index 9890947de..ee6dab42a 100644 --- a/webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/plugin/advanced/SqlInjectionChallenge.java +++ b/webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/plugin/advanced/SqlInjectionChallenge.java @@ -26,6 +26,7 @@ import static org.springframework.web.bind.annotation.RequestMethod.POST; @AssignmentPath("SqlInjection/challenge") @AssignmentHints(value = {"SqlInjectionChallenge1", "SqlInjectionChallenge2", "SqlInjectionChallenge3"}) @Slf4j +@AssignmentHints(value ={"SqlInjectionChallengeHint1", "SqlInjectionChallengeHint2", "SqlInjectionChallengeHint3", "SqlInjectionChallengeHint4"}) public class SqlInjectionChallenge extends AssignmentEndpoint { private static final String PASSWORD_TOM = "thisisasecretfortomonly"; diff --git a/webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/plugin/advanced/SqlInjectionLesson6a.java b/webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/plugin/advanced/SqlInjectionLesson6a.java index 5231895c7..8ed18fa7d 100644 --- a/webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/plugin/advanced/SqlInjectionLesson6a.java +++ b/webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/plugin/advanced/SqlInjectionLesson6a.java @@ -1,11 +1,10 @@ - package org.owasp.webgoat.plugin.advanced; import org.owasp.webgoat.assignments.AssignmentEndpoint; import org.owasp.webgoat.assignments.AssignmentHints; import org.owasp.webgoat.assignments.AssignmentPath; import org.owasp.webgoat.assignments.AttackResult; -import org.owasp.webgoat.plugin.introduction.SqlInjectionLesson8; +import org.owasp.webgoat.plugin.introduction.SqlInjectionLesson5a; import org.owasp.webgoat.session.DatabaseUtilities; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @@ -47,7 +46,7 @@ import java.sql.*; * @created October 28, 2003 */ @AssignmentPath("/SqlInjection/attack6a") -@AssignmentHints(value = {"SqlStringInjectionHint6", "SqlStringInjectionHint7", "SqlStringInjectionHint8"}) +@AssignmentHints(value = {"SqlStringInjectionHint6a1", "SqlStringInjectionHint6a2", "SqlStringInjectionHint6a3", "SqlStringInjectionHint6a4"}) public class SqlInjectionLesson6a extends AssignmentEndpoint { @RequestMapping(method = RequestMethod.POST) @@ -60,9 +59,13 @@ public class SqlInjectionLesson6a extends AssignmentEndpoint { protected AttackResult injectableQuery(String accountName) { try { + boolean usedUnion = true; Connection connection = DatabaseUtilities.getConnection(getWebSession()); String query = "SELECT * FROM user_data WHERE last_name = '" + accountName + "'"; - + //Check if Union is used + if(!accountName.matches("(?i)(^[^-/*;)]*)(\\s*)UNION(.*$)")) { + usedUnion = false; + } try { Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); @@ -72,18 +75,19 @@ public class SqlInjectionLesson6a extends AssignmentEndpoint { ResultSetMetaData resultsMetaData = results.getMetaData(); StringBuffer output = new StringBuffer(); - output.append(SqlInjectionLesson8.generateTable(results)); - if(! (query.toLowerCase().contains("union") || query.toLowerCase().contains("join")) ) - output.append("There is also a way to retrieve the Data by using a UNION or JOIN. Can you figure out, how this is done?"); + output.append(SqlInjectionLesson5a.writeTable(results, resultsMetaData)); + if(! usedUnion) + output.append("To succesfully complete this Assignement you have to use a UNION"); results.last(); // If they get back more than one user they succeeded - if (results.getRow() >= 5) { + if (results.getRow() >= 5 && usedUnion) { return trackProgress(success().feedback("sql-injection.6a.success").feedbackArgs(output.toString()).build()); + } else if((output.toString().contains("dave") && output.toString().contains("passW0rD")) && !usedUnion) { + return trackProgress(failed().output("To succesfully complete this Assignement you have to use a UNION").build()); } else { return trackProgress(failed().output(output.toString()).build()); } - } else { return trackProgress(failed().feedback("sql-injection.6a.no.results").build()); @@ -96,4 +100,4 @@ public class SqlInjectionLesson6a extends AssignmentEndpoint { return trackProgress(failed().output(this.getClass().getName() + " : " + e.getMessage()).build()); } } -} +} \ No newline at end of file diff --git a/webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/plugin/introduction/SqlInjectionLesson5a.java b/webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/plugin/introduction/SqlInjectionLesson5a.java new file mode 100644 index 000000000..68a11f38a --- /dev/null +++ b/webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/plugin/introduction/SqlInjectionLesson5a.java @@ -0,0 +1,126 @@ +package org.owasp.webgoat.plugin.introduction; + +import org.owasp.webgoat.assignments.AssignmentEndpoint; +import org.owasp.webgoat.assignments.AssignmentHints; +import org.owasp.webgoat.assignments.AssignmentPath; +import org.owasp.webgoat.assignments.AttackResult; +import org.owasp.webgoat.session.DatabaseUtilities; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; + +import java.io.IOException; +import java.sql.*; + + +/*************************************************************************************************** + * + * + * This file is part of WebGoat, an Open Web Application Security Project utility. For details, + * please see http://www.owasp.org/ + * + * Copyright (c) 2002 - 20014 Bruce Mayhew + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; if + * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Getting Source ============== + * + * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software + * projects. + * + * For details, please see http://webgoat.github.io + * + * @author Bruce Mayhew WebGoat + * @created October 28, 2003 + */ +@AssignmentPath("/SqlInjection/attack5a") +public class SqlInjectionLesson5a extends AssignmentEndpoint { + + @RequestMapping(method = RequestMethod.POST) + public + @ResponseBody + AttackResult completed(@RequestParam String account, @RequestParam String operator, @RequestParam String injection) { + return injectableQuery(account + " " + operator + " " + injection); + } + + protected AttackResult injectableQuery(String accountName) { + try { + Connection connection = DatabaseUtilities.getConnection(getWebSession()); + System.out.println(accountName); + String query = "SELECT * FROM user_data WHERE first_name = 'John' and last_name = '" + accountName + "'"; + try { + Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, + ResultSet.CONCUR_READ_ONLY); + ResultSet results = statement.executeQuery(query); + + if ((results != null) && (results.first())) { + ResultSetMetaData resultsMetaData = results.getMetaData(); + StringBuffer output = new StringBuffer(); + + output.append(writeTable(results, resultsMetaData)); + results.last(); + + // If they get back more than one user they succeeded + if (results.getRow() >= 6) { + return trackProgress(success().feedback("sql-injection.5a.success").feedbackArgs(output.toString()).build()); + } else { + return trackProgress(failed().output(output.toString()).build()); + } + } else { + return trackProgress(failed().feedback("sql-injection.5a.no.results").build()); + + } + } catch (SQLException sqle) { + + return trackProgress(failed().output(sqle.getMessage()).build()); + } + } catch (Exception e) { + return trackProgress(failed().output(this.getClass().getName() + " : " + e.getMessage()).build()); + } + } + + public static String writeTable(ResultSet results, ResultSetMetaData resultsMetaData) throws IOException, + SQLException { + int numColumns = resultsMetaData.getColumnCount(); + results.beforeFirst(); + StringBuffer t = new StringBuffer(); + t.append("

"); + + if (results.next()) { + for (int i = 1; i < (numColumns + 1); i++) { + t.append(resultsMetaData.getColumnName(i)); + t.append(", "); + } + + t.append("
"); + results.beforeFirst(); + + while (results.next()) { + + for (int i = 1; i < (numColumns + 1); i++) { + t.append(results.getString(i)); + t.append(", "); + } + + t.append("
"); + } + + } else { + t.append("Query Successful; however no data was returned from this query."); + } + + t.append("

"); + return (t.toString()); + } +} \ No newline at end of file diff --git a/webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/plugin/introduction/SqlInjectionLesson5b.java b/webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/plugin/introduction/SqlInjectionLesson5b.java new file mode 100644 index 000000000..b0bececef --- /dev/null +++ b/webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/plugin/introduction/SqlInjectionLesson5b.java @@ -0,0 +1,109 @@ +package org.owasp.webgoat.plugin.introduction; + + +import org.owasp.webgoat.assignments.AssignmentEndpoint; +import org.owasp.webgoat.assignments.AssignmentHints; +import org.owasp.webgoat.assignments.AssignmentPath; +import org.owasp.webgoat.assignments.AttackResult; +import org.owasp.webgoat.session.DatabaseUtilities; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; + +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.sql.*; + + +/*************************************************************************************************** + * + * + * This file is part of WebGoat, an Open Web Application Security Project utility. For details, + * please see http://www.owasp.org/ + * + * Copyright (c) 2002 - 20014 Bruce Mayhew + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; if + * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Getting Source ============== + * + * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software + * projects. + * + * For details, please see http://webgoat.github.io + * + * @author Bruce Mayhew WebGoat + * @created October 28, 2003 + */ +@AssignmentPath("/SqlInjection/attack5b") +@AssignmentHints(value = {"SqlStringInjectionHint5b1", "SqlStringInjectionHint5b2", "SqlStringInjectionHint5b3", "SqlStringInjectionHint5b4"}) +public class SqlInjectionLesson5b extends AssignmentEndpoint { + + @RequestMapping(method = RequestMethod.POST) + public + @ResponseBody + AttackResult completed(@RequestParam String userid, @RequestParam String login_count, HttpServletRequest request) throws IOException { + return injectableQuery(login_count, userid); + } + + protected AttackResult injectableQuery(String login_count, String accountName) { + try { + Connection connection = DatabaseUtilities.getConnection(getWebSession()); + PreparedStatement query = connection.prepareStatement("SELECT * From user_data WHERE Login_Count = ? and userid= " + accountName, ResultSet.TYPE_SCROLL_INSENSITIVE, + ResultSet.CONCUR_READ_ONLY); + + int count = 0; + try { + count = Integer.parseInt(login_count); + } catch(Exception e) { + return trackProgress(failed().output(this.getClass().getName() + " : " + e.getMessage()).build()); + } + + query.setInt(1, count); + //String query = "SELECT * FROM user_data WHERE Login_Count = " + login_count + " and userid = " + accountName, ; + System.err.println("Querry: " + query); + try { + Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, + ResultSet.CONCUR_READ_ONLY); + ResultSet results = query.executeQuery(); + + if ((results != null) && (results.first() == true)) { + ResultSetMetaData resultsMetaData = results.getMetaData(); + StringBuffer output = new StringBuffer(); + + output.append(SqlInjectionLesson5a.writeTable(results, resultsMetaData)); + results.last(); + + // If they get back more than one user they succeeded + if (results.getRow() >= 6) { + return trackProgress(success().feedback("sql-injection.5b.success").feedbackArgs(output.toString()).build()); + } else { + return trackProgress(failed().output(output.toString()).build()); + } + + } else { + return trackProgress(failed().feedback("sql-injection.5b.no.results").build()); + +// output.append(getLabelManager().get("NoResultsMatched")); + } + } catch (SQLException sqle) { + + return trackProgress(failed().output(sqle.getMessage()).build()); + } + } catch (Exception e) { + e.printStackTrace(); + return trackProgress(failed().output(this.getClass().getName() + " : " + e.getMessage()).build()); + } + } +} \ No newline at end of file diff --git a/webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/plugin/mitigation/SqlInjectionLesson12a.java b/webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/plugin/mitigation/SqlInjectionLesson12a.java index 896eec53c..1394cfd53 100644 --- a/webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/plugin/mitigation/SqlInjectionLesson12a.java +++ b/webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/plugin/mitigation/SqlInjectionLesson12a.java @@ -33,8 +33,9 @@ public class SqlInjectionLesson12a extends AssignmentEndpoint { @SneakyThrows public AttackResult completed(@RequestParam String ip) { Connection connection = DatabaseUtilities.getConnection(webSession); - PreparedStatement preparedStatement = connection.prepareStatement("select ip from servers where hostname = 'webgoat-prd' and ip = ?"); + PreparedStatement preparedStatement = connection.prepareStatement("select ip from servers where ip = ? and hostname = ?"); preparedStatement.setString(1, ip); + preparedStatement.setString(2, "webgoat-prd"); ResultSet resultSet = preparedStatement.executeQuery(); if (resultSet.next()) { return trackProgress(success().build()); diff --git a/webgoat-lessons/sql-injection/src/main/resources/html/SqlInjection.html b/webgoat-lessons/sql-injection/src/main/resources/html/SqlInjection.html index 39f8594e4..146625452 100644 --- a/webgoat-lessons/sql-injection/src/main/resources/html/SqlInjection.html +++ b/webgoat-lessons/sql-injection/src/main/resources/html/SqlInjection.html @@ -52,6 +52,79 @@
+
+
+
+
+
+ + + + + + + + +
SELECT * FROM users WHERE LOGIN_COUNT > 0 and FIRST_NAME = ' + + + +
+
+
+
+
+
+ +
+
+
+
+
+ + + + + + + + + + + + + +
Login_Count:
User_Id:
+
+
+
+
+
+
diff --git a/webgoat-lessons/sql-injection/src/main/resources/i18n/WebGoatLabels.properties b/webgoat-lessons/sql-injection/src/main/resources/i18n/WebGoatLabels.properties index 3472a053d..45825e4c1 100644 --- a/webgoat-lessons/sql-injection/src/main/resources/i18n/WebGoatLabels.properties +++ b/webgoat-lessons/sql-injection/src/main/resources/i18n/WebGoatLabels.properties @@ -12,9 +12,18 @@ SqlInjectionChallenge3=Use tooling to automate this attack sql-injection.error= NoResultsMatched=No results matched. Try Again. -SqlStringInjectionHint6=Try Appending a new SQL Statement to the Query. -SqlStringInjectionHint7=The new SQL Statement can be really simple like: SELECT ... FROM ... -SqlStringInjectionHint8=Your new SQL Query should start, with a " ; " and end with " -- " +SqlInjectionChallengeHint1=The Table Name is randomized at each start of Webgoat, try to figure out the name first. +SqlInjectionChallengeHint2=Find the Field which is vulnerable to SQL Injection use that to change the password. +SqlInjectionChallengeHint3=Change the password through an Update Statement. +SqlInjectionChallengeHint4=The Vulnerable Field is the Username Field of the Register form. +SqlStringInjectionHint5b1=Try to check which of the input fields is susceptible to an injection attack. +SqlStringInjectionHint5b2=Insert 0 or 1 = 1 into the first input field. Th Output should tell you if this field is injectable. +SqlStringInjectionHint5b3=The first Input field is not susceptible to sql injection. +SqlStringInjectionHint5b4=You don't need to insert any quotations into your injection-string. +SqlStringInjectionHint6a1=Try Appending stuff like ",1" to your query, to figure out how many columns there are. +SqlStringInjectionHint6a2=When using a UNION the number of columns, from both tables should match. +SqlStringInjectionHint6a3=The UNION should contain 7 columns. +SqlStringInjectionHint6a4=Try using these columns in your union: userid, user_name, password, cookie, cookie, cookie, userid. SqlStringInjectionHint9=Try sorting and look at the request SqlStringInjectionHint10=Intercept the request and try to specify a different order by SqlStringInjectionHint10a1=First establish a connection, after that you can create a statement. diff --git a/webgoat-lessons/sql-injection/src/main/resources/lessonPlans/en/SqlInjection_content6a.adoc b/webgoat-lessons/sql-injection/src/main/resources/lessonPlans/en/SqlInjection_content6a.adoc index 7dc74e14c..8256ad1ff 100644 --- a/webgoat-lessons/sql-injection/src/main/resources/lessonPlans/en/SqlInjection_content6a.adoc +++ b/webgoat-lessons/sql-injection/src/main/resources/lessonPlans/en/SqlInjection_content6a.adoc @@ -1,6 +1,8 @@ == Try It! Pulling data from other tables -Lets try to exploit the fact that you can append your own SQL Statement. One of the tables in the WebGoat database is: +Lets try to exploit the fact that you can use a union to get the contents of another table. + +One of the tables in the WebGoat database is: ------------------------------------------------------- CREATE TABLE user_system_data (userid int not null primary key, @@ -9,7 +11,5 @@ CREATE TABLE user_system_data (userid int not null primary key, cookie varchar(30)); ------------------------------------------------------- -*6.a)* Inject your own Query into the SQL Statement to retrieve all Data from the Table. + -*6.b)* When you have figured it out.... What is Dave's password? - - +*6.a)* Retrieve all data from the table by using a UNION (You have to use a union to complete this assignment.) + +*6.b)* When you have figured it out.... What is Dave's password? \ No newline at end of file diff --git a/webgoat-lessons/sql-injection/src/main/resources/lessonPlans/en/SqlInjection_introduction_content11.adoc b/webgoat-lessons/sql-injection/src/main/resources/lessonPlans/en/SqlInjection_introduction_content11.adoc new file mode 100644 index 000000000..a73fdc660 --- /dev/null +++ b/webgoat-lessons/sql-injection/src/main/resources/lessonPlans/en/SqlInjection_introduction_content11.adoc @@ -0,0 +1,9 @@ +== Try It! String SQL Injection + +The query in the code builds a dynamic query as seen in the previous example. The query in the code builds a dynamic query by concatenating strings making it susceptible to String SQL injection: + +------------------------------------------------------------ +"select * from users where LOGIN_COUNT > 0 and FIRST_NAME = ‘" + userName + "'"; +------------------------------------------------------------ + +Using the form below try to retrieve all the users from the users table. You shouldn't need to know any specific user name to get the complete list. diff --git a/webgoat-lessons/sql-injection/src/main/resources/lessonPlans/en/SqlInjection_introduction_content12.adoc b/webgoat-lessons/sql-injection/src/main/resources/lessonPlans/en/SqlInjection_introduction_content12.adoc new file mode 100644 index 000000000..7dbbc5ae4 --- /dev/null +++ b/webgoat-lessons/sql-injection/src/main/resources/lessonPlans/en/SqlInjection_introduction_content12.adoc @@ -0,0 +1,11 @@ +== Try It! Numeric SQL Injection + +The query in the code builds a dynamic query as seen in the previous example. The query in the code builds a dynamic query by concatenating a number making it susceptible to Numeric SQL injection: + +-------------------------------------------------- +"select * from users where Login_Count = " + Login_Count + " and USERID = " + UserID; +-------------------------------------------------- + +Using the two Input Fields below, try to retrieve all the date from the users table. + +Warning: Only one of these fields is susceptible to SQL Injection. You need to find out which, to successfully retrieve all the data. \ No newline at end of file diff --git a/webgoat-lessons/sql-injection/src/main/resources/lessonPlans/en/SqlInjection_order_by.adoc b/webgoat-lessons/sql-injection/src/main/resources/lessonPlans/en/SqlInjection_order_by.adoc index 6e8ff54e0..d4806d1ed 100644 --- a/webgoat-lessons/sql-injection/src/main/resources/lessonPlans/en/SqlInjection_order_by.adoc +++ b/webgoat-lessons/sql-injection/src/main/resources/lessonPlans/en/SqlInjection_order_by.adoc @@ -2,4 +2,6 @@ In this assignment try to perform an SQL injection through the ORDER BY field. Try to find the ip address of the `webgoat-prd` server, guessing the complete ip address might take too long so we give you the last part: `xxx.130.219.202` +Tip: To complete this assignment a tool such as OWASP ZAP is required. + Note: The submit field of this assignment is *NOT* vulnerable for an SQL injection. \ No newline at end of file