fix: SQL advanced assignment 5 (#2047)
- Add and show correct hints - Fix solving the lesson immediately when you register as tom. Now uses `informationMessage` to display a message in the UI - Add Playwright test Closes: gh-2045
This commit is contained in:
parent
c37a8e8c19
commit
e9f79cc739
@ -15,17 +15,16 @@ public class SqlInjectionAdvancedIntegrationTest extends IntegrationTest {
|
|||||||
startLesson("SqlInjectionAdvanced");
|
startLesson("SqlInjectionAdvanced");
|
||||||
|
|
||||||
Map<String, Object> params = new HashMap<>();
|
Map<String, Object> params = new HashMap<>();
|
||||||
params.clear();
|
|
||||||
params.put("username_reg", "tom' AND substring(password,1,1)='t");
|
params.put("username_reg", "tom' AND substring(password,1,1)='t");
|
||||||
params.put("password_reg", "password");
|
params.put("password_reg", "password");
|
||||||
params.put("email_reg", "someone@microsoft.com");
|
params.put("email_reg", "someone@microsoft.com");
|
||||||
params.put("confirm_password", "password");
|
params.put("confirm_password", "password");
|
||||||
checkAssignmentWithPUT(webGoatUrlConfig.url("SqlInjectionAdvanced/challenge"), params, true);
|
checkAssignmentWithPUT(webGoatUrlConfig.url("SqlInjectionAdvanced/register"), params, false);
|
||||||
|
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("username_login", "tom");
|
params.put("username_login", "tom");
|
||||||
params.put("password_login", "thisisasecretfortomonly");
|
params.put("password_login", "thisisasecretfortomonly");
|
||||||
checkAssignment(webGoatUrlConfig.url("SqlInjectionAdvanced/challenge_Login"), params, true);
|
checkAssignment(webGoatUrlConfig.url("SqlInjectionAdvanced/login"), params, true);
|
||||||
|
|
||||||
params.clear();
|
params.clear();
|
||||||
params.put("userid_6a", "'; SELECT * FROM user_system_data;--");
|
params.put("userid_6a", "'; SELECT * FROM user_system_data;--");
|
||||||
@ -59,7 +58,5 @@ public class SqlInjectionAdvancedIntegrationTest extends IntegrationTest {
|
|||||||
"question_4_solution",
|
"question_4_solution",
|
||||||
"Solution 4: The database registers 'Robert' ); DROP TABLE Students;--'.");
|
"Solution 4: The database registers 'Robert' ); DROP TABLE Students;--'.");
|
||||||
checkAssignment(webGoatUrlConfig.url("SqlInjectionAdvanced/quiz"), params, true);
|
checkAssignment(webGoatUrlConfig.url("SqlInjectionAdvanced/quiz"), params, true);
|
||||||
|
|
||||||
checkResults("SqlInjectionAdvanced");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
* SPDX-FileCopyrightText: Copyright © 2025 WebGoat authors
|
* SPDX-FileCopyrightText: Copyright © 2025 WebGoat authors
|
||||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
*/
|
*/
|
||||||
package org.owasp.webgoat.playwright.webgoat;
|
package org.owasp.webgoat.playwright.webgoat.lessons;
|
||||||
|
|
||||||
import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
|
import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
|
||||||
|
|
||||||
@ -15,8 +15,9 @@ import org.junit.jupiter.api.Order;
|
|||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.TestMethodOrder;
|
import org.junit.jupiter.api.TestMethodOrder;
|
||||||
import org.owasp.webgoat.container.lessons.LessonName;
|
import org.owasp.webgoat.container.lessons.LessonName;
|
||||||
|
import org.owasp.webgoat.playwright.webgoat.PlaywrightTest;
|
||||||
import org.owasp.webgoat.playwright.webgoat.helpers.Authentication;
|
import org.owasp.webgoat.playwright.webgoat.helpers.Authentication;
|
||||||
import org.owasp.webgoat.playwright.webgoat.pages.HttpBasicsLessonPage;
|
import org.owasp.webgoat.playwright.webgoat.pages.lessons.HttpBasicsLessonPage;
|
||||||
|
|
||||||
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
|
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
|
||||||
public class HttpBasicsLessonUITest extends PlaywrightTest {
|
public class HttpBasicsLessonUITest extends PlaywrightTest {
|
@ -0,0 +1,120 @@
|
|||||||
|
/*
|
||||||
|
* SPDX-FileCopyrightText: Copyright © 2025 WebGoat authors
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
*/
|
||||||
|
package org.owasp.webgoat.playwright.webgoat.lessons;
|
||||||
|
|
||||||
|
import static com.microsoft.playwright.assertions.PlaywrightAssertions.assertThat;
|
||||||
|
|
||||||
|
import com.microsoft.playwright.Browser;
|
||||||
|
import com.microsoft.playwright.Page;
|
||||||
|
import com.microsoft.playwright.Page.GetByRoleOptions;
|
||||||
|
import com.microsoft.playwright.options.AriaRole;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.DisplayName;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.owasp.webgoat.container.lessons.LessonName;
|
||||||
|
import org.owasp.webgoat.playwright.webgoat.PlaywrightTest;
|
||||||
|
import org.owasp.webgoat.playwright.webgoat.helpers.Authentication;
|
||||||
|
import org.owasp.webgoat.playwright.webgoat.pages.lessons.LessonPage;
|
||||||
|
|
||||||
|
public class SqlInjectionAdvancedUITest extends PlaywrightTest {
|
||||||
|
|
||||||
|
private LessonPage lessonPage;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void navigateToLesson(Browser browser) {
|
||||||
|
var lessonName = new LessonName("SqlInjectionAdvanced");
|
||||||
|
var page = Authentication.sylvester(browser);
|
||||||
|
|
||||||
|
this.lessonPage = new LessonPage(page);
|
||||||
|
lessonPage.resetLesson(lessonName);
|
||||||
|
lessonPage.open(lessonName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Login as Tom with incorrect password")
|
||||||
|
void loginAsTomWithIncorrectPassword() {
|
||||||
|
lessonPage.navigateTo(5);
|
||||||
|
var page = lessonPage.getPage();
|
||||||
|
page.getByRole(AriaRole.LINK, new GetByRoleOptions().setName("Login")).click();
|
||||||
|
page.locator("[name='username_login']").fill("tom");
|
||||||
|
page.locator("[name='password_login']").fill("test");
|
||||||
|
page.getByRole(AriaRole.BUTTON, new GetByRoleOptions().setName("Log In")).click();
|
||||||
|
|
||||||
|
assertThat(lessonPage.getAssignmentOutput())
|
||||||
|
.containsText("Wrong username or password. Try again.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Login as Tom with correct password")
|
||||||
|
void loginAsTomWithCorrectPassword() {
|
||||||
|
lessonPage.navigateTo(5);
|
||||||
|
var page = lessonPage.getPage();
|
||||||
|
page.getByRole(AriaRole.LINK, new GetByRoleOptions().setName("Login")).click();
|
||||||
|
page.locator("[name='username_login']").fill("tom");
|
||||||
|
page.locator("[name='password_login']").fill("thisisasecretfortomonly");
|
||||||
|
page.getByRole(AriaRole.BUTTON, new GetByRoleOptions().setName("Log In")).click();
|
||||||
|
|
||||||
|
lessonPage.isAssignmentSolved(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Register as Tom should show error that Tom already exists")
|
||||||
|
void registerAsTomShouldDisplayError() {
|
||||||
|
lessonPage.navigateTo(5);
|
||||||
|
var page = lessonPage.getPage();
|
||||||
|
page.getByRole(AriaRole.LINK, new GetByRoleOptions().setName("Register")).click();
|
||||||
|
page.locator("[name='username_reg']").fill("tom");
|
||||||
|
page.locator("[name='email_reg']").fill("tom@tom.org");
|
||||||
|
page.locator("[name='password_reg']").fill("test");
|
||||||
|
page.locator("[name='confirm_password_reg']").fill("test");
|
||||||
|
page.getByRole(AriaRole.BUTTON, new GetByRoleOptions().setName("Register Now")).click();
|
||||||
|
|
||||||
|
assertThat(lessonPage.getAssignmentOutput()).containsText("User tom already exists");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName(
|
||||||
|
"Using SQL Injection to register as Tom to guess the password and the guess is correct")
|
||||||
|
void startGuessingCorrect() {
|
||||||
|
lessonPage.navigateTo(5);
|
||||||
|
var page = lessonPage.getPage();
|
||||||
|
page.getByRole(AriaRole.LINK, new GetByRoleOptions().setName("Register")).click();
|
||||||
|
page.locator("[name='username_reg']").fill("tom' AND substring(password,1,1)='t");
|
||||||
|
page.locator("[name='email_reg']").fill("tom@tom.org");
|
||||||
|
page.locator("[name='password_reg']").fill("test");
|
||||||
|
page.locator("[name='confirm_password_reg']").fill("test");
|
||||||
|
page.getByRole(AriaRole.BUTTON, new GetByRoleOptions().setName("Register Now")).click();
|
||||||
|
|
||||||
|
assertThat(lessonPage.getAssignmentOutput())
|
||||||
|
.containsText("User tom' AND substring(password,1,1)='t already exists");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName(
|
||||||
|
"Using SQL Injection to register as Tom to guess the password and the guess is incorrect")
|
||||||
|
void startGuessingIncorrect() {
|
||||||
|
lessonPage.navigateTo(5);
|
||||||
|
var page = lessonPage.getPage();
|
||||||
|
page.getByRole(AriaRole.LINK, new GetByRoleOptions().setName("Register")).click();
|
||||||
|
page.locator("[name='username_reg']").fill("tom' AND substring(password,1,1)='a");
|
||||||
|
page.locator("[name='email_reg']").fill("tom@tom.org");
|
||||||
|
page.locator("[name='password_reg']").fill("test");
|
||||||
|
page.locator("[name='confirm_password_reg']").fill("test");
|
||||||
|
page.getByRole(AriaRole.BUTTON, new GetByRoleOptions().setName("Register Now")).click();
|
||||||
|
|
||||||
|
assertThat(lessonPage.getAssignmentOutput())
|
||||||
|
.containsText(
|
||||||
|
"User tom' AND substring(password,1,1)='a created, please proceed to the login page.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Should display correct hints")
|
||||||
|
void shouldDisplayCorrectHints() {
|
||||||
|
lessonPage.navigateTo(5);
|
||||||
|
var page = lessonPage.getPage();
|
||||||
|
page.getByRole(AriaRole.BUTTON, new Page.GetByRoleOptions().setName("Show hints")).click();
|
||||||
|
assertThat(lessonPage.getAssignmentOutput()).containsText("Look at the different");
|
||||||
|
}
|
||||||
|
}
|
@ -2,7 +2,7 @@
|
|||||||
* SPDX-FileCopyrightText: Copyright © 2025 WebGoat authors
|
* SPDX-FileCopyrightText: Copyright © 2025 WebGoat authors
|
||||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
*/
|
*/
|
||||||
package org.owasp.webgoat.playwright.webgoat.pages;
|
package org.owasp.webgoat.playwright.webgoat.pages.lessons;
|
||||||
|
|
||||||
import com.microsoft.playwright.Locator;
|
import com.microsoft.playwright.Locator;
|
||||||
import com.microsoft.playwright.Page;
|
import com.microsoft.playwright.Page;
|
@ -2,7 +2,7 @@
|
|||||||
* SPDX-FileCopyrightText: Copyright © 2025 WebGoat authors
|
* SPDX-FileCopyrightText: Copyright © 2025 WebGoat authors
|
||||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
*/
|
*/
|
||||||
package org.owasp.webgoat.playwright.webgoat.pages;
|
package org.owasp.webgoat.playwright.webgoat.pages.lessons;
|
||||||
|
|
||||||
import static org.owasp.webgoat.playwright.webgoat.PlaywrightTest.webGoatUrl;
|
import static org.owasp.webgoat.playwright.webgoat.PlaywrightTest.webGoatUrl;
|
||||||
|
|
||||||
@ -14,7 +14,7 @@ import org.assertj.core.api.Assertions;
|
|||||||
import org.owasp.webgoat.container.lessons.LessonName;
|
import org.owasp.webgoat.container.lessons.LessonName;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
class LessonPage {
|
public class LessonPage {
|
||||||
|
|
||||||
private final Page page;
|
private final Page page;
|
||||||
|
|
||||||
@ -65,4 +65,8 @@ class LessonPage {
|
|||||||
public Locator getAssignmentOutput() {
|
public Locator getAssignmentOutput() {
|
||||||
return page.locator("#lesson-content-wrapper");
|
return page.locator("#lesson-content-wrapper");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Locator getHintsOutput() {
|
||||||
|
return page.locator("#lesson-hint");
|
||||||
|
}
|
||||||
}
|
}
|
@ -4,11 +4,9 @@
|
|||||||
*/
|
*/
|
||||||
package org.owasp.webgoat.container.assignments;
|
package org.owasp.webgoat.container.assignments;
|
||||||
|
|
||||||
import org.owasp.webgoat.container.i18n.PluginMessages;
|
|
||||||
|
|
||||||
public class AttackResultBuilder {
|
public class AttackResultBuilder {
|
||||||
|
|
||||||
private boolean lessonCompleted;
|
private boolean assignmentCompleted;
|
||||||
private Object[] feedbackArgs;
|
private Object[] feedbackArgs;
|
||||||
private String feedbackResourceBundleKey;
|
private String feedbackResourceBundleKey;
|
||||||
private String output;
|
private String output;
|
||||||
@ -16,15 +14,8 @@ public class AttackResultBuilder {
|
|||||||
private AssignmentEndpoint assignment;
|
private AssignmentEndpoint assignment;
|
||||||
private boolean attemptWasMade = false;
|
private boolean attemptWasMade = false;
|
||||||
|
|
||||||
public AttackResultBuilder lessonCompleted(boolean lessonCompleted) {
|
public AttackResultBuilder assignmentCompleted(boolean lessonCompleted) {
|
||||||
this.lessonCompleted = lessonCompleted;
|
this.assignmentCompleted = lessonCompleted;
|
||||||
this.feedbackResourceBundleKey = "lesson.completed";
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public AttackResultBuilder lessonCompleted(boolean lessonCompleted, String resourceBundleKey) {
|
|
||||||
this.lessonCompleted = lessonCompleted;
|
|
||||||
this.feedbackResourceBundleKey = resourceBundleKey;
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,7 +46,7 @@ public class AttackResultBuilder {
|
|||||||
|
|
||||||
public AttackResult build() {
|
public AttackResult build() {
|
||||||
return new AttackResult(
|
return new AttackResult(
|
||||||
lessonCompleted,
|
assignmentCompleted,
|
||||||
feedbackResourceBundleKey,
|
feedbackResourceBundleKey,
|
||||||
feedbackArgs,
|
feedbackArgs,
|
||||||
output,
|
output,
|
||||||
@ -81,7 +72,7 @@ public class AttackResultBuilder {
|
|||||||
*/
|
*/
|
||||||
public static AttackResultBuilder success(AssignmentEndpoint assignment) {
|
public static AttackResultBuilder success(AssignmentEndpoint assignment) {
|
||||||
return new AttackResultBuilder()
|
return new AttackResultBuilder()
|
||||||
.lessonCompleted(true)
|
.assignmentCompleted(true)
|
||||||
.attemptWasMade()
|
.attemptWasMade()
|
||||||
.feedback("assignment.solved")
|
.feedback("assignment.solved")
|
||||||
.assignment(assignment);
|
.assignment(assignment);
|
||||||
@ -99,13 +90,13 @@ public class AttackResultBuilder {
|
|||||||
*/
|
*/
|
||||||
public static AttackResultBuilder failed(AssignmentEndpoint assignment) {
|
public static AttackResultBuilder failed(AssignmentEndpoint assignment) {
|
||||||
return new AttackResultBuilder()
|
return new AttackResultBuilder()
|
||||||
.lessonCompleted(false)
|
.assignmentCompleted(false)
|
||||||
.attemptWasMade()
|
.attemptWasMade()
|
||||||
.feedback("assignment.not.solved")
|
.feedback("assignment.not.solved")
|
||||||
.assignment(assignment);
|
.assignment(assignment);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AttackResultBuilder informationMessage(AssignmentEndpoint assignment) {
|
public static AttackResultBuilder informationMessage(AssignmentEndpoint assignment) {
|
||||||
return new AttackResultBuilder().lessonCompleted(false).assignment(assignment);
|
return new AttackResultBuilder().assignmentCompleted(false).assignment(assignment);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -84,7 +84,7 @@ public class CourseConfiguration {
|
|||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public Course course() {
|
public Course course() {
|
||||||
assignments.stream().forEach(this::attachToLesson);
|
assignments.forEach(this::attachToLesson);
|
||||||
|
|
||||||
// Check if all assignments are attached to a lesson
|
// Check if all assignments are attached to a lesson
|
||||||
var assignmentsAttachedToLessons =
|
var assignmentsAttachedToLessons =
|
||||||
@ -99,7 +99,7 @@ public class CourseConfiguration {
|
|||||||
|
|
||||||
private List<String> findDiff() {
|
private List<String> findDiff() {
|
||||||
var matchedToLessons =
|
var matchedToLessons =
|
||||||
lessons.stream().flatMap(l -> l.getAssignments().stream()).map(a -> a.getName()).toList();
|
lessons.stream().flatMap(l -> l.getAssignments().stream()).map(Assignment::getName).toList();
|
||||||
var allAssignments = assignments.stream().map(a -> a.getClass().getSimpleName()).toList();
|
var allAssignments = assignments.stream().map(a -> a.getClass().getSimpleName()).toList();
|
||||||
|
|
||||||
var diff = new ArrayList<>(allAssignments);
|
var diff = new ArrayList<>(allAssignments);
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
package org.owasp.webgoat.lessons.sqlinjection.advanced;
|
package org.owasp.webgoat.lessons.sqlinjection.advanced;
|
||||||
|
|
||||||
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
|
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.failed;
|
||||||
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.success;
|
import static org.owasp.webgoat.container.assignments.AttackResultBuilder.informationMessage;
|
||||||
|
|
||||||
import java.sql.*;
|
import java.sql.*;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@ -19,13 +19,17 @@ import org.springframework.web.bind.annotation.RequestParam;
|
|||||||
import org.springframework.web.bind.annotation.ResponseBody;
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
/**
|
|
||||||
* @author nbaars
|
|
||||||
* @since 4/8/17.
|
|
||||||
*/
|
|
||||||
@RestController
|
@RestController
|
||||||
@AssignmentHints(
|
@AssignmentHints(
|
||||||
value = {"SqlInjectionChallenge1", "SqlInjectionChallenge2", "SqlInjectionChallenge3"})
|
value = {
|
||||||
|
"SqlInjectionChallenge1",
|
||||||
|
"SqlInjectionChallenge2",
|
||||||
|
"SqlInjectionChallenge3",
|
||||||
|
"SqlInjectionChallenge4",
|
||||||
|
"SqlInjectionChallenge5",
|
||||||
|
"SqlInjectionChallenge6",
|
||||||
|
"SqlInjectionChallenge7"
|
||||||
|
})
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class SqlInjectionChallenge implements AssignmentEndpoint {
|
public class SqlInjectionChallenge implements AssignmentEndpoint {
|
||||||
|
|
||||||
@ -35,38 +39,34 @@ public class SqlInjectionChallenge implements AssignmentEndpoint {
|
|||||||
this.dataSource = dataSource;
|
this.dataSource = dataSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
@PutMapping("/SqlInjectionAdvanced/challenge")
|
@PutMapping("/SqlInjectionAdvanced/register")
|
||||||
// assignment path is bounded to class so we use different http method :-)
|
// assignment path is bounded to class so we use different http method :-)
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
public AttackResult registerNewUser(
|
public AttackResult registerNewUser(
|
||||||
@RequestParam String username_reg,
|
@RequestParam("username_reg") String username,
|
||||||
@RequestParam String email_reg,
|
@RequestParam("email_reg") String email,
|
||||||
@RequestParam String password_reg)
|
@RequestParam("password_reg") String password) {
|
||||||
throws Exception {
|
AttackResult attackResult = checkArguments(username, email, password);
|
||||||
AttackResult attackResult = checkArguments(username_reg, email_reg, password_reg);
|
|
||||||
|
|
||||||
if (attackResult == null) {
|
if (attackResult == null) {
|
||||||
|
|
||||||
try (Connection connection = dataSource.getConnection()) {
|
try (Connection connection = dataSource.getConnection()) {
|
||||||
String checkUserQuery =
|
String checkUserQuery =
|
||||||
"select userid from sql_challenge_users where userid = '" + username_reg + "'";
|
"select userid from sql_challenge_users where userid = '" + username + "'";
|
||||||
Statement statement = connection.createStatement();
|
Statement statement = connection.createStatement();
|
||||||
ResultSet resultSet = statement.executeQuery(checkUserQuery);
|
ResultSet resultSet = statement.executeQuery(checkUserQuery);
|
||||||
|
|
||||||
if (resultSet.next()) {
|
if (resultSet.next()) {
|
||||||
if (username_reg.contains("tom'")) {
|
attackResult = failed(this).feedback("user.exists").feedbackArgs(username).build();
|
||||||
attackResult = success(this).feedback("user.exists").build();
|
|
||||||
} else {
|
|
||||||
attackResult = failed(this).feedback("user.exists").feedbackArgs(username_reg).build();
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
PreparedStatement preparedStatement =
|
PreparedStatement preparedStatement =
|
||||||
connection.prepareStatement("INSERT INTO sql_challenge_users VALUES (?, ?, ?)");
|
connection.prepareStatement("INSERT INTO sql_challenge_users VALUES (?, ?, ?)");
|
||||||
preparedStatement.setString(1, username_reg);
|
preparedStatement.setString(1, username);
|
||||||
preparedStatement.setString(2, email_reg);
|
preparedStatement.setString(2, email);
|
||||||
preparedStatement.setString(3, password_reg);
|
preparedStatement.setString(3, password);
|
||||||
preparedStatement.execute();
|
preparedStatement.execute();
|
||||||
attackResult = success(this).feedback("user.created").feedbackArgs(username_reg).build();
|
attackResult =
|
||||||
|
informationMessage(this).feedback("user.created").feedbackArgs(username).build();
|
||||||
}
|
}
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
attackResult = failed(this).output("Something went wrong").build();
|
attackResult = failed(this).output("Something went wrong").build();
|
||||||
@ -75,13 +75,13 @@ public class SqlInjectionChallenge implements AssignmentEndpoint {
|
|||||||
return attackResult;
|
return attackResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
private AttackResult checkArguments(String username_reg, String email_reg, String password_reg) {
|
private AttackResult checkArguments(String username, String email, String password) {
|
||||||
if (StringUtils.isEmpty(username_reg)
|
if (StringUtils.isEmpty(username)
|
||||||
|| StringUtils.isEmpty(email_reg)
|
|| StringUtils.isEmpty(email)
|
||||||
|| StringUtils.isEmpty(password_reg)) {
|
|| StringUtils.isEmpty(password)) {
|
||||||
return failed(this).feedback("input.invalid").build();
|
return failed(this).feedback("input.invalid").build();
|
||||||
}
|
}
|
||||||
if (username_reg.length() > 250 || email_reg.length() > 30 || password_reg.length() > 30) {
|
if (username.length() > 250 || email.length() > 30 || password.length() > 30) {
|
||||||
return failed(this).feedback("input.invalid").build();
|
return failed(this).feedback("input.invalid").build();
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
@ -9,7 +9,6 @@ import static org.owasp.webgoat.container.assignments.AttackResultBuilder.succes
|
|||||||
|
|
||||||
import org.owasp.webgoat.container.LessonDataSource;
|
import org.owasp.webgoat.container.LessonDataSource;
|
||||||
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
import org.owasp.webgoat.container.assignments.AssignmentEndpoint;
|
||||||
import org.owasp.webgoat.container.assignments.AssignmentHints;
|
|
||||||
import org.owasp.webgoat.container.assignments.AttackResult;
|
import org.owasp.webgoat.container.assignments.AttackResult;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
@ -17,13 +16,6 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
|||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@AssignmentHints(
|
|
||||||
value = {
|
|
||||||
"SqlInjectionChallengeHint1",
|
|
||||||
"SqlInjectionChallengeHint2",
|
|
||||||
"SqlInjectionChallengeHint3",
|
|
||||||
"SqlInjectionChallengeHint4"
|
|
||||||
})
|
|
||||||
public class SqlInjectionChallengeLogin implements AssignmentEndpoint {
|
public class SqlInjectionChallengeLogin implements AssignmentEndpoint {
|
||||||
private final LessonDataSource dataSource;
|
private final LessonDataSource dataSource;
|
||||||
|
|
||||||
@ -31,20 +23,22 @@ public class SqlInjectionChallengeLogin implements AssignmentEndpoint {
|
|||||||
this.dataSource = dataSource;
|
this.dataSource = dataSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/SqlInjectionAdvanced/challenge_Login")
|
@PostMapping("/SqlInjectionAdvanced/login")
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
public AttackResult login(
|
public AttackResult login(
|
||||||
@RequestParam String username_login, @RequestParam String password_login) throws Exception {
|
@RequestParam("username_login") String username,
|
||||||
|
@RequestParam("password_login") String password)
|
||||||
|
throws Exception {
|
||||||
try (var connection = dataSource.getConnection()) {
|
try (var connection = dataSource.getConnection()) {
|
||||||
var statement =
|
var statement =
|
||||||
connection.prepareStatement(
|
connection.prepareStatement(
|
||||||
"select password from sql_challenge_users where userid = ? and password = ?");
|
"select password from sql_challenge_users where userid = ? and password = ?");
|
||||||
statement.setString(1, username_login);
|
statement.setString(1, username);
|
||||||
statement.setString(2, password_login);
|
statement.setString(2, password);
|
||||||
var resultSet = statement.executeQuery();
|
var resultSet = statement.executeQuery();
|
||||||
|
|
||||||
if (resultSet.next()) {
|
if (resultSet.next()) {
|
||||||
return ("tom".equals(username_login))
|
return ("tom".equals(username))
|
||||||
? success(this).build()
|
? success(this).build()
|
||||||
: failed(this).feedback("ResultsButNotTom").build();
|
: failed(this).feedback("ResultsButNotTom").build();
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
lesson.completed=Congratulations. You have successfully completed this lesson.
|
|
||||||
assignment.solved=Congratulations. You have successfully completed the assignment.
|
assignment.solved=Congratulations. You have successfully completed the assignment.
|
||||||
assignment.not.solved=Sorry the solution is not correct, please try again.
|
assignment.not.solved=Sorry the solution is not correct, please try again.
|
||||||
RestartLesson=Restart this Lesson
|
RestartLesson=Restart this Lesson
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
#General
|
#General
|
||||||
lesson.completed=Herzlichen Gl\u00fcckwunsch! Sie haben diese Lektion erfolgreich abgeschlossen.
|
|
||||||
assignment.solved=Herzlichen Gl\u00fcckwunsch! Sie haben diesen Auftrag erfolgreich abgeschlossen.
|
assignment.solved=Herzlichen Gl\u00fcckwunsch! Sie haben diesen Auftrag erfolgreich abgeschlossen.
|
||||||
assignment.not.solved=Die L\u00f6sung ist nicht korrekt, versuchen Sie es erneut.
|
assignment.not.solved=Die L\u00f6sung ist nicht korrekt, versuchen Sie es erneut.
|
||||||
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
#General
|
#General
|
||||||
lesson.completed=F\u00e9licitations. Vous avez termin\u00e9 cette le\u00e7on avec succ\u00e9s.
|
|
||||||
RestartLesson=Recommencer cette le\u00e7on
|
RestartLesson=Recommencer cette le\u00e7on
|
||||||
SolutionVideos=Solution vid\u00e9os
|
SolutionVideos=Solution vid\u00e9os
|
||||||
ErrorGenerating=Error generating
|
ErrorGenerating=Error generating
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
lesson.completed=Gefeliciteerd, je hebt deze les succesvol afgerond.
|
|
||||||
assignment.solved=Gefeliciteerd, je hebt deze opdracht succesvol afgerond.
|
assignment.solved=Gefeliciteerd, je hebt deze opdracht succesvol afgerond.
|
||||||
assignment.not.solved=Sorry de oplossing is niet correct, probeer het nog eens.
|
assignment.not.solved=Sorry de oplossing is niet correct, probeer het nog eens.
|
||||||
RestartLesson=Herstart de les
|
RestartLesson=Herstart de les
|
||||||
|
@ -10,7 +10,7 @@ challenge9.title=Changing password
|
|||||||
challenge.solved=Congratulations, you solved the challenge. Here is your flag: {0}
|
challenge.solved=Congratulations, you solved the challenge. Here is your flag: {0}
|
||||||
challenge.close=This is not the correct password for Larry, please try again.
|
challenge.close=This is not the correct password for Larry, please try again.
|
||||||
|
|
||||||
email.send=An e-mail has been send to {0}
|
email.send=An e-mail has been sent to {0}
|
||||||
|
|
||||||
user.exists=User {0} already exists please try to register with a different username.
|
user.exists=User {0} already exists please try to register with a different username.
|
||||||
user.created=User {0} created, please proceed to the login page.
|
user.created=User {0} created, please proceed to the login page.
|
||||||
|
@ -1,2 +0,0 @@
|
|||||||
EnterYourName=\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u0432\u0430\u0448\u0435 \u0438\u043c\u044f
|
|
||||||
Go!=\u0412\u043f\u0435\u0440\u0451\u0434!
|
|
@ -79,7 +79,7 @@
|
|||||||
<div class="col-lg-12">
|
<div class="col-lg-12">
|
||||||
<form id="login-form" class="attack-form" accept-charset="UNKNOWN"
|
<form id="login-form" class="attack-form" accept-charset="UNKNOWN"
|
||||||
method="POST" name="form"
|
method="POST" name="form"
|
||||||
th:action="@{/SqlInjectionAdvanced/Challenge_Login}"
|
th:action="@{/SqlInjectionAdvanced/login}"
|
||||||
role="form">
|
role="form">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<input type="text" name="username_login" id="username4" tabindex="1"
|
<input type="text" name="username_login" id="username4" tabindex="1"
|
||||||
@ -115,7 +115,7 @@
|
|||||||
</form>
|
</form>
|
||||||
<form id="register-form" class="attack-form" accept-charset="UNKNOWN"
|
<form id="register-form" class="attack-form" accept-charset="UNKNOWN"
|
||||||
method="PUT" name="form"
|
method="PUT" name="form"
|
||||||
th:action="@{/SqlInjectionAdvanced/challenge}"
|
th:action="@{/SqlInjectionAdvanced/register}"
|
||||||
style="display: none;" role="form">
|
style="display: none;" role="form">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<input type="text" name="username_reg" id="username" tabindex="1"
|
<input type="text" name="username_reg" id="username" tabindex="1"
|
||||||
|
@ -3,12 +3,8 @@
|
|||||||
2.sql.advanced.title=SQL Injection (advanced)
|
2.sql.advanced.title=SQL Injection (advanced)
|
||||||
3.sql.mitigation.title=SQL Injection (mitigation)
|
3.sql.mitigation.title=SQL Injection (mitigation)
|
||||||
|
|
||||||
|
NoResultsMatched=Wrong username or password. Try again.
|
||||||
SqlInjectionChallenge1=Look at the different response you receive from the server
|
ResultsButNotTom=Try to log in as Tom!
|
||||||
SqlInjectionChallenge2=The vulnerability is on the register form
|
|
||||||
SqlInjectionChallenge3=Use tooling to automate this attack
|
|
||||||
NoResultsMatched=No results matched, try again.
|
|
||||||
ResultsButNotTom=Try To login as Tom!
|
|
||||||
|
|
||||||
sql-injection.2.success=You have succeeded!
|
sql-injection.2.success=You have succeeded!
|
||||||
sql-injection.2.failed=Something went wrong! You got no results, check your SQL Statement and the table above.
|
sql-injection.2.failed=Something went wrong! You got no results, check your SQL Statement and the table above.
|
||||||
@ -100,10 +96,13 @@ SqlStringInjectionHint-mitigation-13-2=Intercept the request and try to specify
|
|||||||
SqlStringInjectionHint-mitigation-13-3=Use for example "(case when (true) then hostname else id end)" in the order by and see what happens
|
SqlStringInjectionHint-mitigation-13-3=Use for example "(case when (true) then hostname else id end)" in the order by and see what happens
|
||||||
SqlStringInjectionHint-mitigation-13-4=Use for example "(case when (true) then hostname else id end)" in the order by and see what happens
|
SqlStringInjectionHint-mitigation-13-4=Use for example "(case when (true) then hostname else id end)" in the order by and see what happens
|
||||||
|
|
||||||
SqlInjectionChallengeHint1=The table name is randomized at each start of WebGoat, try to figure out the name first.
|
SqlInjectionChallenge1=Look at the different response you receive from the server when you try different entries
|
||||||
SqlInjectionChallengeHint2=Find the field which is vulnerable to SQL injection use that to change the password.
|
SqlInjectionChallenge2=Does the register form give you any indication a user already exists?
|
||||||
SqlInjectionChallengeHint3=Change the password through an UPDATE Statement.
|
SqlInjectionChallenge3=Try to guess the password of the user 'tom' one character at a time
|
||||||
SqlInjectionChallengeHint4=The vulnerable field is the username field of the register form.
|
SqlInjectionChallenge4=Use substring(column, start, length) to get the password of the user 'tom' one character at a time
|
||||||
|
SqlInjectionChallenge5=Use tom' AND substring(password,1,1)='a for the guess of the first character of the password
|
||||||
|
SqlInjectionChallenge6=It is important to look at the different responses you receive from the server when you try different entries
|
||||||
|
SqlInjectionChallenge7=You can use tooling to automate this attack
|
||||||
|
|
||||||
SqlOnlyInputValidation-failed=Using spaces is not allowed!
|
SqlOnlyInputValidation-failed=Using spaces is not allowed!
|
||||||
SqlOnlyInputValidation-1=Spaces are rejected, try to find a way around this restriction
|
SqlOnlyInputValidation-1=Spaces are rejected, try to find a way around this restriction
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#StringSqlInjection.java
|
#StringSqlInjection.java
|
||||||
StringSqlInjectionSecondStage=Da sie nun erfolgreich eine SQL Injection durchgef\u00fchrt haben, versuchen Sie denselben Typ von Angriff auf eine parametrisierte Anfrage. Starten Sie Diese Lektion neu, wenn Sie zur verwundbaren SQL Anfrage gelangen m\u00f6chten.
|
StringSqlInjectionSecondStage=Da sie nun erfolgreich eine SQL Injection durchgef\u00fchrt haben, versuchen Sie denselben Typ von Angriff auf eine parametrisierte Anfrage. Starten Sie Diese Lektion neu, wenn Sie zur verwundbaren SQL Anfrage gelangen m\u00f6chten.
|
||||||
EnterLastName=Geben Sie Ihren Nachnamen ein:
|
EnterLastName=Geben Sie Ihren Nachnamen ein:
|
||||||
NoResultsMatched=Keine Resultate gefunden, versuchen Sie es erneut
|
NoResultsMatched=Falscher Benutzername oder falsches Passwort. Versuchen Sie es erneut.
|
||||||
SqlStringInjectionHint1=The application is taking your input and inserting it at the end of a pre-formed SQL command.
|
SqlStringInjectionHint1=The application is taking your input and inserting it at the end of a pre-formed SQL command.
|
||||||
SqlStringInjectionHint2=This is the code for the query being built and issued by WebGoat:<br><br> "SELECT * FROM user_data WHERE last_name = "accountName"
|
SqlStringInjectionHint2=This is the code for the query being built and issued by WebGoat:<br><br> "SELECT * FROM user_data WHERE last_name = "accountName"
|
||||||
SqlStringInjectionHint3=Compound SQL statements can be made by joining multiple tests with keywords like AND and OR. Try appending a SQL statement that always resolves to true
|
SqlStringInjectionHint3=Compound SQL statements can be made by joining multiple tests with keywords like AND and OR. Try appending a SQL statement that always resolves to true
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#StringSqlInjection.java
|
#StringSqlInjection.java
|
||||||
StringSqlInjectionSecondStage=Maintenant que vous avez r\u00e9alis\u00e9 une injection SQL avec succ\u00e8s, essayer le m\u00eame type d'attaque sur une requ\u00eate param\u00e9tr\u00e9e. Red\u00e9marrez la le\u00e7on si vous souhaitez revenir \u00e0 la requ\u00eate injectable.
|
StringSqlInjectionSecondStage=Maintenant que vous avez r\u00e9alis\u00e9 une injection SQL avec succ\u00e8s, essayer le m\u00eame type d'attaque sur une requ\u00eate param\u00e9tr\u00e9e. Red\u00e9marrez la le\u00e7on si vous souhaitez revenir \u00e0 la requ\u00eate injectable.
|
||||||
EnterLastName=Entrez votre nom :
|
EnterLastName=Entrez votre nom :
|
||||||
NoResultsMatched=Aucun r\u00e9sultat correspondant. Essayez encore.
|
NoResultsMatched=Aucun nom d'utilisateur ou mot de passe incorrect. Essayez encore.
|
||||||
SqlStringInjectionHint1=L'application r\u00e9cup\u00e8re votre saisie et l'ins\u00e8re \u00e0 la fin d'une commande SQL pr\u00e9-form\u00e9e.
|
SqlStringInjectionHint1=L'application r\u00e9cup\u00e8re votre saisie et l'ins\u00e8re \u00e0 la fin d'une commande SQL pr\u00e9-form\u00e9e.
|
||||||
SqlStringInjectionHint2=Voici le code de la requ\u00eate assembl\u00e9e et ex\u00e9cut\u00e9e par WebGoat :<br><br> "SELECT * FROM user_data WHERE last_name = "accountName"
|
SqlStringInjectionHint2=Voici le code de la requ\u00eate assembl\u00e9e et ex\u00e9cut\u00e9e par WebGoat :<br><br> "SELECT * FROM user_data WHERE last_name = "accountName"
|
||||||
SqlStringInjectionHint3=Les commandes SQL compos\u00e9es peuvent \u00eatre assembl\u00e9es en associant de multiples conditions au moyen de mots-cl\u00e9 tels que AND et OR. Essayez d'assembler une condition qui sera toujours r\u00e9solue \u00e0 vrai.
|
SqlStringInjectionHint3=Les commandes SQL compos\u00e9es peuvent \u00eatre assembl\u00e9es en associant de multiples conditions au moyen de mots-cl\u00e9 tels que AND et OR. Essayez d'assembler une condition qui sera toujours r\u00e9solue \u00e0 vrai.
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
#StringSqlInjection.java
|
|
||||||
StringSqlInjectionSecondStage=\u0422\u0435\u043f\u0435\u0440\u044c, \u043a\u043e\u0433\u0434\u0430 \u0432\u0430\u043c \u0443\u0434\u0430\u043b\u043e\u0441\u044c \u0443\u0434\u0430\u0447\u043d\u043e \u043f\u0440\u043e\u044d\u043a\u0441\u043f\u043b\u0443\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c SQL-\u0438\u043d\u044a\u0435\u043a\u0446\u0438\u044e, \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u043e\u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0438\u0442\u044c \u044d\u0442\u043e \u0441 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u043c \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u043c. \u041d\u0430\u0447\u043d\u0438\u0442\u0435 \u0443\u0440\u043e\u043a \u0437\u0430\u043d\u043e\u0432\u043e \u0435\u0441\u043b\u0438 \u0432\u044b \u0445\u043e\u0442\u0438\u0442\u0435 \u0432\u043d\u043e\u0432\u044c \u0443\u0432\u0438\u0434\u0435\u0442\u044c \u0443\u044f\u0437\u0432\u0438\u043c\u043e\u0435 \u043f\u043e\u043b\u0435.
|
|
||||||
EnterLastName=\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u0432\u0430\u0448\u0443 \u0444\u0430\u043c\u0438\u043b\u0438\u044e:
|
|
||||||
NoResultsMatched=\u041d\u0435\u0442 \u0441\u043e\u0432\u043f\u0430\u0434\u0435\u043d\u0438\u0439. \u041f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u0441\u043d\u043e\u0432\u0430.
|
|
||||||
SqlStringInjectionHint1=\u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0431\u0435\u0440\u0451\u0442 \u0442\u043e \u0447\u0442\u043e \u0432\u044b \u0432\u0432\u043e\u0434\u0438\u0442\u0435 \u0438 \u0432\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0432 \u043a\u043e\u043d\u0435\u0446 \u0437\u0430\u0440\u0430\u043d\u0435\u0435 \u0441\u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e SQL-\u0437\u0430\u043f\u0440\u043e\u0441\u0430.
|
|
||||||
SqlStringInjectionHint2=\u0412\u043e\u0442 \u043a\u043e\u0434 \u0437\u0430\u043f\u0440\u043e\u0441\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0438 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442\u0441\u044f WebGoat`\u043e\u043c:<br><br> "SELECT * FROM user_data WHERE last_name = "accountName"
|
|
||||||
SqlStringInjectionHint3=\u0426\u0435\u043b\u043e\u0441\u0442\u043d\u043e\u0441\u0442\u044c SQL-\u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043c\u043e\u0436\u043d\u043e \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0438\u0442\u044c \u043f\u0440\u043e\u0432\u0435\u0434\u044f \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043f\u0440\u043e\u0432\u0435\u0440\u043e\u043a \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0442\u0430\u043a\u0438\u0445 \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u0445 \u0441\u043b\u043e\u0432 \u043a\u0430\u043a AND \u0438 OR. \u041f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u0441\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0442\u0430\u043a\u043e\u0435 SQL-\u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0435, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0432\u0441\u0435\u0433\u0434\u0430 \u0431\u0443\u0434\u0435\u0442 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0442\u044c \u0438\u0441\u0442\u0438\u043d\u0443.
|
|
||||||
SqlStringInjectionHint4=\u041f\u043e\u043f\u0440\u043e\u0431\u0443\u0439\u0442\u0435 \u0432\u0432\u0435\u0441\u0442\u0438 [ smith' OR '1' = '1 ].
|
|
Loading…
x
Reference in New Issue
Block a user