Adjust lesson template (#704)

* Remove method `getId()` from all lessons as it defaults to the class name

* remove clean up endpoint

* remove unused class `RequestParameter`

* remove unused class `PluginLoadingFailure`

* Move `CourseConfiguration` to lesson package

* Add more content around the lesson template lesson and make it visible as a lesson in WebGoat

* Remove explicit invocation `trackProgress()` inside WebGoat framework so assignments only need to return an `AttackResult`

* Put original solution back as well for SQL string injection

* review comments

* Add
This commit is contained in:
Nanne Baars
2019-11-17 13:39:56 +01:00
committed by René Zubcevic
parent f40b6ffd31
commit 5dd6b31905
139 changed files with 769 additions and 870 deletions

View File

@ -37,9 +37,4 @@ public class SqlInjectionAdvanced extends Lesson {
public String getTitle() {
return "2.sql.advanced.title";
}
@Override
public String getId() {
return "SqlInjectionAdvanced";
}
}

View File

@ -66,9 +66,9 @@ public class SqlInjectionChallenge extends AssignmentEndpoint {
if (resultSet.next()) {
if (username_reg.contains("tom'")) {
attackResult = trackProgress(success().feedback("user.exists").build());
attackResult = success(this).feedback("user.exists").build();
} else {
attackResult = failed().feedback("user.exists").feedbackArgs(username_reg).build();
attackResult = failed(this).feedback("user.exists").feedbackArgs(username_reg).build();
}
} else {
PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO sql_challenge_users VALUES (?, ?, ?)");
@ -76,10 +76,10 @@ public class SqlInjectionChallenge extends AssignmentEndpoint {
preparedStatement.setString(2, email_reg);
preparedStatement.setString(3, password_reg);
preparedStatement.execute();
attackResult = success().feedback("user.created").feedbackArgs(username_reg).build();
attackResult = success(this).feedback("user.created").feedbackArgs(username_reg).build();
}
} catch (SQLException e) {
attackResult = failed().output("Something went wrong").build();
attackResult = failed(this).output("Something went wrong").build();
}
}
return attackResult;
@ -87,10 +87,10 @@ public class SqlInjectionChallenge extends AssignmentEndpoint {
private AttackResult checkArguments(String username_reg, String email_reg, String password_reg) {
if (StringUtils.isEmpty(username_reg) || StringUtils.isEmpty(email_reg) || StringUtils.isEmpty(password_reg)) {
return failed().feedback("input.invalid").build();
return failed(this).feedback("input.invalid").build();
}
if (username_reg.length() > 250 || email_reg.length() > 30 || password_reg.length() > 30) {
return failed().feedback("input.invalid").build();
return failed(this).feedback("input.invalid").build();
}
return null;
}

View File

@ -54,10 +54,10 @@ public class SqlInjectionChallengeLogin extends AssignmentEndpoint {
ResultSet resultSet = statement.executeQuery();
if (resultSet.next()) {
return ("tom".equals(username_login)) ? trackProgress(success().build())
: success().feedback("ResultsButNotTom").build();
return ("tom".equals(username_login)) ? success(this).build()
: success(this).feedback("ResultsButNotTom").build();
} else {
return failed().feedback("NoResultsMatched").build();
return failed(this).feedback("NoResultsMatched").build();
}
}
}

View File

@ -81,19 +81,19 @@ public class SqlInjectionLesson6a extends AssignmentEndpoint {
if (output.toString().contains("dave") && output.toString().contains("passW0rD")) {
output.append(appendingWhenSucceded);
return trackProgress(success().feedback("sql-injection.advanced.6a.success").feedbackArgs(output.toString()).output(" Your query was: " + query).build());
return success(this).feedback("sql-injection.advanced.6a.success").feedbackArgs(output.toString()).output(" Your query was: " + query).build();
} else {
return trackProgress(failed().output(output.toString() + "<br> Your query was: " + query).build());
return failed(this).output(output.toString() + "<br> Your query was: " + query).build();
}
} else {
return trackProgress(failed().feedback("sql-injection.advanced.6a.no.results").output(" Your query was: " + query).build());
return failed(this).feedback("sql-injection.advanced.6a.no.results").output(" Your query was: " + query).build();
}
} catch (SQLException sqle) {
return trackProgress(failed().output(sqle.getMessage() + "<br> Your query was: " + query).build());
return failed(this).output(sqle.getMessage() + "<br> Your query was: " + query).build();
}
} catch (Exception e) {
e.printStackTrace();
return trackProgress(failed().output(this.getClass().getName() + " : " + e.getMessage() + "<br> Your query was: " + query).build());
return failed(this).output(this.getClass().getName() + " : " + e.getMessage() + "<br> Your query was: " + query).build();
}
}
}

