Convert lesson into using DB instead of using regular expression to check the solution

This commit is contained in:
Nanne Baars 2021-03-14 11:09:07 +01:00 committed by Nanne Baars
parent c798e4be32
commit d4da2d0efa
5 changed files with 83 additions and 21 deletions

View File

@ -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";

View File

@ -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("<span class='feedback-positive'>" + query + "</span>");
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() + "<br> 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;
}
}
}

View File

@ -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);

View File

@ -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=<span class='feedback-positive'>You have succeeded: {0}</span>
sql-injection.5a.no.results=<span class='feedback-negative'>No results matched. Try Again.</span>

View File

@ -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)));
}