From e783c0c1f13176efcd7a397e7453fb5f4397dd8b Mon Sep 17 00:00:00 2001 From: Nanne Baars Date: Tue, 24 Sep 2019 22:41:20 +0200 Subject: [PATCH] SQL: Cannot use apostrophe/quotes on string literals #662 --- .../introduction/SqlInjectionLesson5.java | 11 +- .../introduction/SqlInjectionLesson5Test.java | 87 ++++++++++++++ .../SqlInjectionLesson5aTest.java | 108 +++++++----------- 3 files changed, 136 insertions(+), 70 deletions(-) create mode 100644 webgoat-lessons/sql-injection/src/test/java/org/owasp/webgoat/sql_injection/introduction/SqlInjectionLesson5Test.java 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 650a7b7f3..8e1b587ed 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 @@ -38,19 +38,18 @@ public class SqlInjectionLesson5 extends AssignmentEndpoint { @PostMapping("/SqlInjection/attack5") @ResponseBody - public AttackResult completed(@RequestParam String query) { + public AttackResult completed(@RequestParam("_query") String query) { return injectableQuery(query); } - protected AttackResult injectableQuery(String _query) { + protected AttackResult injectableQuery(String query) { try { - String regex = "(?i)^(grant alter table to unauthorizedUser)(?:[;]?)$"; - Boolean isCorrect = false; + 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 + ""); + if (query.matches(regex)) { + output.append("" + query + ""); return trackProgress(success().output(output.toString()).build()); } else { return trackProgress(failed().output(output.toString()).build()); 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 new file mode 100644 index 000000000..2022b2fbe --- /dev/null +++ b/webgoat-lessons/sql-injection/src/test/java/org/owasp/webgoat/sql_injection/introduction/SqlInjectionLesson5Test.java @@ -0,0 +1,87 @@ +/* + * This file is part of WebGoat, an Open Web Application Security Project utility. For details, please see http://www.owasp.org/ + * + * Copyright (c) 2002 - 2019 Bruce Mayhew + * + * This program is free software; you can redistribute it and/or modify it under the terms of the + * GNU General Public License as published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with this program; if + * not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Getting Source ============== + * + * Source for this application is maintained at https://github.com/WebGoat/WebGoat, a repository for free software projects. + */ + +package org.owasp.webgoat.sql_injection.introduction; + +import org.hamcrest.CoreMatchers; +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.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; + +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; +import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup; + +@RunWith(MockitoJUnitRunner.class) +public class SqlInjectionLesson5Test extends AssignmentEndpointTest { + + private MockMvc mockMvc; + + @Before + public void setup() { + SqlInjectionLesson5 sql = new SqlInjectionLesson5(); + init(sql); + this.mockMvc = standaloneSetup(sql).build(); + when(webSession.getCurrentLesson()).thenReturn(new SqlInjection()); + + } + + @Test + public void grantSolution() throws Exception { + mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack5") + .param("_query","grant alter table to unauthorizedUser")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.output", CoreMatchers.containsString("grant"))) + .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true))); + } + + @Test + public void grantSolutionWithQuotes() throws Exception { + mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack5") + .param("_query","grant alter table to \"unauthorizedUser\"")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.output", CoreMatchers.containsString("grant"))) + .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true))); + } + + @Test + public void grantSolutionWithSingleQuotes() throws Exception { + mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack5") + .param("_query","grant alter table to 'unauthorizedUser';")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.output", CoreMatchers.containsString("grant"))) + .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true))); + } + + @Test + public void grantSolutionWrong() throws Exception { + mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/attack5") + .param("_query","grant alter table to me")) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false))); + } +} \ No newline at end of file diff --git a/webgoat-lessons/sql-injection/src/test/java/org/owasp/webgoat/sql_injection/introduction/SqlInjectionLesson5aTest.java b/webgoat-lessons/sql-injection/src/test/java/org/owasp/webgoat/sql_injection/introduction/SqlInjectionLesson5aTest.java index f07d93547..da84bc1a7 100644 --- a/webgoat-lessons/sql-injection/src/test/java/org/owasp/webgoat/sql_injection/introduction/SqlInjectionLesson5aTest.java +++ b/webgoat-lessons/sql-injection/src/test/java/org/owasp/webgoat/sql_injection/introduction/SqlInjectionLesson5aTest.java @@ -1,22 +1,17 @@ package org.owasp.webgoat.sql_injection.introduction; -import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; -import org.owasp.webgoat.plugins.LessonTest; -import org.owasp.webgoat.session.WebgoatContext; import org.owasp.webgoat.sql_injection.SqlLessonTest; -import org.owasp.webgoat.sql_injection.introduction.SqlInjection; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.util.LinkedMultiValueMap; +import java.util.Map; + import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.is; -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; @@ -27,65 +22,50 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. @RunWith(SpringJUnit4ClassRunner.class) public class SqlInjectionLesson5aTest extends SqlLessonTest { - @Test - public void knownAccountShouldDisplayData() throws Exception { - LinkedMultiValueMap map = new LinkedMultiValueMap<>(); - map.add("account", "Smith"); - map.add("operator", ""); - map.add("injection", ""); - mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/assignment5a") - .params(map)) + @Test + public void knownAccountShouldDisplayData() throws Exception { + var params = Map.of("account", "Smith", "operator", "", "injection", ""); + mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/assignment5a") + .params(new LinkedMultiValueMap(params))) + .andExpect(status().isOk()) + .andExpect(jsonPath("lessonCompleted", is(false))) + .andExpect(jsonPath("$.feedback", is(messages.getMessage("assignment.not.solved")))) + .andExpect(jsonPath("$.output", containsString("