View File

@ -51,9 +51,9 @@ public class SqlInjectionLesson6b extends AssignmentEndpoint {
@ResponseBody
public AttackResult completed(@RequestParam String userid_6b) throws IOException {
if (userid_6b.equals(getPassword())) {
return trackProgress(success().build());
return success(this).build();
} else {
return trackProgress(failed().build());
return failed(this).build();
}
}

View File

@ -59,9 +59,9 @@ public class SqlInjectionQuiz extends AssignmentEndpoint {
}
if (correctAnswers == solutions.length) {
return trackProgress(success().build());
return success(this).build();
} else {
return trackProgress(failed().build());
return failed(this).build();
}
}

View File

@ -37,9 +37,4 @@ public class SqlInjection extends Lesson {
public String getTitle() {
return "1.sql.injection.title";
}
@Override
public String getId() {
return "SqlInjection";
}
}

View File

@ -65,24 +65,24 @@ public class SqlInjectionLesson10 extends AssignmentEndpoint {
if (results.getStatement() != null) {
results.first();
output.append(SqlInjectionLesson8.generateTable(results));
return trackProgress(failed().feedback("sql-injection.10.entries").output(output.toString()).build());
return failed(this).feedback("sql-injection.10.entries").output(output.toString()).build();
} else {
if (tableExists(connection)) {
return trackProgress(failed().feedback("sql-injection.10.entries").output(output.toString()).build());
return failed(this).feedback("sql-injection.10.entries").output(output.toString()).build();
} else {
return trackProgress(success().feedback("sql-injection.10.success").build());
return success(this).feedback("sql-injection.10.success").build();
}
}
} catch (SQLException e) {
if (tableExists(connection)) {
return trackProgress(failed().feedback("sql-injection.error").output("<span class='feedback-negative'>" + e.getMessage() + "</span><br>" + output.toString()).build());
return failed(this).feedback("sql-injection.error").output("<span class='feedback-negative'>" + e.getMessage() + "</span><br>" + output.toString()).build();
} else {
return trackProgress(success().feedback("sql-injection.10.success").build());
return success(this).feedback("sql-injection.10.success").build();
}
}
} catch (Exception e) {
return trackProgress(failed().output("<span class='feedback-negative'>" + e.getMessage() + "</span>").build());
return failed(this).output("<span class='feedback-negative'>" + e.getMessage() + "</span>").build();
}
}

View File

@ -67,12 +67,12 @@ public class SqlInjectionLesson2 extends AssignmentEndpoint {
if (results.getString("department").equals("Marketing")) {
output.append("<span class='feedback-positive'>" + query + "</span>");
output.append(SqlInjectionLesson8.generateTable(results));
return trackProgress(success().feedback("sql-injection.2.success").output(output.toString()).build());
return success(this).feedback("sql-injection.2.success").output(output.toString()).build();
} else {
return trackProgress(failed().feedback("sql-injection.2.failed").output(output.toString()).build());
return failed(this).feedback("sql-injection.2.failed").output(output.toString()).build();
}
} catch (SQLException sqle) {
return trackProgress(failed().feedback("sql-injection.2.failed").output(sqle.getMessage()).build());
return failed(this).feedback("sql-injection.2.failed").output(sqle.getMessage()).build();
}
}
}

View File

@ -70,16 +70,16 @@ public class SqlInjectionLesson3 extends AssignmentEndpoint {
if (results.getString("department").equals("Sales")) {
output.append("<span class='feedback-positive'>" + query + "</span>");
output.append(SqlInjectionLesson8.generateTable(results));
return trackProgress(success().output(output.toString()).build());
return success(this).output(output.toString()).build();
} else {
return trackProgress(failed().output(output.toString()).build());
return failed(this).output(output.toString()).build();
}
} catch (SQLException sqle) {
return trackProgress(failed().output(sqle.getMessage()).build());
return failed(this).output(sqle.getMessage()).build();
}
} catch (Exception e) {
return trackProgress(failed().output(this.getClass().getName() + " : " + e.getMessage()).build());
return failed(this).output(this.getClass().getName() + " : " + e.getMessage()).build();
}
}
}

