fix: Success if only Smith earn most salary (#1744)
* Update labels * Update Java * Update Test --------- Co-authored-by: René Zubcevic <rene@zubcevic.com>
This commit is contained in:
parent
e219887f14
commit
3134f18066
@ -63,36 +63,42 @@ public class SqlInjectionLesson9 extends AssignmentEndpoint {
|
|||||||
|
|
||||||
protected AttackResult injectableQueryIntegrity(String name, String auth_tan) {
|
protected AttackResult injectableQueryIntegrity(String name, String auth_tan) {
|
||||||
StringBuilder output = new StringBuilder();
|
StringBuilder output = new StringBuilder();
|
||||||
String query =
|
String queryInjection =
|
||||||
"SELECT * FROM employees WHERE last_name = '"
|
"SELECT * FROM employees WHERE last_name = '"
|
||||||
+ name
|
+ name
|
||||||
+ "' AND auth_tan = '"
|
+ "' AND auth_tan = '"
|
||||||
+ auth_tan
|
+ auth_tan
|
||||||
+ "'";
|
+ "'";
|
||||||
try (Connection connection = dataSource.getConnection()) {
|
try (Connection connection = dataSource.getConnection()) {
|
||||||
try {
|
// V2019_09_26_7__employees.sql
|
||||||
Statement statement = connection.createStatement(TYPE_SCROLL_SENSITIVE, CONCUR_UPDATABLE);
|
int oldMaxSalary = this.getMaxSalary(connection);
|
||||||
SqlInjectionLesson8.log(connection, query);
|
int oldSumSalariesOfOtherEmployees = this.getSumSalariesOfOtherEmployees(connection);
|
||||||
ResultSet results = statement.executeQuery(query);
|
// begin transaction
|
||||||
var test = results.getRow() != 0;
|
connection.setAutoCommit(false);
|
||||||
if (results.getStatement() != null) {
|
// do injectable query
|
||||||
if (results.first()) {
|
Statement statement = connection.createStatement(TYPE_SCROLL_SENSITIVE, CONCUR_UPDATABLE);
|
||||||
output.append(SqlInjectionLesson8.generateTable(results));
|
SqlInjectionLesson8.log(connection, queryInjection);
|
||||||
} else {
|
statement.execute(queryInjection);
|
||||||
// no results
|
// check new sum of salaries other employees and new salaries of John
|
||||||
return failed(this).feedback("sql-injection.8.no.results").build();
|
int newJohnSalary = this.getJohnSalary(connection);
|
||||||
}
|
int newSumSalariesOfOtherEmployees = this.getSumSalariesOfOtherEmployees(connection);
|
||||||
}
|
if (newJohnSalary > oldMaxSalary
|
||||||
} catch (SQLException e) {
|
&& newSumSalariesOfOtherEmployees == oldSumSalariesOfOtherEmployees) {
|
||||||
System.err.println(e.getMessage());
|
// success commit
|
||||||
return failed(this)
|
connection.commit(); // need execute not executeQuery
|
||||||
.output("<br><span class='feedback-negative'>" + e.getMessage() + "</span>")
|
connection.setAutoCommit(true);
|
||||||
.build();
|
output.append(
|
||||||
|
SqlInjectionLesson8.generateTable(this.getEmployeesDataOrderBySalaryDesc(connection)));
|
||||||
|
return success(this).feedback("sql-injection.9.success").output(output.toString()).build();
|
||||||
}
|
}
|
||||||
|
// failed roolback
|
||||||
return checkSalaryRanking(connection, output);
|
connection.rollback();
|
||||||
|
return failed(this)
|
||||||
} catch (Exception e) {
|
.feedback("sql-injection.9.one")
|
||||||
|
.output(
|
||||||
|
SqlInjectionLesson8.generateTable(this.getEmployeesDataOrderBySalaryDesc(connection)))
|
||||||
|
.build();
|
||||||
|
} catch (SQLException e) {
|
||||||
System.err.println(e.getMessage());
|
System.err.println(e.getMessage());
|
||||||
return failed(this)
|
return failed(this)
|
||||||
.output("<br><span class='feedback-negative'>" + e.getMessage() + "</span>")
|
.output("<br><span class='feedback-negative'>" + e.getMessage() + "</span>")
|
||||||
@ -100,29 +106,31 @@ public class SqlInjectionLesson9 extends AssignmentEndpoint {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private AttackResult checkSalaryRanking(Connection connection, StringBuilder output) {
|
private int getSqlInt(Connection connection, String query) throws SQLException {
|
||||||
try {
|
Statement statement = connection.createStatement(TYPE_SCROLL_SENSITIVE, CONCUR_UPDATABLE);
|
||||||
String query = "SELECT * FROM employees ORDER BY salary DESC";
|
ResultSet results = statement.executeQuery(query);
|
||||||
try (Statement statement =
|
results.first();
|
||||||
connection.createStatement(TYPE_SCROLL_SENSITIVE, CONCUR_UPDATABLE); ) {
|
return results.getInt(1);
|
||||||
ResultSet results = statement.executeQuery(query);
|
}
|
||||||
|
|
||||||
results.first();
|
private int getMaxSalary(Connection connection) throws SQLException {
|
||||||
// user completes lesson if John Smith is the first in the list
|
String query = "SELECT max(salary) FROM employees";
|
||||||
if ((results.getString(2).equals("John")) && (results.getString(3).equals("Smith"))) {
|
return this.getSqlInt(connection, query);
|
||||||
output.append(SqlInjectionLesson8.generateTable(results));
|
}
|
||||||
return success(this)
|
|
||||||
.feedback("sql-injection.9.success")
|
private int getSumSalariesOfOtherEmployees(Connection connection) throws SQLException {
|
||||||
.output(output.toString())
|
String query = "SELECT sum(salary) FROM employees WHERE auth_tan != '3SL99A'";
|
||||||
.build();
|
return this.getSqlInt(connection, query);
|
||||||
} else {
|
}
|
||||||
return failed(this).feedback("sql-injection.9.one").output(output.toString()).build();
|
|
||||||
}
|
private int getJohnSalary(Connection connection) throws SQLException {
|
||||||
}
|
String query = "SELECT salary FROM employees WHERE auth_tan = '3SL99A'";
|
||||||
} catch (SQLException e) {
|
return this.getSqlInt(connection, query);
|
||||||
return failed(this)
|
}
|
||||||
.output("<br><span class='feedback-negative'>" + e.getMessage() + "</span>")
|
|
||||||
.build();
|
private ResultSet getEmployeesDataOrderBySalaryDesc(Connection connection) throws SQLException {
|
||||||
}
|
String query = "SELECT * FROM employees ORDER BY salary DESC";
|
||||||
|
Statement statement = connection.createStatement(TYPE_SCROLL_SENSITIVE, CONCUR_UPDATABLE);
|
||||||
|
return statement.executeQuery(query);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,8 +63,8 @@ SqlStringInjectionHint.8.3=Try appending a SQL statement that always resolves to
|
|||||||
SqlStringInjectionHint.8.4=Make sure all quotes (" ' ") are opened and closed properly so the resulting SQL query is syntactically correct.
|
SqlStringInjectionHint.8.4=Make sure all quotes (" ' ") are opened and closed properly so the resulting SQL query is syntactically correct.
|
||||||
SqlStringInjectionHint.8.5=Try extending the WHERE clause of the statement by adding something like: ' OR '1' = '1.
|
SqlStringInjectionHint.8.5=Try extending the WHERE clause of the statement by adding something like: ' OR '1' = '1.
|
||||||
|
|
||||||
sql-injection.9.success=Well done! Now you are earning the most money. And at the same time you successfully compromised the integrity of data by changing the salary!
|
sql-injection.9.success=Well done! Now you are earning the most money. And at the same time you successfully compromised the integrity of data by changing your salary!
|
||||||
sql-injection.9.one=Still not earning enough! Better try again and change that.
|
sql-injection.9.one=Still not earning enough or only your own salary must be changed! Better try again and change that.
|
||||||
SqlStringInjectionHint.9.1=Try to find a way, to chain another query to the end of the existing one.
|
SqlStringInjectionHint.9.1=Try to find a way, to chain another query to the end of the existing one.
|
||||||
SqlStringInjectionHint.9.2=Use the ; metacharacter to do so.
|
SqlStringInjectionHint.9.2=Use the ; metacharacter to do so.
|
||||||
SqlStringInjectionHint.9.3=Make use of DML to change your salary.
|
SqlStringInjectionHint.9.3=Make use of DML to change your salary.
|
||||||
|
@ -37,123 +37,7 @@ import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
|||||||
*/
|
*/
|
||||||
public class SqlInjectionLesson9Test extends SqlLessonTest {
|
public class SqlInjectionLesson9Test extends SqlLessonTest {
|
||||||
|
|
||||||
private String completedError = "JSON path \"lessonCompleted\"";
|
private final String completedError = "JSON path \"lessonCompleted\"";
|
||||||
|
|
||||||
@Test
|
|
||||||
public void oneAccount() throws Exception {
|
|
||||||
try {
|
|
||||||
mockMvc
|
|
||||||
.perform(
|
|
||||||
MockMvcRequestBuilders.post("/SqlInjection/attack9")
|
|
||||||
.param("name", "Smith")
|
|
||||||
.param("auth_tan", "3SL99A"))
|
|
||||||
.andExpect(status().isOk())
|
|
||||||
.andExpect(jsonPath("lessonCompleted", is(false)))
|
|
||||||
.andExpect(jsonPath("$.feedback", is(messages.getMessage("sql-injection.9.one"))))
|
|
||||||
.andExpect(jsonPath("$.output", containsString("<table><tr><th>")));
|
|
||||||
} catch (AssertionError e) {
|
|
||||||
if (!e.getMessage().contains(completedError)) throw e;
|
|
||||||
|
|
||||||
mockMvc
|
|
||||||
.perform(
|
|
||||||
MockMvcRequestBuilders.post("/SqlInjection/attack9")
|
|
||||||
.param("name", "Smith")
|
|
||||||
.param("auth_tan", "3SL99A"))
|
|
||||||
.andExpect(status().isOk())
|
|
||||||
.andExpect(jsonPath("lessonCompleted", is(true)))
|
|
||||||
.andExpect(jsonPath("$.feedback", is(messages.getMessage("sql-injection.9.success"))))
|
|
||||||
.andExpect(jsonPath("$.output", containsString("<table><tr><th>")));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void multipleAccounts() throws Exception {
|
|
||||||
try {
|
|
||||||
mockMvc
|
|
||||||
.perform(
|
|
||||||
MockMvcRequestBuilders.post("/SqlInjection/attack9")
|
|
||||||
.param("name", "Smith")
|
|
||||||
.param("auth_tan", "3SL99A' OR '1' = '1"))
|
|
||||||
.andExpect(status().isOk())
|
|
||||||
.andExpect(jsonPath("lessonCompleted", is(false)))
|
|
||||||
.andExpect(jsonPath("$.feedback", is(messages.getMessage("sql-injection.9.one"))))
|
|
||||||
.andExpect(
|
|
||||||
jsonPath(
|
|
||||||
"$.output",
|
|
||||||
containsString(
|
|
||||||
"<tr><td>96134<\\/td><td>Bob<\\/td><td>Franco<\\/td><td>Marketing<\\/td><td>83700<\\/td><td>LO9S2V<\\/td><\\/tr>")));
|
|
||||||
} catch (AssertionError e) {
|
|
||||||
if (!e.getMessage().contains(completedError)) throw e;
|
|
||||||
|
|
||||||
mockMvc
|
|
||||||
.perform(
|
|
||||||
MockMvcRequestBuilders.post("/SqlInjection/attack9")
|
|
||||||
.param("name", "Smith")
|
|
||||||
.param("auth_tan", "3SL99A' OR '1' = '1"))
|
|
||||||
.andExpect(status().isOk())
|
|
||||||
.andExpect(jsonPath("lessonCompleted", is(true)))
|
|
||||||
.andExpect(jsonPath("$.feedback", is(messages.getMessage("sql-injection.9.success"))))
|
|
||||||
.andExpect(
|
|
||||||
jsonPath(
|
|
||||||
"$.output",
|
|
||||||
containsString(
|
|
||||||
"<tr><td>96134<\\/td><td>Bob<\\/td><td>Franco<\\/td><td>Marketing<\\/td><td>83700<\\/td><td>LO9S2V<\\/td><\\/tr>")));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void wrongNameReturnsNoAccounts() throws Exception {
|
|
||||||
try {
|
|
||||||
mockMvc
|
|
||||||
.perform(
|
|
||||||
MockMvcRequestBuilders.post("/SqlInjection/attack9")
|
|
||||||
.param("name", "Smithh")
|
|
||||||
.param("auth_tan", "3SL99A"))
|
|
||||||
.andExpect(status().isOk())
|
|
||||||
.andExpect(jsonPath("lessonCompleted", is(false)))
|
|
||||||
.andExpect(jsonPath("$.feedback", is(messages.getMessage("sql-injection.8.no.results"))))
|
|
||||||
.andExpect(jsonPath("$.output").doesNotExist());
|
|
||||||
} catch (AssertionError e) {
|
|
||||||
if (!e.getMessage().contains(completedError)) throw e;
|
|
||||||
|
|
||||||
mockMvc
|
|
||||||
.perform(
|
|
||||||
MockMvcRequestBuilders.post("/SqlInjection/attack9")
|
|
||||||
.param("name", "Smithh")
|
|
||||||
.param("auth_tan", "3SL99A"))
|
|
||||||
.andExpect(status().isOk())
|
|
||||||
.andExpect(jsonPath("lessonCompleted", is(true)))
|
|
||||||
.andExpect(jsonPath("$.feedback", is(messages.getMessage("sql-injection.8.no.success"))))
|
|
||||||
.andExpect(jsonPath("$.output").doesNotExist());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void wrongTANReturnsNoAccounts() throws Exception {
|
|
||||||
try {
|
|
||||||
mockMvc
|
|
||||||
.perform(
|
|
||||||
MockMvcRequestBuilders.post("/SqlInjection/attack9")
|
|
||||||
.param("name", "Smithh")
|
|
||||||
.param("auth_tan", ""))
|
|
||||||
.andExpect(status().isOk())
|
|
||||||
.andExpect(jsonPath("lessonCompleted", is(false)))
|
|
||||||
.andExpect(jsonPath("$.feedback", is(messages.getMessage("sql-injection.8.no.results"))))
|
|
||||||
.andExpect(jsonPath("$.output").doesNotExist());
|
|
||||||
} catch (AssertionError e) {
|
|
||||||
if (!e.getMessage().contains(completedError)) throw e;
|
|
||||||
|
|
||||||
mockMvc
|
|
||||||
.perform(
|
|
||||||
MockMvcRequestBuilders.post("/SqlInjection/attack9")
|
|
||||||
.param("name", "Smithh")
|
|
||||||
.param("auth_tan", ""))
|
|
||||||
.andExpect(status().isOk())
|
|
||||||
.andExpect(jsonPath("lessonCompleted", is(true)))
|
|
||||||
.andExpect(jsonPath("$.feedback", is(messages.getMessage("sql-injection.9.success"))))
|
|
||||||
.andExpect(jsonPath("$.output").doesNotExist());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void malformedQueryReturnsError() throws Exception {
|
public void malformedQueryReturnsError() throws Exception {
|
||||||
@ -181,6 +65,44 @@ public class SqlInjectionLesson9Test extends SqlLessonTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void SmithIsNotMostEarning() throws Exception {
|
||||||
|
mockMvc
|
||||||
|
.perform(
|
||||||
|
MockMvcRequestBuilders.post("/SqlInjection/attack9")
|
||||||
|
.param("name", "Smith")
|
||||||
|
.param(
|
||||||
|
"auth_tan",
|
||||||
|
"3SL99A'; UPDATE employees SET salary = 9999 WHERE last_name = 'Smith"))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("lessonCompleted", is(false)))
|
||||||
|
.andExpect(jsonPath("$.feedback", is(messages.getMessage("sql-injection.9.one"))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void OnlySmithSalaryMustBeUpdated() throws Exception {
|
||||||
|
mockMvc
|
||||||
|
.perform(
|
||||||
|
MockMvcRequestBuilders.post("/SqlInjection/attack9")
|
||||||
|
.param("name", "Smith")
|
||||||
|
.param("auth_tan", "3SL99A'; UPDATE employees SET salary = 9999 -- "))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("lessonCompleted", is(false)))
|
||||||
|
.andExpect(jsonPath("$.feedback", is(messages.getMessage("sql-injection.9.one"))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void OnlySmithMustMostEarning() throws Exception {
|
||||||
|
mockMvc
|
||||||
|
.perform(
|
||||||
|
MockMvcRequestBuilders.post("/SqlInjection/attack9")
|
||||||
|
.param("name", "'; UPDATE employees SET salary = 999999 -- ")
|
||||||
|
.param("auth_tan", ""))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("lessonCompleted", is(false)))
|
||||||
|
.andExpect(jsonPath("$.feedback", is(messages.getMessage("sql-injection.9.one"))));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void SmithIsMostEarningCompletesAssignment() throws Exception {
|
public void SmithIsMostEarningCompletesAssignment() throws Exception {
|
||||||
mockMvc
|
mockMvc
|
||||||
|
Loading…
x
Reference in New Issue
Block a user