USERID, FIRST_NAME"))); + } - .andExpect(status().isOk()) - .andExpect(jsonPath("lessonCompleted", is(false))) - .andExpect(jsonPath("$.feedback", is(messages.getMessage("assignment.not.solved")))) - .andExpect(jsonPath("$.output", containsString("

USERID, FIRST_NAME"))); - } + @Ignore + @Test + public void unknownAccount() throws Exception { + var params = Map.of("account", "Smith", "operator", "", "injection", ""); + mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/assignment5a") + .params(new LinkedMultiValueMap(params))) - @Ignore - @Test - public void unknownAccount() throws Exception { - LinkedMultiValueMap map = new LinkedMultiValueMap<>(); - map.add("account", "Smith"); - map.add("operator", ""); - map.add("injection", ""); - mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/assignment5a") - .params(map)) + .andExpect(status().isOk()) + .andExpect(jsonPath("lessonCompleted", is(false))) + .andExpect(jsonPath("$.feedback", is(SqlInjectionLesson8Test.modifySpan(messages.getMessage("NoResultsMatched"))))) + .andExpect(jsonPath("$.output").doesNotExist()); + } - .andExpect(status().isOk()) - .andExpect(jsonPath("lessonCompleted", is(false))) - .andExpect(jsonPath("$.feedback", is(SqlInjectionLesson8Test.modifySpan(messages.getMessage("NoResultsMatched"))))) - .andExpect(jsonPath("$.output").doesNotExist()); - } + @Test + public void sqlInjection() throws Exception { + var params = Map.of("account", "'", "operator", "OR", "injection", "'1' = '1"); + mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/assignment5a") + .params(new LinkedMultiValueMap(params))) + .andExpect(status().isOk()) + .andExpect(jsonPath("lessonCompleted", is(true))) + .andExpect(jsonPath("$.feedback", containsString("You have succeed"))) + .andExpect(jsonPath("$.output").exists()); + } - @Test - public void sqlInjection() throws Exception { - LinkedMultiValueMap map = new LinkedMultiValueMap<>(); - map.add("account", "'"); - map.add("operator", "OR"); - map.add("injection", "'1' = '1"); - mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/assignment5a") - .params(map)) - - .andExpect(status().isOk()) - .andExpect(jsonPath("lessonCompleted", is(true))) - .andExpect(jsonPath("$.feedback", containsString("You have succeed"))) - .andExpect(jsonPath("$.output").exists()); - } - - @Test - public void sqlInjectionWrongShouldDisplayError() throws Exception { - LinkedMultiValueMap map = new LinkedMultiValueMap<>(); - map.add("account", "Smith'"); - map.add("operator", "OR"); - map.add("injection", "'1' = '1'"); - mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/assignment5a") - .params(map)) - - .andExpect(status().isOk()) - .andExpect(jsonPath("lessonCompleted", is(false))) - .andExpect(jsonPath("$.feedback", containsString(messages.getMessage("assignment.not.solved")))) - .andExpect(jsonPath("$.output", is("malformed string: '1''
Your query was: SELECT * FROM user_data WHERE" + - " first_name = 'John' and last_name = 'Smith' OR '1' = '1''"))); - } + @Test + public void sqlInjectionWrongShouldDisplayError() throws Exception { + var params = Map.of("account", "Smith'", "operator", "OR", "injection", "'1' = '1'"); + mockMvc.perform(MockMvcRequestBuilders.post("/SqlInjection/assignment5a") + .params(new LinkedMultiValueMap(params))) + .andExpect(status().isOk()) + .andExpect(jsonPath("lessonCompleted", is(false))) + .andExpect(jsonPath("$.feedback", containsString(messages.getMessage("assignment.not.solved")))) + .andExpect(jsonPath("$.output", is("malformed string: '1''
Your query was: SELECT * FROM user_data WHERE" + + " first_name = 'John' and last_name = 'Smith' OR '1' = '1''"))); + } } \ No newline at end of file