diff --git a/webgoat-integration-tests/src/test/java/org/owasp/webgoat/SqlInjectionLessonTest.java b/webgoat-integration-tests/src/test/java/org/owasp/webgoat/SqlInjectionLessonTest.java
index 680f80042..f5e3b6101 100644
--- a/webgoat-integration-tests/src/test/java/org/owasp/webgoat/SqlInjectionLessonTest.java
+++ b/webgoat-integration-tests/src/test/java/org/owasp/webgoat/SqlInjectionLessonTest.java
@@ -11,7 +11,7 @@ public class SqlInjectionLessonTest extends IntegrationTest {
public static final String sql_3 = "update employees set department='Sales' where last_name='Barnett'";
public static final String sql_4_drop = "alter table employees drop column phone";
public static final String sql_4_add = "alter table employees add column phone varchar(20)";
- public static final String sql_5 = "grant alter table to UnauthorizedUser";
+ public static final String sql_5 = "grant select on grant_rights to unauthorized_user";
public static final String sql_9_account = " ' ";
public static final String sql_9_operator = "or";
public static final String sql_9_injection = "'1'='1";
diff --git a/webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/sql_injection/introduction/SqlInjectionLesson5.java b/webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/sql_injection/introduction/SqlInjectionLesson5.java
index 0cc1ce3af..0b8d064a5 100644
--- a/webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/sql_injection/introduction/SqlInjectionLesson5.java
+++ b/webgoat-lessons/sql-injection/src/main/java/org/owasp/webgoat/sql_injection/introduction/SqlInjectionLesson5.java
@@ -30,11 +30,36 @@ import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
+import javax.annotation.PostConstruct;
+import javax.sql.DataSource;
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
@RestController
@AssignmentHints(value = {"SqlStringInjectionHint5-a"})
public class SqlInjectionLesson5 extends AssignmentEndpoint {
+ private final DataSource dataSource;
+
+ public SqlInjectionLesson5(DataSource dataSource) {
+ this.dataSource = dataSource;
+ }
+
+ @PostConstruct
+ public void createUser() {
+ // HSQLDB does not support CREATE USER with IF NOT EXISTS so we need to do it in code (DROP first will throw error if user does not exists)
+ try (Connection connection = dataSource.getConnection()) {
+ try (var statement = connection.prepareStatement("CREATE USER unauthorized_user PASSWORD test")) {
+ statement.execute();
+ }
+ } catch (Exception e) {
+ //user already exists continue
+ }
+ }
+
@PostMapping("/SqlInjection/attack5")
@ResponseBody
public AttackResult completed(String query) {
@@ -42,19 +67,29 @@ public class SqlInjectionLesson5 extends AssignmentEndpoint {
}
protected AttackResult injectableQuery(String query) {
- try {
- String regex = "(?i)^(grant alter table to [']?unauthorizedUser[']?)(?:[;]?)$";
- StringBuffer output = new StringBuffer();
-
- // user completes lesson if the query is correct
- if (query.matches(regex)) {
- output.append("" + query + "");
- return success(this).output(output.toString()).build();
- } else {
- return failed(this).output(output.toString()).build();
+ try (Connection connection = dataSource.getConnection()) {
+ try (Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE)) {
+ statement.executeQuery(query);
+ if (checkSolution(connection)) {
+ return success(this).build();
+ }
+ return failed(this).output("Your query was: " + query).build();
}
} catch (Exception e) {
- return failed(this).output(this.getClass().getName() + " : " + e.getMessage()).build();
+ return failed(this).output(this.getClass().getName() + " : " + e.getMessage() + "
Your query was: " + query).build();
}
}
+
+ private boolean checkSolution(Connection connection) {
+ try {
+ var stmt = connection.prepareStatement("SELECT * FROM INFORMATION_SCHEMA.TABLE_PRIVILEGES WHERE TABLE_NAME = ? AND GRANTEE = ?");
+ stmt.setString(1, "GRANT_RIGHTS");
+ stmt.setString(2, "UNAUTHORIZED_USER");
+ var resultSet = stmt.executeQuery();
+ return resultSet.next();
+ } catch (SQLException throwables) {
+ return false;
+ }
+
+ }
}
diff --git a/webgoat-lessons/sql-injection/src/main/resources/db/migration/V2021_03_13_8__grant.sql b/webgoat-lessons/sql-injection/src/main/resources/db/migration/V2021_03_13_8__grant.sql
new file mode 100644
index 000000000..b4577e4d1
--- /dev/null
+++ b/webgoat-lessons/sql-injection/src/main/resources/db/migration/V2021_03_13_8__grant.sql
@@ -0,0 +1,14 @@
+CREATE TABLE grant_rights(
+ userid varchar(6) not null primary key,
+ first_name varchar(20),
+ last_name varchar(20),
+ department varchar(20),
+ salary int
+);
+
+INSERT INTO grant_rights VALUES ('32147','Paulina', 'Travers', 'Accounting', 46000);
+INSERT INTO grant_rights VALUES ('89762','Tobi', 'Barnett', 'Development', 77000);
+INSERT INTO grant_rights VALUES ('96134','Bob', 'Franco', 'Marketing', 83700);
+INSERT INTO grant_rights VALUES ('34477','Abraham ', 'Holman', 'Development', 50000);
+INSERT INTO grant_rights VALUES ('37648','John', 'Smith', 'Marketing', 64350);
+
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 7c24f2fb8..cd611a432 100644
--- a/webgoat-lessons/sql-injection/src/main/resources/i18n/WebGoatLabels.properties
+++ b/webgoat-lessons/sql-injection/src/main/resources/i18n/WebGoatLabels.properties
@@ -25,7 +25,8 @@ SqlStringInjectionHint4-1=ALTER TABLE alters the structure of an existing databa
SqlStringInjectionHint4-2=Do not forget the data type of the new column (e.g. varchar(size) or int(size))
SqlStringInjectionHint4-3=ALTER TABLE table name ADD column name data type(size);
-SqlStringInjectionHint5-a=Look at the example. There is everything you will need.
+SqlStringInjectionHint5-1=Take a look at how to use a grant statement.
+SqlStringInjectionHint5-2=You are using 'tom' trying to grant access to tom
sql-injection.5a.success=You have succeeded: {0}
sql-injection.5a.no.results=No results matched. Try Again.
diff --git a/webgoat-lessons/sql-injection/src/test/java/org/owasp/webgoat/sql_injection/introduction/SqlInjectionLesson5Test.java b/webgoat-lessons/sql-injection/src/test/java/org/owasp/webgoat/sql_injection/introduction/SqlInjectionLesson5Test.java
index 6ea8bf178..ad0296714 100644
--- a/webgoat-lessons/sql-injection/src/test/java/org/owasp/webgoat/sql_injection/introduction/SqlInjectionLesson5Test.java
+++ b/webgoat-lessons/sql-injection/src/test/java/org/owasp/webgoat/sql_injection/introduction/SqlInjectionLesson5Test.java
@@ -23,16 +23,22 @@
package org.owasp.webgoat.sql_injection.introduction;
import org.hamcrest.CoreMatchers;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.junit.MockitoJUnitRunner;
import org.owasp.webgoat.assignments.AssignmentEndpointTest;
import org.owasp.webgoat.sql_injection.SqlLessonTest;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
+import javax.sql.DataSource;
+
+import java.sql.SQLException;
+
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@@ -41,28 +47,34 @@ import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standal
@RunWith(SpringJUnit4ClassRunner.class)
public class SqlInjectionLesson5Test extends SqlLessonTest {
+ @Autowired
+ private DataSource dataSource;
+
+ @After
+ public void removeGrant() throws SQLException {
+ dataSource.getConnection().prepareStatement("revoke select on grant_rights from unauthorized_user cascade").execute();
+ }
+
@Test
public void grantSolution() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack5")
- .param("query","grant alter table to unauthorizedUser"))
+ .param("query", "grant select on grant_rights to unauthorized_user"))
.andExpect(status().isOk())
- .andExpect(jsonPath("$.output", CoreMatchers.containsString("grant")))
.andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true)));
}
@Test
- public void grantSolutionWithSingleQuotes() throws Exception {
+ public void differentTableShouldNotSolveIt() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack5")
- .param("query","grant alter table to 'unauthorizedUser';"))
+ .param("query", "grant select on users to unauthorized_user"))
.andExpect(status().isOk())
- .andExpect(jsonPath("$.output", CoreMatchers.containsString("grant")))
- .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true)));
+ .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false)));
}
@Test
- public void grantSolutionWrong() throws Exception {
+ public void noGrantShouldNotSolveIt() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack5")
- .param("query","grant alter table to me"))
+ .param("query", "select * from grant_rights"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false)));
}