View File

@ -63,15 +63,15 @@ public class SqlInjectionLesson4 extends AssignmentEndpoint {
// user completes lesson if column phone exists
if (results.first()) {
output.append("<span class='feedback-positive'>" + query + "</span>");
return trackProgress(success().output(output.toString()).build());
return success(this).output(output.toString()).build();
} else {
return trackProgress(failed().output(output.toString()).build());
return failed(this).output(output.toString()).build();
}
} catch (SQLException sqle) {
return trackProgress(failed().output(sqle.getMessage()).build());
return failed(this).output(sqle.getMessage()).build();
}
} catch (Exception e) {
return trackProgress(failed().output(this.getClass().getName() + " : " + e.getMessage()).build());
return failed(this).output(this.getClass().getName() + " : " + e.getMessage()).build();
}
}
}

View File

@ -27,7 +27,6 @@ import org.owasp.webgoat.assignments.AssignmentEndpoint;
import org.owasp.webgoat.assignments.AssignmentHints;
import org.owasp.webgoat.assignments.AttackResult;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
@ -50,12 +49,12 @@ public class SqlInjectionLesson5 extends AssignmentEndpoint {
// user completes lesson if the query is correct
if (query.matches(regex)) {
output.append("<span class='feedback-positive'>" + query + "</span>");
return trackProgress(success().output(output.toString()).build());
return success(this).output(output.toString()).build();
} else {
return trackProgress(failed().output(output.toString()).build());
return failed(this).output(output.toString()).build();
}
} catch (Exception e) {
return trackProgress(failed().output(this.getClass().getName() + " : " + e.getMessage()).build());
return failed(this).output(this.getClass().getName() + " : " + e.getMessage()).build();
}
}
}

View File

@ -70,18 +70,18 @@ public class SqlInjectionLesson5a extends AssignmentEndpoint {
// If they get back more than one user they succeeded
if (results.getRow() >= 6) {
return trackProgress(success().feedback("sql-injection.5a.success").output("Your query was: " + query + EXPLANATION).feedbackArgs(output.toString()).build());
return success(this).feedback("sql-injection.5a.success").output("Your query was: " + query + EXPLANATION).feedbackArgs(output.toString()).build();
} else {
return trackProgress(failed().output(output.toString() + "<br> Your query was: " + query).build());
return failed(this).output(output.toString() + "<br> Your query was: " + query).build();
}
} else {
return trackProgress(failed().feedback("sql-injection.5a.no.results").output("Your query was: " + query).build());
return failed(this).feedback("sql-injection.5a.no.results").output("Your query was: " + query).build();
}
} catch (SQLException sqle) {
return trackProgress(failed().output(sqle.getMessage() + "<br> Your query was: " + query).build());
return failed(this).output(sqle.getMessage() + "<br> Your query was: " + query).build();
}
} catch (Exception e) {
return trackProgress(failed().output(this.getClass().getName() + " : " + e.getMessage() + "<br> Your query was: " + query).build());
return failed(this).output(this.getClass().getName() + " : " + e.getMessage() + "<br> Your query was: " + query).build();
}
}

View File

