Convert lesson into using DB instead of using regular expression to check the solution
This commit is contained in:
parent
c798e4be32
commit
d4da2d0efa
@ -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_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_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_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_account = " ' ";
|
||||||
public static final String sql_9_operator = "or";
|
public static final String sql_9_operator = "or";
|
||||||
public static final String sql_9_injection = "'1'='1";
|
public static final String sql_9_injection = "'1'='1";
|
||||||
|
@ -30,11 +30,36 @@ import org.springframework.web.bind.annotation.PostMapping;
|
|||||||
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;
|
||||||
|
|
||||||
|
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
|
@RestController
|
||||||
@AssignmentHints(value = {"SqlStringInjectionHint5-a"})
|
@AssignmentHints(value = {"SqlStringInjectionHint5-a"})
|
||||||
public class SqlInjectionLesson5 extends AssignmentEndpoint {
|
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")
|
@PostMapping("/SqlInjection/attack5")
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
public AttackResult completed(String query) {
|
public AttackResult completed(String query) {
|
||||||
@ -42,19 +67,29 @@ public class SqlInjectionLesson5 extends AssignmentEndpoint {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected AttackResult injectableQuery(String query) {
|
protected AttackResult injectableQuery(String query) {
|
||||||
try {
|
try (Connection connection = dataSource.getConnection()) {
|
||||||
String regex = "(?i)^(grant alter table to [']?unauthorizedUser[']?)(?:[;]?)$";
|
try (Statement statement = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE)) {
|
||||||
StringBuffer output = new StringBuffer();
|
statement.executeQuery(query);
|
||||||
|
if (checkSolution(connection)) {
|
||||||
// user completes lesson if the query is correct
|
return success(this).build();
|
||||||
if (query.matches(regex)) {
|
}
|
||||||
output.append("<span class='feedback-positive'>" + query + "</span>");
|
return failed(this).output("Your query was: " + query).build();
|
||||||
return success(this).output(output.toString()).build();
|
|
||||||
} else {
|
|
||||||
return failed(this).output(output.toString()).build();
|
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
|
@ -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-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);
|
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.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>
|
sql-injection.5a.no.results=<span class='feedback-negative'>No results matched. Try Again.</span>
|
||||||
|
@ -23,16 +23,22 @@
|
|||||||
package org.owasp.webgoat.sql_injection.introduction;
|
package org.owasp.webgoat.sql_injection.introduction;
|
||||||
|
|
||||||
import org.hamcrest.CoreMatchers;
|
import org.hamcrest.CoreMatchers;
|
||||||
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mockito.junit.MockitoJUnitRunner;
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
import org.owasp.webgoat.assignments.AssignmentEndpointTest;
|
import org.owasp.webgoat.assignments.AssignmentEndpointTest;
|
||||||
import org.owasp.webgoat.sql_injection.SqlLessonTest;
|
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.context.junit4.SpringJUnit4ClassRunner;
|
||||||
import org.springframework.test.web.servlet.MockMvc;
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
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.mockito.Mockito.when;
|
||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
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)
|
@RunWith(SpringJUnit4ClassRunner.class)
|
||||||
public class SqlInjectionLesson5Test extends SqlLessonTest {
|
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
|
@Test
|
||||||
public void grantSolution() throws Exception {
|
public void grantSolution() throws Exception {
|
||||||
mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack5")
|
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(status().isOk())
|
||||||
.andExpect(jsonPath("$.output", CoreMatchers.containsString("grant")))
|
|
||||||
.andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true)));
|
.andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void grantSolutionWithSingleQuotes() throws Exception {
|
public void differentTableShouldNotSolveIt() throws Exception {
|
||||||
mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack5")
|
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(status().isOk())
|
||||||
.andExpect(jsonPath("$.output", CoreMatchers.containsString("grant")))
|
.andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false)));
|
||||||
.andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void grantSolutionWrong() throws Exception {
|
public void noGrantShouldNotSolveIt() throws Exception {
|
||||||
mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack5")
|
mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack5")
|
||||||
.param("query","grant alter table to me"))
|
.param("query", "select * from grant_rights"))
|
||||||
.andExpect(status().isOk())
|
.andExpect(status().isOk())
|
||||||
.andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false)));
|
.andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false)));
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user