@ -61,8 +61,8 @@ public class SqlInjectionLesson5b extends AssignmentEndpoint {
try {
count = Integer.parseInt(login_count);
} catch (Exception e) {
return trackProgress(failed().output("Could not parse: " + login_count + " to a number"
+ "<br> Your query was: " + queryString.replace("?", login_count)).build());
return failed(this).output("Could not parse: " + login_count + " to a number"
+ "<br> Your query was: " + queryString.replace("?", login_count)).build();
}
query.setInt(1, count);
@ -79,20 +79,20 @@ public class SqlInjectionLesson5b extends AssignmentEndpoint {
// If they get back more than one user they succeeded
if (results.getRow() >= 6) {
return trackProgress(success().feedback("sql-injection.5b.success").output("Your query was: " + queryString.replace("?", login_count)).feedbackArgs(output.toString()).build());
return success(this).feedback("sql-injection.5b.success").output("Your query was: " + queryString.replace("?", login_count)).feedbackArgs(output.toString()).build();
} else {
return trackProgress(failed().output(output.toString() + "<br> Your query was: " + queryString.replace("?", login_count)).build());
return failed(this).output(output.toString() + "<br> Your query was: " + queryString.replace("?", login_count)).build();
}
} else {
return trackProgress(failed().feedback("sql-injection.5b.no.results").output("Your query was: " + queryString.replace("?", login_count)).build());
return failed(this).feedback("sql-injection.5b.no.results").output("Your query was: " + queryString.replace("?", login_count)).build();
}
} catch (SQLException sqle) {
return trackProgress(failed().output(sqle.getMessage() + "<br> Your query was: " + queryString.replace("?", login_count)).build());
return failed(this).output(sqle.getMessage() + "<br> Your query was: " + queryString.replace("?", login_count)).build();
}
} catch (Exception e) {
return trackProgress(failed().output(this.getClass().getName() + " : " + e.getMessage() + "<br> Your query was: " + queryString.replace("?", login_count)).build());
return failed(this).output(this.getClass().getName() + " : " + e.getMessage() + "<br> Your query was: " + queryString.replace("?", login_count)).build();
}
}
}

View File

@ -71,25 +71,25 @@ public class SqlInjectionLesson8 extends AssignmentEndpoint {
if (results.getRow() > 1) {
// more than one record, the user succeeded
return trackProgress(success().feedback("sql-injection.8.success").output(output.toString()).build());
return success(this).feedback("sql-injection.8.success").output(output.toString()).build();
} else {
// only one record
return trackProgress(failed().feedback("sql-injection.8.one").output(output.toString()).build());
return failed(this).feedback("sql-injection.8.one").output(output.toString()).build();
}
} else {
// no results
return trackProgress(failed().feedback("sql-injection.8.no.results").build());
return failed(this).feedback("sql-injection.8.no.results").build();
}
} else {
return trackProgress(failed().feedback("sql-injection.error").build());
return failed(this).feedback("sql-injection.error").build();
}
} catch (SQLException e) {
return trackProgress(failed().feedback("sql-injection.error").output("<br><span class='feedback-negative'>" + e.getMessage() + "</span>").build());
return failed(this).feedback("sql-injection.error").output("<br><span class='feedback-negative'>" + e.getMessage() + "</span>").build();
}
} catch (Exception e) {
return trackProgress(failed().feedback("sql-injection.error").output("<br><span class='feedback-negative'>" + e.getMessage() + "</span>").build());
return failed(this).feedback("sql-injection.error").output("<br><span class='feedback-negative'>" + e.getMessage() + "</span>").build();
}
}

View File

@ -37,8 +37,8 @@ import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import static java.sql.ResultSet.CONCUR_READ_ONLY;
import static org.hsqldb.jdbc.JDBCResultSet.*;
import static org.hsqldb.jdbc.JDBCResultSet.CONCUR_UPDATABLE;
import static org.hsqldb.jdbc.JDBCResultSet.TYPE_SCROLL_SENSITIVE;
@RestController
@AssignmentHints(value = {"SqlStringInjectionHint.9.1", "SqlStringInjectionHint.9.2", "SqlStringInjectionHint.9.3", "SqlStringInjectionHint.9.4", "SqlStringInjectionHint.9.5"})
@ -70,19 +70,19 @@ public class SqlInjectionLesson9 extends AssignmentEndpoint {
output.append(SqlInjectionLesson8.generateTable(results));
} else {
// no results
return trackProgress(failed().feedback("sql-injection.8.no.results").build());
return failed(this).feedback("sql-injection.8.no.results").build();
}
}
} catch (SQLException e) {
System.err.println(e.getMessage());
return trackProgress(failed().feedback("sql-injection.error").output("<br><span class='feedback-negative'>" + e.getMessage() + "</span>").build());
return failed(this).feedback("sql-injection.error").output("<br><span class='feedback-negative'>" + e.getMessage() + "</span>").build();
}
return checkSalaryRanking(connection, output);
} catch (Exception e) {
System.err.println(e.getMessage());
return trackProgress(failed().feedback("sql-injection.error").output("<br><span class='feedback-negative'>" + e.getMessage() + "</span>").build());
return failed(this).feedback("sql-injection.error").output("<br><span class='feedback-negative'>" + e.getMessage() + "</span>").build();
}
}
@ -97,13 +97,13 @@ public class SqlInjectionLesson9 extends AssignmentEndpoint {
// user completes lesson if John Smith is the first in the list
if ((results.getString(2).equals("John")) && (results.getString(3).equals("Smith"))) {
output.append(SqlInjectionLesson8.generateTable(results));
return trackProgress(success().feedback("sql-injection.9.success").output(output.toString()).build());
return success(this).feedback("sql-injection.9.success").output(output.toString()).build();
} else {
return trackProgress(failed().feedback("sql-injection.9.one").output(output.toString()).build());
return failed(this).feedback("sql-injection.9.one").output(output.toString()).build();
}
}
} catch (SQLException e) {
return trackProgress(failed().feedback("sql-injection.error").output("<br><span class='feedback-negative'>" + e.getMessage() + "</span>").build());
return failed(this).feedback("sql-injection.error").output("<br><span class='feedback-negative'>" + e.getMessage() + "</span>").build();
}
}

View File

@ -48,13 +48,13 @@ public class SqlInjectionLesson10a extends AssignmentEndpoint {
if (input.toLowerCase().contains(this.results[position].toLowerCase())) {
completed = true;
} else {
return trackProgress(failed().build());
return failed(this).build();
}
position++;
}
if (completed) {
return trackProgress(success().build());
return success(this).build();
}
return trackProgress(failed().build());
return failed(this).build();
}
}

View File

@ -24,11 +24,9 @@ package org.owasp.webgoat.sql_injection.mitigation;
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.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.tools.*;
import java.io.IOException;
import java.net.URI;
@ -45,7 +43,7 @@ public class SqlInjectionLesson10b extends AssignmentEndpoint {
@ResponseBody
public AttackResult completed(@RequestParam String editor) {
try {
if (editor.isEmpty()) return trackProgress(failed().feedback("sql-injection.10b.no-code").build());
if (editor.isEmpty()) return failed(this).feedback("sql-injection.10b.no-code").build();
editor = editor.replaceAll("\\<.*?>", "");
@ -69,18 +67,18 @@ public class SqlInjectionLesson10b extends AssignmentEndpoint {
List<Diagnostic> hasCompiled = this.compileFromString(editor);
if (hasImportant && hasCompiled.size() < 1) {
return trackProgress(success().feedback("sql-injection.10b.success").build());
return success(this).feedback("sql-injection.10b.success").build();
} else if (hasCompiled.size() > 0) {
String errors = "";
for (Diagnostic d : hasCompiled) {
errors += d.getMessage(null) + "<br>";
}
return trackProgress(failed().feedback("sql-injection.10b.compiler-errors").output(errors).build());
return failed(this).feedback("sql-injection.10b.compiler-errors").output(errors).build();
} else {
return trackProgress(failed().feedback("sql-injection.10b.failed").build());
return failed(this).feedback("sql-injection.10b.failed").build();
}
} catch (Exception e) {
return trackProgress(failed().output(e.getMessage()).build());
return failed(this).output(e.getMessage()).build();
}
}

View File

@ -22,7 +22,6 @@
package org.owasp.webgoat.sql_injection.mitigation;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.owasp.webgoat.assignments.AssignmentEndpoint;
import org.owasp.webgoat.assignments.AssignmentHints;
@ -58,12 +57,12 @@ public class SqlInjectionLesson12a extends AssignmentEndpoint {
preparedStatement.setString(2, "webgoat-prd");
ResultSet resultSet = preparedStatement.executeQuery();
if (resultSet.next()) {
return trackProgress(success().build());
return success(this).build();
}
return trackProgress(failed().build());
return failed(this).build();
} catch (SQLException e) {
log.error("Failed", e);
return trackProgress(failed().build());
return (failed(this).build());
}
}
}

View File

@ -37,9 +37,4 @@ public class SqlInjectionMitigations extends Lesson {
public String getTitle() {
return "3.sql.mitigation.title";
}
@Override
public String getId() {
return "SqlInjectionMitigations";
}
}

View File

@ -157,6 +157,7 @@
<option>'Smith</option>
<option>'</option>
<option>'Smith'</option>
<option>Smith'</option>
</select></td>
<td>
<select name="operator">